001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.io.IOException;
009: import java.net.URL;
010: import java.util.Collections;
011: import java.util.HashMap;
012: import java.util.Hashtable;
013: import java.util.Map;
014:
015: import javax.servlet.http.HttpServletRequest;
016: import javax.servlet.http.HttpSessionBindingEvent;
017:
018: import org.jasig.portal.i18n.LocaleManager;
019: import org.jasig.portal.jndi.JNDIManager;
020: import org.jasig.portal.layout.IUserLayoutManager;
021: import org.jasig.portal.layout.UserLayoutManagerFactory;
022: import org.jasig.portal.layout.UserLayoutStoreFactory;
023: import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
024: import org.jasig.portal.properties.PropertiesManager;
025: import org.jasig.portal.security.IPerson;
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.jasig.portal.utils.PropsMatcher;
029:
030: /**
031: * Multithreaded version of {@link UserPreferencesManager}.
032: * @author Peter Kharchenko {@link <a href="mailto:pkharchenko@interactivebusiness.com">pkharchenko@interactivebusiness.com</a>}
033: * @version $Revision: 36690 $
034: * @see UserPreferencesManager
035: */
036: public class GuestUserPreferencesManager extends UserPreferencesManager {
037:
038: private static final Log log = LogFactory
039: .getLog(GuestUserPreferencesManager.class);
040:
041: private class MState {
042: private ThemeStylesheetDescription tsd;
043: private StructureStylesheetDescription ssd;
044: private boolean unmapped_user_agent;
045: private UserPreferences complete_up;
046: private IUserLayoutManager ulm;
047:
048: public MState() {
049: tsd = null;
050: ssd = null;
051: complete_up = null;
052: unmapped_user_agent = false;
053: }
054: }
055:
056: Map stateTable;
057:
058: // tables keeping user layouts and clean user preferences for various profiles
059: Hashtable sp_layouts;
060: Hashtable up_layouts;
061:
062: Hashtable sp_cleanUPs;
063: Hashtable up_cleanUPs;
064: Hashtable ts_descripts;
065: Hashtable ss_descripts;
066: Hashtable cached_profiles;
067:
068: IPerson m_person;
069: LocaleManager localeManager;
070:
071: final static boolean SAVE_PROFILE_GUESSES = PropertiesManager
072: .getPropertyAsBoolean("org.jasig.portal.GuestUserPreferencesManager.save_profile_guesses");
073:
074: /**
075: * Initializing constructor.
076: * @param person object
077: */
078: public GuestUserPreferencesManager(IPerson person) {
079: super (person);
080: stateTable = Collections.synchronizedMap(new HashMap());
081: up_cleanUPs = new Hashtable();
082: sp_cleanUPs = new Hashtable();
083: sp_layouts = new Hashtable();
084: up_layouts = new Hashtable();
085: cached_profiles = new Hashtable();
086: ts_descripts = new Hashtable();
087: ss_descripts = new Hashtable();
088: m_person = person;
089: ulsdb = UserLayoutStoreFactory.getUserLayoutStoreImpl();
090: }
091:
092: /**
093: * Unbinds a registered session.
094: * @param sessionId a <code>String</code> value
095: */
096: public void unbindSession(String sessionId) {
097: stateTable.remove(sessionId);
098: }
099:
100: /**
101: * Register arrival of a new session.
102: * Create and populate new state entry.
103: * @param req a <code>HttpServletRequest</code> value
104: * @exception PortalException if an error occurs
105: */
106: public void registerSession(HttpServletRequest req)
107: throws PortalException {
108: MState newState = new MState();
109: try {
110: // load user preferences
111: // determine user profile
112: String userAgent = req.getHeader("User-Agent");
113: if (userAgent == null || userAgent.equals("")) {
114: userAgent = MediaManager.NULL_USER_AGENT;
115: }
116: UserProfile upl;
117: // see if the profile was cached
118: if ((upl = (UserProfile) cached_profiles.get(userAgent)) == null) {
119: synchronized (cached_profiles) {
120: upl = ulsdb.getUserProfile(m_person, userAgent);
121: if (upl == null) {
122: upl = ulsdb.getSystemProfile(userAgent);
123: }
124: if (upl != null) {
125: cached_profiles.put(userAgent, upl);
126: }
127: }
128: }
129:
130: if (upl == null) {
131: // try guessing the profile through pattern matching
132:
133: if (uaMatcher == null) {
134: // init user agent matcher
135: URL url = null;
136: try {
137: url = this .getClass().getResource(
138: "/properties/browser.mappings");
139: if (url != null) {
140: uaMatcher = new PropsMatcher(url
141: .openStream());
142: }
143: } catch (IOException ioe) {
144: log
145: .error("GuestUserPreferencesManager::GuestUserPreferencesManager() : Exception occurred while loading browser mapping file: "
146: + url + ". " + ioe);
147: }
148: }
149:
150: if (uaMatcher != null) {
151: // try matching
152: String profileId = uaMatcher.match(userAgent);
153: if (profileId != null) {
154: // user agent has been matched
155: if (log.isDebugEnabled())
156: log
157: .debug("GuestUserPreferencesManager::GuestUserPreferencesManager() : "
158: + "userAgent \""
159: + userAgent
160: + "\" has matched to a profile "
161: + profileId);
162: upl = ulsdb.getSystemProfileById(Integer
163: .parseInt(profileId));
164: // save mapping
165: if (SAVE_PROFILE_GUESSES) {
166: ulsdb.setSystemBrowserMapping(userAgent,
167: upl.getProfileId());
168: }
169: } else {
170: if (log.isDebugEnabled())
171: log
172: .debug("GuestUserPreferencesManager::GuestUserPreferencesManager() : "
173: + "userAgent \""
174: + userAgent
175: + "\" has not matched any profile.");
176: }
177: }
178: }
179:
180: if (upl != null) {
181: // see if the user layout xml has been cached
182: if (upl.isSystemProfile()) {
183: newState.ulm = (IUserLayoutManager) sp_layouts
184: .get(new Integer(upl.getProfileId()));
185: } else {
186: newState.ulm = (IUserLayoutManager) up_layouts
187: .get(new Integer(upl.getProfileId()));
188: }
189: if (newState.ulm == null) {
190: try {
191: upl.setLocaleManager(localeManager);
192: newState.ulm = UserLayoutManagerFactory
193: .immutableUserLayoutManager(UserLayoutManagerFactory
194: .getUserLayoutManager(m_person,
195: upl));
196: if (upl.isSystemProfile()) {
197: sp_layouts.put(new Integer(upl
198: .getProfileId()), newState.ulm);
199: } else {
200: up_layouts.put(new Integer(upl
201: .getProfileId()), newState.ulm);
202: }
203: } catch (PortalException pe) {
204: throw pe;
205: } catch (Exception e) {
206: throw new PortalException(
207: "GuestUserPreferencesManager::registerSession() : caught an exception while trying to retreive a userLayout for user=\""
208: + m_person.getID()
209: + "\", profile=\""
210: + upl.getProfileName() + "\".",
211: e);
212: }
213: }
214:
215: /*
216: // modify the entire profile to be unremovable and immutable
217: // mark all of the folders
218: NodeList folderList=newState.uLayoutXML.getElementsByTagName("folder");
219: for(int i=0;i<folderList.getLength();i++) {
220: Element e=(Element)folderList.item(i);
221: e.setAttribute("immutable","true");
222: e.setAttribute("unremovable","true");
223: }
224: // mark all of the channels
225: NodeList channelList=newState.uLayoutXML.getElementsByTagName("channel");
226: for(int i=0;i<channelList.getLength();i++) {
227: Element e=(Element)channelList.item(i);
228: e.setAttribute("immutable","true");
229: e.setAttribute("unremovable","true");
230: }
231: */
232:
233: // see if the user preferences for this profile are cached
234: UserPreferences cleanUP;
235: if (upl.isSystemProfile()) {
236: cleanUP = (UserPreferences) sp_cleanUPs
237: .get(new Integer(upl.getProfileId()));
238: } else {
239: cleanUP = (UserPreferences) up_cleanUPs
240: .get(new Integer(upl.getProfileId()));
241: }
242: if (cleanUP == null) {
243: try {
244: cleanUP = ulsdb.getUserPreferences(m_person,
245: upl);
246: if (cleanUP != null) {
247: if (upl.isSystemProfile()) {
248: sp_cleanUPs.put(new Integer(upl
249: .getProfileId()), cleanUP);
250: } else {
251: up_cleanUPs.put(new Integer(upl
252: .getProfileId()), cleanUP);
253: }
254: }
255: } catch (Exception e) {
256: log
257: .error(
258: "GuestUserPreferencesManager::registerSession() : "
259: + "unable to find UP for a profile \""
260: + upl.getProfileName()
261: + "\"", e);
262: cleanUP = new UserPreferences(upl);
263: }
264: }
265:
266: if (cleanUP != null) {
267: newState.complete_up = new UserPreferences(cleanUP);
268: } else {
269: log
270: .error("GuestUserPreferencesManager::registerSession() : "
271: + "unable to find UP for a profile \""
272: + upl.getProfileName() + "\"");
273: newState.complete_up = new UserPreferences(upl);
274: }
275:
276: // Initialize the JNDI context for this user
277: JNDIManager.initializeSessionContext(req.getSession(),
278: Integer.toString(m_person.getID()), Integer
279: .toString(upl.getLayoutId()),
280: newState.ulm.getUserLayoutDOM());
281: } else {
282: // there is no user-defined mapping for this particular browser.
283: // user should be redirected to a browser-registration page.
284: newState.unmapped_user_agent = true;
285: if (log.isDebugEnabled())
286: log
287: .debug("GuestUserPreferencesManager::registerSession() : "
288: + "unable to find a profile for user \""
289: + m_person.getID()
290: + "\" and userAgent=\""
291: + userAgent
292: + "\".");
293: }
294: } catch (PortalException pe) {
295: throw pe;
296: } catch (Throwable t) {
297: throw new PortalException(t);
298: }
299: stateTable.put(req.getSession(false).getId(), newState);
300: }
301:
302: /* This function processes request parameters related to
303: * setting Structure/Theme stylesheet parameters and attributes.
304: * (uP_sparam, uP_tparam, uP_sfattr, uP_scattr uP_tcattr)
305: * It also processes layout root requests (uP_root)
306: */
307: public void processUserPreferencesParameters(HttpServletRequest req) {
308: MState state = (MState) stateTable.get(req.getSession(false)
309: .getId());
310: if (state == null) {
311: throw new IllegalStateException(
312: "Trying to envoke a method on a non-registered sessionId=\""
313: + req.getSession(false).getId() + "\".");
314: }
315: // layout root setting
316: String root;
317: if ((root = req.getParameter("uP_root")) != null) {
318: // If a channel specifies "me" as its root, set the root
319: // to the channel's instance Id
320: if (root.equals("me")) {
321: // get uPFile spec and search for "channel" clause
322: UPFileSpec upfs = new UPFileSpec(req);
323: root = upfs.getTargetNodeId();
324: }
325: if (root != null) {
326: state.complete_up
327: .getStructureStylesheetUserPreferences()
328: .putParameterValue("userLayoutRoot", root);
329: } else {
330: log
331: .error("GuestUserPreferencesManager::processUserPreferencesParameters() : unable to extract channel ID. servletPath=\""
332: + req.getServletPath() + "\".");
333: }
334: }
335: // other params
336: String[] sparams = req.getParameterValues("uP_sparam");
337: if (sparams != null) {
338: for (int i = 0; i < sparams.length; i++) {
339: String pValue = req.getParameter(sparams[i]);
340: state.complete_up
341: .getStructureStylesheetUserPreferences()
342: .putParameterValue(sparams[i], pValue);
343: if (log.isDebugEnabled())
344: log
345: .debug("GuestUserPreferencesManager::processUserPreferencesParameters() : "
346: + "setting sparam \""
347: + sparams[i]
348: + "\"=\"" + pValue + "\".");
349: }
350: }
351: String[] tparams = req.getParameterValues("uP_tparam");
352: if (tparams != null) {
353: for (int i = 0; i < tparams.length; i++) {
354: String pValue = req.getParameter(tparams[i]);
355: state.complete_up.getThemeStylesheetUserPreferences()
356: .putParameterValue(tparams[i], pValue);
357: if (log.isDebugEnabled())
358: log
359: .debug("GuestUserPreferencesManager::processUserPreferencesParameters() : "
360: + "setting tparam \""
361: + tparams[i]
362: + "\"=\"" + pValue + "\".");
363: }
364: }
365: // attribute processing
366: // structure transformation
367: String[] sfattrs = req.getParameterValues("uP_sfattr");
368: if (sfattrs != null) {
369: for (int i = 0; i < sfattrs.length; i++) {
370: String aName = sfattrs[i];
371: String[] aNode = req.getParameterValues(aName
372: + "_folderId");
373: if (aNode != null && aNode.length > 0) {
374: for (int j = 0; j < aNode.length; j++) {
375: String aValue = req.getParameter(aName + "_"
376: + aNode[j] + "_value");
377: state.complete_up
378: .getStructureStylesheetUserPreferences()
379: .setFolderAttributeValue(aNode[j],
380: aName, aValue);
381: if (log.isDebugEnabled())
382: log
383: .debug("GuestUserPreferencesManager::processUserPreferencesParameters() : "
384: + "setting sfattr \""
385: + aName
386: + "\" of \""
387: + aNode[j]
388: + "\" to \""
389: + aValue + "\".");
390: }
391: }
392: }
393: }
394: String[] scattrs = req.getParameterValues("uP_scattr");
395: if (scattrs != null) {
396: for (int i = 0; i < scattrs.length; i++) {
397: String aName = scattrs[i];
398: String[] aNode = req.getParameterValues(aName
399: + "_channelId");
400: if (aNode != null && aNode.length > 0) {
401: for (int j = 0; j < aNode.length; j++) {
402: String aValue = req.getParameter(aName + "_"
403: + aNode[j] + "_value");
404: state.complete_up
405: .getStructureStylesheetUserPreferences()
406: .setChannelAttributeValue(aNode[j],
407: aName, aValue);
408: if (log.isDebugEnabled())
409: log
410: .debug("GuestUserPreferencesManager::processUserPreferencesParameters() : "
411: + "setting scattr \""
412: + aName
413: + "\" of \""
414: + aNode[j]
415: + "\" to \""
416: + aValue + "\".");
417: }
418: }
419: }
420: }
421: // theme stylesheet attributes
422: String[] tcattrs = req.getParameterValues("uP_tcattr");
423: if (tcattrs != null) {
424: for (int i = 0; i < tcattrs.length; i++) {
425: String aName = tcattrs[i];
426: String[] aNode = req.getParameterValues(aName
427: + "_channelId");
428: if (aNode != null && aNode.length > 0) {
429: for (int j = 0; j < aNode.length; j++) {
430: String aValue = req.getParameter(aName + "_"
431: + aNode[j] + "_value");
432: state.complete_up
433: .getThemeStylesheetUserPreferences()
434: .setChannelAttributeValue(aNode[j],
435: aName, aValue);
436: if (log.isDebugEnabled())
437: log
438: .debug("GuestUserPreferencesManager::processUserPreferencesParameters() : setting tcattr \""
439: + aName
440: + "\" of \""
441: + aNode[j]
442: + "\" to \""
443: + aValue + "\".");
444: }
445: }
446: }
447: }
448: }
449:
450: /**
451: * Returns a global channel Id given a channel instance Id
452: * @return Channel's global Id
453: */
454: protected String getChannelGlobalId(String channelSubscribeId,
455: String sessionId) throws PortalException {
456: // Get the channel node from the user's layout
457: IUserLayoutChannelDescription channel = (IUserLayoutChannelDescription) getUserLayoutManager(
458: sessionId).getNode(channelSubscribeId);
459: if (channel != null) {
460: return channel.getChannelPublishId();
461: } else {
462: return null;
463: }
464: }
465:
466: public boolean isUserAgentUnmapped(String sessionId) {
467: MState state = (MState) stateTable.get(sessionId);
468: if (state == null) {
469: throw new IllegalStateException(
470: "Trying to envoke a method on a non-registered sessionId=\""
471: + sessionId + "\".");
472: }
473: return state.unmapped_user_agent;
474: }
475:
476: public boolean isUserAgentUnmapped() {
477: throw new UnsupportedOperationException();
478: }
479:
480: public UserPreferences getUserPreferences(String sessionId) {
481: MState state = (MState) stateTable.get(sessionId);
482: if (state == null) {
483: throw new IllegalStateException(
484: "Trying to envoke a method on a non-registered sessionId=\""
485: + sessionId + "\".");
486: }
487: return state.complete_up;
488: }
489:
490: public UserPreferences getUserPreferences() {
491: throw new UnsupportedOperationException();
492: }
493:
494: /*
495: * Guest users can not (by definition) save any preferences. Method does nothing.
496: */
497: public void setNewUserLayoutAndUserPreferences(
498: IUserLayoutManager newLayout,
499: UserPreferences newPreferences, String sessionId)
500: throws PortalException {
501: // not implemented yet
502: }
503:
504: public void setNewUserLayoutAndUserPreferences(
505: IUserLayoutManager newLayout, UserPreferences newPreferences)
506: throws PortalException {
507: throw new UnsupportedOperationException();
508: }
509:
510: public UserPreferences getUserPreferencesCopy(String sessionId) {
511: return new UserPreferences(this .getUserPreferences(sessionId));
512: }
513:
514: public UserPreferences getUserPreferencesCopy() {
515: throw new UnsupportedOperationException();
516: }
517:
518: /**
519: * Returns current profile
520: * @return UserProfile
521: */
522: public UserProfile getCurrentProfile(String sessionId) {
523: return this .getUserPreferences(sessionId).getProfile();
524: }
525:
526: public UserProfile getCurrentProfile() {
527: throw new UnsupportedOperationException();
528: }
529:
530: public ThemeStylesheetDescription getThemeStylesheetDescription(
531: String sessionId) throws Exception {
532: MState state = (MState) stateTable.get(sessionId);
533: if (state == null) {
534: throw new IllegalStateException(
535: "Trying to envoke a method on a non-registered sessionId=\""
536: + sessionId + "\".");
537: }
538: if (state.tsd == null) {
539: int sid = state.complete_up.getProfile()
540: .getThemeStylesheetId();
541: state.tsd = (ThemeStylesheetDescription) ts_descripts
542: .get(new Integer(sid));
543: if (state.tsd == null) {
544: state.tsd = ulsdb.getThemeStylesheetDescription(sid);
545: ts_descripts.put(new Integer(sid), state.tsd);
546: }
547: }
548: return state.tsd;
549: }
550:
551: public ThemeStylesheetDescription getThemeStylesheetDescription() {
552: throw new UnsupportedOperationException();
553: }
554:
555: public StructureStylesheetDescription getStructureStylesheetDescription(
556: String sessionId) throws Exception {
557: MState state = (MState) stateTable.get(sessionId);
558: if (state == null) {
559: throw new IllegalStateException(
560: "Trying to envoke a method on a non-registered sessionId=\""
561: + sessionId + "\".");
562: }
563: if (state.ssd == null) {
564: int sid = state.complete_up.getProfile()
565: .getStructureStylesheetId();
566: state.ssd = (StructureStylesheetDescription) ss_descripts
567: .get(new Integer(sid));
568: if (state.ssd == null) {
569: state.ssd = ulsdb
570: .getStructureStylesheetDescription(sid);
571: ss_descripts.put(new Integer(sid), state.ssd);
572: }
573: }
574: return state.ssd;
575: }
576:
577: public StructureStylesheetDescription getStructureStylesheetDescription() {
578: throw new UnsupportedOperationException();
579: }
580:
581: public IUserLayoutManager getUserLayoutManager(String sessionId) {
582: MState state = (MState) stateTable.get(sessionId);
583: if (state == null) {
584: throw new IllegalStateException(
585: "Trying to envoke a method on a non-registered sessionId=\""
586: + sessionId + "\".");
587: }
588: return state.ulm;
589: }
590:
591: public IUserLayoutManager getUserLayoutManager() {
592: throw new UnsupportedOperationException();
593: }
594:
595: public void finishedSession(HttpSessionBindingEvent bindingEvent,
596: String sessionId) {
597: // remove session state info
598: stateTable.remove(sessionId);
599: }
600:
601: public void finishedSession(HttpSessionBindingEvent bindingEvent) {
602: throw new UnsupportedOperationException();
603: }
604:
605: public void setLocaleManager(LocaleManager lm) {
606: localeManager = lm;
607: }
608:
609: }
|