001: /**
002: * $Id: PSClientAwareContextFactory.java,v 1.4 2005/07/15 00:17:26 rakeshn Exp $
003: * Copyright 2002 Sun Microsystems, Inc. Allrights reserved. Use of
004: * this product is subjectto license terms. Federal Acquisitions:
005: * Commercial Software -- Government Users Subject to Standard License
006: * Terms and Conditions.
007: *
008: * Sun, Sun Microsystems, the Sun logo, and Sun ONE are trademarks or
009: * registered trademarks of Sun Microsystems,Inc. in the United States
010: * and other countries.
011: */package com.sun.ssoadapter.config;
012:
013: import java.util.Iterator;
014: import java.util.Map;
015: import java.util.HashMap;
016: import java.util.MissingResourceException;
017:
018: import javax.servlet.ServletConfig;
019: import com.sun.ssoadapter.SSOAdapterSession;
020:
021: /**
022: * PSClientAwareContextFactory
023: * <br>
024: * This is the factory class for obtaining service objects stored in a Service
025: * definition - ex: DSAME Schema
026: * <p>
027: * Usage:
028: * Call the static method PSClientAwareContextFactory.getInstance() or
029: * PSClientAwareContextFactory.getInstance(String configContextClassName)
030: *
031: * A ConfigContext object is created using the configContextClassName. And the
032: * ConfigContext must return a valid pathname for Template base directory and a
033: * valid classname for creating the ClientAwareAppContext object.
034: *
035: * The default ConfigContext object is property file driven and uses the
036: * <a href="http://ipsmap.red.iplanet.com:8080/oldsite/design/saal/SAALContext.properties">
037: * SAALContext.properties </a>
038: * file.
039: *
040: * <p>
041: * Sample Code:
042: * <code>
043: * <p>
044: * PSClientAwareContextFactory mapFac = null;<br>
045: *
046: * try { <br>
047: * mapFac = PSClientAwareContextFactory.getInstance();<br>
048: * } catch (SAALException se) {<br>
049: * // return to login page <br>
050: * return; <br>
051: * }
052:
053: * <p>
054: * // <br>
055: * // To get the global context (when session is not available) <br>
056: * // <br>
057: *
058: * ClientAwareAppContext caAppContext = null;<br>
059: * try {<br>
060: * caAppContext = mapFac.getClientAwareAppContext();<br>
061: * } catch (SAALException se) {<br>
062: * // return to login page <br>
063: * return; <br>
064: * }<br>
065: *
066: * <p>
067: * // <br>
068: * // To get a user specific context - pass in the SSOAdapterSession <br>
069: * //<br>
070: *
071: * try { <br>
072: * ClientAwareUserContext caUserContext =
073: * mapFac.getClientAwareUserContext(session); <br>
074: * } catch (IllegalStateException ie) { <br>
075: * // return to login page <br>
076: * return; <br>
077: * } catch (SAALException se) { <br>
078: * // return to login page <br>
079: * return; <br>
080: * }
081: *
082: * <p>
083: * Map serviceMap = new HashMap();
084: * <br>
085: * serviceMap.put ("serviceName", "DesktopMailService");
086: * <br>
087: *
088: * // <br>
089: * // The global attributes can be obtained using either the <br>
090: * // global context or the user context. <br>
091: * // Ex: When using a global context (without a session) <br>
092: * // Pass in the servicename (or any other) backend service<br>
093: * // specific requirements through the serviceMap <br>
094: * // <br>
095: *
096: * String mailConnectionPoolCacheSize =
097: * caAppContext.getStringAttribute (serviceMap, "cachesize");
098: * <br>
099: *
100: * <p>
101: * // <br>
102: * // To get a user specific attribute's value <br>
103: * // <br>
104: *
105: * String mailUserName =
106: * caUserContext.getStringAttribute (serviceMap, "userName");
107: * <br>
108: *
109: * <p>
110: * <b>
111: * // <br>
112: * // Since the default behaviour of the API is to fetch <br>
113: * // User/Dynamic attributes, the serviceMap can be null.<br>
114: * // <br>
115: * </b>
116: *
117: * String mailUserName =
118: * caUserContext.getStringAttribute (null, "userName");
119: * <br>
120: *
121: * </code>
122: *
123: */
124:
125: public class PSClientAwareContextFactory implements SessionListener {
126: //
127: // static objects
128: //
129:
130: // store the factories
131: //
132: private static Map facHashMap = new HashMap();
133:
134: //
135: // Default config context classname
136: //
137: private static final String CONFIG_CONTEXT_CLASSNAME = "com.sun.ssoadapter.config.PropertiesConfigContext";
138:
139: //
140: // per-instance objects
141: //
142: private HashMap caUserContexts = new HashMap();
143:
144: private ConfigContext config = null;
145:
146: private ClientAwareAppContext caAppContext = null;
147:
148: private String this ClassName = null;
149:
150: //
151: // authless authentication session uid
152: //
153: private static final String authlessSUID = "ssoadapter.authless.suid";
154:
155: //
156: // The classnames of the implementations.
157: //
158: private String caAppContextClassName = null;
159: private String caUserContextClassName = null;
160: private String caAuthlessUserContextClassName = null;
161:
162: protected PSClientAwareContextFactory() {
163: this ClassName = getClass().getName(); // for debug
164: }
165:
166: /**
167: *
168: * @param configContextClassName The classname for the ConfigContext impl.
169: * @exception SAALException if the class could not be instantiated.
170: */
171: private void init(String configContextClassName)
172: throws SAALException {
173: //
174: // Create the ConfigContext Object
175: //
176:
177: try {
178: config = (ConfigContext) (Class
179: .forName(configContextClassName).newInstance());
180: } catch (Exception cnfe) {
181: throw new SAALException(this ClassName
182: + ": Could not create ConfigContext class: "
183: + configContextClassName + ": " + cnfe);
184: }
185:
186: config.init(); // throws SAALException
187:
188: //
189: // Get the class names once, instead of in the
190: // getClientAware*Methods() - perf
191: //
192: caAppContextClassName = config
193: .getClientAwareAppContextClassName();
194: if (caAppContextClassName == null) {
195: throw new MissingResourceException(
196: "Could not get Appcontext class name from config file",
197: "ConfigContext", "clientAwareAppContextClassName");
198: }
199:
200: caUserContextClassName = config
201: .getClientAwareUserContextClassName();
202: if (caUserContextClassName == null) {
203: throw new MissingResourceException(
204: this ClassName
205: + ": Could not get UserContext class name from config file",
206: "ConfigContext", "clientAwareUserContextClassName");
207: }
208:
209: caAuthlessUserContextClassName = config
210: .getClientAwareAuthlessUserContextClassName();
211: if (caAuthlessUserContextClassName == null) {
212: throw new MissingResourceException(
213: this ClassName
214: + ": Could not get AuthlessUserContext class name from config file",
215: "ConfigContext",
216: "clientAwareAuthlessUserContextClassName");
217: }
218: }
219:
220: /**
221: * Get an instance of the factory using the default ConfigContext
222: * classname. The default is
223: * com.sun.ssoadapter.config.PropertiesConfigContext.
224: *
225: * @return An instance of PSClientAwareContextFactory.
226: *
227: * @exception SAALException if the ClientAwareContextFactory object could
228: * not be created.
229: */
230: public static PSClientAwareContextFactory getInstance()
231: throws SAALException {
232: return getInstance(CONFIG_CONTEXT_CLASSNAME);
233: }
234:
235: /**
236: * Get an instance of the factory driven by the ConfigContext object created
237: * with configContextClassName. The ConfigContext class must be in the
238: * default web-containers CLASSPATH.
239: *
240: * @param configContextClassName The classname to use, to create the
241: * the ConfigContext object.
242: * @return An instance of PSClientAwareContextFactory.
243: * @see ConfigContext
244: *
245: * @exception SAALException if the ClientAwareContextFactory object could
246: * not be created.
247: */
248:
249: public static PSClientAwareContextFactory getInstance(
250: String configContextClassName) throws SAALException {
251: PSClientAwareContextFactory mapFac = null;
252:
253: synchronized (facHashMap) {
254: //
255: // Look in the Hashmap with the configFilename
256: //
257: if ((mapFac = (PSClientAwareContextFactory) facHashMap
258: .get(configContextClassName)) == null) {
259: mapFac = new PSClientAwareContextFactory();
260: mapFac.init(configContextClassName);
261:
262: facHashMap.put(configContextClassName, mapFac);
263: }
264: }
265:
266: return (mapFac);
267: }
268:
269: /**
270: * Get an instance of ClientAwareAppContext Object.
271: * This method uses the getClientAwareAppContextClassName() of
272: * ConfigContext object (created in getInstance()). And generates the
273: * object with the Class.forName(). The default ClassLoader and the
274: * CLASSPATH of the web-container will be used.
275: *
276: * @see ConfigContext
277: * @exception SAALException if the ClientAwareAppContext could not be
278: * created. (either because the implementation class could not be
279: * instantiated or because, connection could not be establishished
280: * with the backend service provider).
281: * @return
282: */
283: public synchronized ClientAwareAppContext getClientAwareAppContext()
284: throws SAALException {
285:
286: if (caAppContext == null) {
287: ClientAwareAppContext appCntxt = null;
288: try {
289: appCntxt = (ClientAwareAppContext) (Class
290: .forName(caAppContextClassName).newInstance());
291: } catch (Exception cnfe) {
292: throw new SAALException(this ClassName
293: + ": Could not create AppContext class: "
294: + caAppContextClassName + ":: " + cnfe);
295: }
296:
297: //
298: // SAALException is thrown in init();
299: //
300: appCntxt.init(this );
301:
302: caAppContext = appCntxt; // if all goes well
303: }
304:
305: return caAppContext;
306: }
307:
308: /**
309: * Creates an ClientAwareUserContext Object.
310: * This method invokes the getClientAwareUserContextClassName() of
311: * the ClientAwareAppContext object. And generates the object with the
312: * Class.forName(). The default ClassLoader and the CLASSPATH of the
313: * web-container will be used.
314: *
315: * @param session The SSOAdapterSession
316: * @return A ClientAwareUserContext object.
317: *
318: * @exception IllegalStateException if the session is not valid.
319: * @exception SAALException if the ClientAwareUserContext could not be
320: * created. (either because the implementation class could not be
321: * instantiated or because, connection could not be establishished
322: * with the backend service provider).
323: */
324:
325: public ClientAwareUserContext getClientAwareUserContext(
326: SSOAdapterSession session) throws IllegalStateException,
327: SAALException {
328: ClientAwareUserContext userContext = null;
329: String contextClassName = caUserContextClassName;
330: boolean isValidSession = true;
331:
332: //
333: // if the user called this without creating a AppContext
334: //
335: if (caAppContext == null)
336: caAppContext = getClientAwareAppContext();
337:
338: String sid = session.getSessionID();
339:
340: // if sid is null the session is not valid, so check the request for
341: // the authless authentication session uid
342: //
343: if (sid == null) {
344: sid = session.getAuthlessUID();
345:
346: // authless session uid set, so verify this uid is authorized
347: // as an authless ssoadapter user
348: //
349: if (caAppContext.isAuthorizedAuthlessUID(sid)) {
350: contextClassName = caAuthlessUserContextClassName;
351: isValidSession = false;
352: } else {
353: throw new IllegalStateException("Session Invalid:");
354: }
355: }
356:
357: synchronized (caUserContexts) {
358: userContext = (ClientAwareUserContext) caUserContexts
359: .get(sid);
360: if (userContext == null) {
361: //
362: // could not find in cache create a new one
363: //
364: try {
365: userContext = (ClientAwareUserContext) (Class
366: .forName(contextClassName).newInstance());
367:
368: } catch (Exception cnfe) {
369: throw new SAALException(this ClassName
370: + ": Could not create UserContext class: "
371: + contextClassName + ":: " + cnfe);
372: }
373:
374: userContext.init(session, caAppContext); // throws SAALException
375:
376: //
377: // put the new object into the cache
378: //
379: caUserContexts.put(sid, userContext);
380:
381: if (isValidSession) {
382: caAppContext.addSessionListener(session);
383: }
384:
385: } else {
386:
387: }
388: } // sync
389:
390: return userContext;
391: }
392:
393: /**
394: * The ContextFactory caches the UserContexts internally using the
395: * session ids to improve performance. To clean up the contexts of
396: * timed-out/logged-out sessions the ContextFactory implements the
397: * Sessionlistener Object, and registers the ContextFactory object
398: * with the backend session provider using the ClientAwareUserContext:
399: * addSessionListener(SessionListener) method. When the session is
400: * invalidated the sessionDestroyed() of this object "CAN" be called
401: * by the implementation of the ClientAwareUserContext.
402: *
403: * This method removes the expired session from its cache
404: * <p>
405: * @param sid The session id
406: */
407:
408: public void sessionDestroyed(String sid) {
409: synchronized (caUserContexts) {
410: caUserContexts.remove(sid);
411: }
412: }
413:
414: }
|