001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005: package com.sun.portal.desktop.context;
006:
007: import com.sun.portal.desktop.ubt.DesktopEvents;
008: import com.sun.portal.desktop.ubt.ProviderLogRecord;
009: import com.sun.portal.log.common.PortalLogger;
010: import com.sun.portal.ubt.UBTEvent;
011: import com.sun.portal.ubt.UBTLogField;
012: import com.sun.portal.ubt.UBTLogManager;
013:
014: import javax.servlet.ServletContext;
015: import javax.servlet.http.HttpServletRequest;
016: import java.util.HashMap;
017: import java.util.HashSet;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Set;
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: public class PSDesktopContextFactory implements DesktopContextFactory,
025: SessionListener, PSContextConstants {
026: //
027: // TBD: should this be configurable?
028: // regardless, 5 minutes is to too short
029: //
030: private static final long REAP_INTERVAL = 300000;
031:
032: private HashMap desktopContexts = new HashMap();
033: private DesktopContextReaper dcReaper = null;
034:
035: protected DesktopAppContext desktopAppContext = null;
036: protected ServletContext initConfig = null;
037:
038: // Create a logger for this class
039: private static Logger debugLogger = PortalLogger
040: .getLogger(PSDesktopContextFactory.class);
041:
042: private static class DesktopContextCacheElement {
043: private DesktopContext desktopContext = null;
044: private long expiresTime = -1;
045:
046: private DesktopContextCacheElement() {
047: }
048:
049: public DesktopContextCacheElement(
050: DesktopContext desktopContext, int expires) {
051: this .desktopContext = desktopContext;
052: if (expires != -1) {
053: this .expiresTime = System.currentTimeMillis()
054: + (expires * 1000);
055: }
056: }
057:
058: public DesktopContextCacheElement(DesktopContext desktopContext) {
059: this (desktopContext, -1);
060: }
061:
062: public DesktopContext getDesktopContext() {
063: return desktopContext;
064: }
065:
066: public long getExpiresTime() {
067: return expiresTime;
068: }
069: }
070:
071: private class DesktopContextReaper {
072: private Map desktopContexts = null;
073: private long reapInterval;
074: private long lastReap = -1;
075:
076: public DesktopContextReaper(Map desktopContexts,
077: long reapInterval) {
078: this .desktopContexts = desktopContexts;
079: this .reapInterval = reapInterval;
080: }
081:
082: public void reap() {
083: long now = System.currentTimeMillis();
084: if (now > lastReap + reapInterval) {
085: lastReap = now;
086: debugLogger.fine("PSDT_CSPDC0021");
087: Set removeKeys = new HashSet();
088: for (Iterator i = desktopContexts.keySet().iterator(); i
089: .hasNext();) {
090: String sid = (String) i.next();
091: DesktopContextCacheElement dcce = (DesktopContextCacheElement) desktopContexts
092: .get(sid);
093: if (dcce.getExpiresTime() != -1
094: && now > dcce.getExpiresTime()) {
095: removeKeys.add(sid);
096: }
097: }
098: for (Iterator i = removeKeys.iterator(); i.hasNext();) {
099: String sid = (String) i.next();
100: desktopContexts.remove(sid);
101: debugLogger.log(Level.INFO, "PSDT_CSPDC0022", sid);
102: }
103: }
104: }
105: }
106:
107: public PSDesktopContextFactory() {
108: // nothing
109: }
110:
111: public void init(ServletContext sc) {
112: initConfig = sc;
113: initDesktopAppContext();
114:
115: //
116: // the creation and starting of the reaper thread
117: // is disabled per bug #4720290. see this bug report
118: // for details
119: //
120: //startDesktopContextReaper();
121:
122: dcReaper = new DesktopContextReaper(desktopContexts,
123: REAP_INTERVAL);
124: }
125:
126: /*
127: protected void startDesktopContextReaper() {
128: DesktopContextReaper reaper = new DesktopContextReaper(this);
129: reaper.start();
130: }
131: */
132:
133: public DesktopAppContext getDesktopAppContext() {
134: if (desktopAppContext == null) {
135: throw new ContextError(
136: "PSDesktopContextFactory.getDesktopAppContext(): not initialized");
137: }
138:
139: DesktopAppContextThreadLocalizer.set(desktopAppContext);
140: return desktopAppContext;
141: }
142:
143: protected synchronized void initDesktopAppContext() {
144: String desktopAppContextClassName = initConfig
145: .getInitParameter(SC_APP_CONTEXT_CLASSNAME);
146: if (desktopAppContextClassName == null) {
147: throw new ContextError(
148: "PSDesktopContextFactory.getDesktopAppContext(): could not get desktop app context class name");
149: }
150:
151: try {
152: desktopAppContext = (DesktopAppContext) (Class
153: .forName(desktopAppContextClassName).newInstance());
154: desktopAppContext.init(initConfig);
155: } catch (ClassNotFoundException cnfe) {
156: throw new ContextError(
157: "PSDesktopContextFactory.getDesktopAppContext(): ",
158: cnfe);
159: } catch (NoClassDefFoundError ncdfe) {
160: throw new ContextError(
161: "PSDesktopContextFactory.getDesktopAppContext(): ",
162: ncdfe);
163: } catch (IllegalAccessException iae) {
164: throw new ContextError(
165: "PSDesktopContextFactory.getDesktopAppContext(): ",
166: iae);
167: } catch (ClassCastException cce) {
168: throw new ContextError(
169: "PSDesktopContextFactory.getDesktopAppContext(): ",
170: cce);
171: } catch (InstantiationException ie) {
172: throw new ContextError(
173: "PSDesktopContextFactory.getDesktopAppContext(): ",
174: ie);
175: } catch (SecurityException se) {
176: throw new ContextError(
177: "PSDesktopContextFactory.getDesktopAppContext(): ",
178: se);
179: }
180: }
181:
182: public synchronized void releaseDesktopContexts(Set sessionIDs) {
183: for (Iterator i = sessionIDs.iterator(); i.hasNext();) {
184: String sid = (String) i.next();
185: if (desktopContexts.containsKey(sid)) {
186: desktopContexts.remove(sid);
187: }
188: }
189: }
190:
191: // BEGIN CR6344207
192:
193: // Note: getDesktopContext(...) was changed to remove the initialization of
194: // a DesktopContext object out of a critical section that all
195: // requests could potentially block on. DesktopContext.init()
196: // resulted in LDAP activity that could potentially hang, and
197: // thus block all future requests. So..., this was removed from
198: // a global critical section.
199:
200: public DesktopContext getDesktopContext(HttpServletRequest req) {
201: return getDesktopContext(req, -1);
202: }
203:
204: public DesktopContext getDesktopContext(HttpServletRequest req,
205: int expires) {
206: return getDesktopContext(req, expires, true);
207: }
208:
209: public DesktopContext getDesktopContext(HttpServletRequest req,
210: int expires, boolean create) {
211:
212: DesktopContext context = null;
213: String sid = desktopAppContext.getSessionID(req);
214:
215: synchronized (desktopContexts) {
216:
217: dcReaper.reap();
218:
219: DesktopContextCacheElement dcce = (DesktopContextCacheElement) desktopContexts
220: .get(sid);
221:
222: if (dcce != null) {
223: if (dcce.getDesktopContext().getIsStale()) {
224: //synchronized (desktopContexts) {
225: desktopContexts.remove(sid);
226: //}
227: } else {
228: context = dcce.getDesktopContext();
229: }
230: }
231:
232: if (context == null && create) {
233: //
234: // could not find in cache
235: // create a new one
236: //
237: String desktopContextClassName = desktopAppContext
238: .getDesktopContextClassName();
239:
240: try {
241: context = (DesktopContext) (Class
242: .forName(desktopContextClassName)
243: .newInstance());
244:
245: //
246: // put the new object into the cache
247: //
248: dcce = new DesktopContextCacheElement(context,
249: expires);
250: desktopContexts.put(sid, dcce);
251: } catch (ClassNotFoundException cnfe) {
252: throw new ContextError(
253: "PSDesktopContextFactory.getDesktopContext(): ",
254: cnfe);
255: } catch (NoClassDefFoundError ncdfe) {
256: throw new ContextError(
257: "PSDesktopContextFactory.getDesktopContext(): ",
258: ncdfe);
259: } catch (IllegalAccessException iae) {
260: throw new ContextError(
261: "PSDesktopContextFactory.getDesktopContext(): ",
262: iae);
263: } catch (ClassCastException cce) {
264: throw new ContextError(
265: "PSDesktopContextFactory.getDesktopContext(): ",
266: cce);
267: } catch (InstantiationException ie) {
268: throw new ContextError(
269: "PSDesktopContextFactory.getDesktopContext(): ",
270: ie);
271: } catch (SecurityException se) {
272: throw new ContextError(
273: "PSDesktopContextFactory.getDesktopContext(): ",
274: se);
275: }
276: }
277: }
278:
279: if (context != null) {
280: synchronized (context) {
281: try {
282: if (!context.isInitDone()) {
283: context.init(req);
284: context.addSessionListener(this );
285:
286: //UBT code - start
287: try {
288: UBTLogManager manager = UBTLogManager
289: .getInstance();
290: if (manager.isUBTEnabled()) {
291: UBTEvent prov_ren = UBTEvent
292: .getInstance(DesktopEvents.SESSION_START);
293: prov_ren.put(UBTLogField.ACTION,
294: "Login");
295: manager.logEvent(new ProviderLogRecord(
296: prov_ren, req, null, context
297: .getUserID()));
298: }
299: } catch (Exception e) {
300: //ubt exception
301: }
302: //UBT code - end
303: }
304: } catch (Exception e) {
305: throw new ContextError(
306: "PSDesktopContextFactory.getDesktopContext(): ",
307: e);
308: }
309:
310: context.setLastAccess(System.currentTimeMillis());
311:
312: DesktopContextThreadLocalizer.set(context);
313: }
314: }
315:
316: return context;
317: }
318:
319: // END CR6344207
320:
321: //
322: // the creation and starting of the reaper thread
323: // is disabled per bug #4720290. see this bug report
324: // for details
325: //
326: /*
327: public void reapDesktopContexts(long maxInactive) {
328: DesktopContext context = null;
329: HashMap smap = null;
330:
331: synchronized (desktopContexts) {
332: smap = (HashMap)desktopContexts.clone();
333: }
334:
335: for (Iterator it = smap.keySet().iterator(); it.hasNext(); ) {
336: String sid = (String)it.next();
337: DesktopContext dc = (DesktopContext)smap.get(sid);
338:
339: if (dc == null) {
340: //desktopAppContext.debugError("PSDesktopContextFactory.reapDesktopContexts(): no desktop context found for sid=" + sid);
341: } else {
342: long now = System.currentTimeMillis();
343: long durInactive = now - dc.getLastAccess();
344:
345: //desktopAppContext.debugError("PSDesktopContextFactory.reapDesktopContexts(): durInactive=" + durInactive + " for sid=" + sid);
346: if (durInactive > maxInactive) {
347: synchronized (desktopContexts) {
348: desktopContexts.remove(sid);
349: }
350: //desktopAppContext.debugError("PSDesktopContextFactory.reapDesktopContexts(): removed desktop context for sid=" + sid);
351: }
352: }
353: }
354: }
355: */
356:
357: public synchronized void sessionDestroyed(SessionEvent se) {
358: String sid = se.getSessionID();
359: //UBT code - start
360: try {
361: UBTLogManager manager = UBTLogManager.getInstance();
362: if (manager.isUBTEnabled()) {
363: UBTEvent prov_ren = UBTEvent
364: .getInstance(DesktopEvents.SESSION_TERMINATE);
365: prov_ren.put(UBTLogField.ACTION, "Logout");
366: manager.logEvent(new ProviderLogRecord(prov_ren, null,
367: null,
368: ((DesktopContextCacheElement) desktopContexts
369: .get(sid)).getDesktopContext()
370: .getUserID()));
371: }
372: } catch (Exception e) {
373: //ubt exception
374: }
375: //UBT code - end
376:
377: desktopContexts.remove(sid);
378:
379: }
380:
381: //
382: // the creation and starting of the reaper thread
383: // is disabled per bug #4720290. see this bug report
384: // for details.
385: /*
386: class DesktopContextReaper extends Thread {
387: private DesktopContextFactory factory = null;
388: private DesktopAppContext dac = null;
389:
390: public DesktopContextReaper(DesktopContextFactory factory) {
391: this.factory = factory;
392: this.dac = factory.getDesktopAppContext();
393: setDaemon(true);
394: }
395:
396: public void run() {
397: while (true) {
398: try {
399: long maxInactive = dac.getInactiveMax();
400: factory.reapDesktopContexts(maxInactive * 1000);
401:
402: long interval = dac.getReapInterval();
403:
404: synchronized (this) {
405: sleep(interval * 1000);
406: }
407: } catch (Throwable t) {
408: dac.debugError("DesktopContextReaper.run()", t);
409: }
410: }
411: }
412: }
413: */
414: }
|