1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.portalsite.impl;
18
19 import java.io.Serializable;
20 import java.security.AccessController;
21 import java.security.Principal;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28 import javax.security.auth.Subject;
29 import javax.servlet.http.HttpSessionActivationListener;
30 import javax.servlet.http.HttpSessionBindingEvent;
31 import javax.servlet.http.HttpSessionBindingListener;
32 import javax.servlet.http.HttpSessionEvent;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.jetspeed.om.folder.Folder;
37 import org.apache.jetspeed.om.page.Page;
38 import org.apache.jetspeed.page.PageManager;
39 import org.apache.jetspeed.page.PageManagerEventListener;
40 import org.apache.jetspeed.page.document.Node;
41 import org.apache.jetspeed.page.document.NodeException;
42 import org.apache.jetspeed.page.document.NodeNotFoundException;
43 import org.apache.jetspeed.page.document.NodeSet;
44 import org.apache.jetspeed.portalsite.PortalSiteRequestContext;
45 import org.apache.jetspeed.portalsite.PortalSiteSessionContext;
46 import org.apache.jetspeed.portalsite.view.SiteView;
47 import org.apache.jetspeed.portalsite.view.SiteViewMenuDefinitionLocator;
48 import org.apache.jetspeed.profiler.ProfileLocator;
49 import org.apache.jetspeed.profiler.ProfileLocatorProperty;
50 import org.apache.jetspeed.security.JSSubject;
51 import org.apache.jetspeed.security.UserPrincipal;
52
53 /***
54 * This class encapsulates managed session state for and
55 * interface to the portal-site component and subscribes
56 * to page manager and session events to flush stale state.
57 *
58 * Note that is object is Serializable since it is designed
59 * to be cached in the session. However, because this object
60 * is cached only for these two reasons:
61 *
62 * 1. a performance optimization to reuse SiteViews, and
63 * 2. to hold optional folder page history,
64 *
65 * this object need not be relocatable between J2 instances.
66 * Consequently, all data members are marked transient and
67 * the isValid() method is used to test whether this object
68 * is a valid context for the session or if it was
69 * transferred from another server or the persistent session
70 * store and needs to be discarded.
71 *
72 * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
73 * @version $Id: PortalSiteSessionContextImpl.java 553375 2007-07-05 05:37:00Z taylor $
74 */
75 public class PortalSiteSessionContextImpl implements PortalSiteSessionContext, PageManagerEventListener, HttpSessionActivationListener, HttpSessionBindingListener, Serializable
76 {
77 /***
78 * log - logging instance
79 */
80 private final static Log log = LogFactory.getLog(PortalSiteSessionContextImpl.class);
81
82 /***
83 * pageManager - PageManager component
84 */
85 private transient PageManager pageManager;
86
87 /***
88 * profileLocators - map of session profile locators by locator names
89 */
90 private transient Map profileLocators;
91
92 /***
93 * userPrincipal - session user principal
94 */
95 private transient String userPrincipal;
96
97 /***
98 * siteView - session site view
99 */
100 private transient SiteView siteView;
101
102 /***
103 * folderPageHistory - map of last page visited by folder
104 */
105 private transient Map folderPageHistory;
106
107 /***
108 * menuDefinitionLocatorCache - cached menu definition locators for
109 * absolute menus valid for session
110 */
111 private transient Map menuDefinitionLocatorCache;
112
113 /***
114 * subscribed - flag that indicates whether this context
115 * is subscribed as event listeners
116 */
117 private transient boolean subscribed;
118
119 /***
120 * stale - flag that indicates whether the state
121 * managed by this context is stale
122 */
123 private transient boolean stale;
124
125 /***
126 * store which pipeline we are serving
127 *
128 */
129 private transient String pipeline = "";
130
131 /***
132 * PortalSiteSessionContextImpl - constructor
133 *
134 * @param pageManager PageManager component instance
135 */
136 public PortalSiteSessionContextImpl(PageManager pageManager)
137 {
138 this.pageManager = pageManager;
139 this.pipeline = "";
140 }
141
142 /***
143 * newRequestContext - create a new request context instance with fallback and history
144 *
145 * @param requestProfileLocators request profile locators
146 * @return new request context instance
147 */
148 public PortalSiteRequestContext newRequestContext(Map requestProfileLocators)
149 {
150 return new PortalSiteRequestContextImpl(this, requestProfileLocators, true, true);
151 }
152
153 /***
154 * newRequestContext - create a new request context instance with history
155 *
156 * @param requestProfileLocators request profile locators
157 * @param requestFallback flag specifying whether to fallback to root folder
158 * if locators do not select a page or access is forbidden
159 * @return new request context instance
160 */
161 public PortalSiteRequestContext newRequestContext(Map requestProfileLocators, boolean requestFallback)
162 {
163 return new PortalSiteRequestContextImpl(this, requestProfileLocators, requestFallback, true);
164 }
165
166 /***
167 * newRequestContext - create a new request context instance
168 *
169 * @param requestProfileLocators request profile locators
170 * @param requestFallback flag specifying whether to fallback to root folder
171 * if locators do not select a page or access is forbidden
172 * @param useHistory flag indicating whether to use visited page
173 * history to select default page per site folder
174 * @return new request context instance
175 */
176 public PortalSiteRequestContext newRequestContext(Map requestProfileLocators, boolean requestFallback, boolean useHistory)
177 {
178 return new PortalSiteRequestContextImpl(this, requestProfileLocators, requestFallback, useHistory);
179 }
180
181 /***
182 * selectRequestPage - select page proxy for request given profile locators
183 *
184 * @param requestProfileLocators map of profile locators for request
185 * @param requestFallback flag specifying whether to fallback to root folder
186 * if locators do not select a page or access is forbidden
187 * @param useHistory flag indicating whether to use visited page
188 * history to select default page per site folder
189 * @return selected page proxy for request
190 * @throws NodeNotFoundException if not found
191 * @throws SecurityException if view access not granted
192 */
193 public Page selectRequestPage(Map requestProfileLocators, boolean requestFallback, boolean useHistory) throws NodeNotFoundException
194 {
195
196 if (updateSessionProfileLocators(requestProfileLocators))
197 {
198
199 String requestPath = Folder.PATH_SEPARATOR;
200 ProfileLocator locator = (ProfileLocator)requestProfileLocators.get(ProfileLocator.PAGE_LOCATOR);
201 if (locator != null)
202 {
203
204
205 requestPath = getRequestPathFromLocator(locator);
206 }
207 else
208 {
209
210
211
212
213 locator = (ProfileLocator)requestProfileLocators.values().iterator().next();
214 requestPath = locator.getRequestPath();
215 }
216
217
218
219
220
221
222 do
223 {
224
225 Exception fallbackException = null;
226 try
227 {
228 return selectRequestPage(requestPath, useHistory);
229 }
230 catch (NodeNotFoundException nnfe)
231 {
232 if (!requestFallback || requestPath.equals(Folder.PATH_SEPARATOR))
233 {
234 throw nnfe;
235 }
236 fallbackException = nnfe;
237 }
238 catch (SecurityException se)
239 {
240 if (!requestFallback || requestPath.equals(Folder.PATH_SEPARATOR))
241 {
242 throw se;
243 }
244 fallbackException = se;
245 }
246
247
248 if (requestFallback && !requestPath.equals(Folder.PATH_SEPARATOR))
249 {
250
251 String fallbackRequestPath = requestPath;
252 while (fallbackRequestPath.endsWith(Folder.PATH_SEPARATOR))
253 {
254 fallbackRequestPath = fallbackRequestPath.substring(0, fallbackRequestPath.length()-1);
255 }
256 int folderIndex = fallbackRequestPath.lastIndexOf(Folder.PATH_SEPARATOR);
257 if (folderIndex >= 2)
258 {
259
260 fallbackRequestPath = fallbackRequestPath.substring(0, folderIndex);
261 }
262 else
263 {
264
265 fallbackRequestPath = Folder.PATH_SEPARATOR;
266 }
267
268
269 if (!fallbackRequestPath.equals(requestPath))
270 {
271
272 if (log.isDebugEnabled())
273 {
274 log.debug("Missing/forbidden page selection fallback: request path=" + requestPath + ", attempting fallback request path=" + fallbackRequestPath, fallbackException);
275 }
276
277
278
279
280 Iterator folderIter = getFolderPageHistory().keySet().iterator();
281 while (folderIter.hasNext())
282 {
283 Folder folder = (Folder)folderIter.next();
284 if (folder.getUrl().equals(fallbackRequestPath))
285 {
286 folderIter.remove();
287 break;
288 }
289 }
290
291
292 requestPath = fallbackRequestPath;
293 }
294 }
295 else
296 {
297
298 break;
299 }
300 }
301 while (true);
302 }
303
304
305 throw new NodeNotFoundException("No request page available in site view.");
306 }
307
308 /***
309 * getRequestPathFromLocator - execute profile locator to extract
310 * request path using locator rules; this
311 * is request specific and is not part of
312 * the site view
313 *
314 * @param locator profile locator to execute
315 * @return request path from profile locator
316 */
317 private String getRequestPathFromLocator(ProfileLocator locator)
318 {
319
320
321
322
323
324 String requestPath = locator.getRequestPath();
325 Iterator locatorIter = locator.iterator();
326 if (locatorIter.hasNext())
327 {
328 ProfileLocatorProperty [] properties = (ProfileLocatorProperty []) locatorIter.next();
329 for (int i = 0; (i < properties.length); i++)
330 {
331 if (!properties[i].isControl() && !properties[i].isNavigation())
332 {
333
334
335 String path = properties[i].getValue();
336 if (path != null)
337 {
338
339
340
341 if (!path.startsWith(Folder.PATH_SEPARATOR))
342 {
343
344
345 String basePath = requestPath;
346 if (basePath == null)
347 {
348 basePath = Folder.PATH_SEPARATOR;
349 }
350 else if (basePath.endsWith(Page.DOCUMENT_TYPE))
351 {
352 basePath = basePath.substring(0, basePath.lastIndexOf(Folder.PATH_SEPARATOR)+1);
353 }
354 else if (!basePath.endsWith(Folder.PATH_SEPARATOR))
355 {
356 basePath += Folder.PATH_SEPARATOR;
357 }
358 path = basePath + path;
359
360
361
362 if (!path.endsWith(Folder.PATH_SEPARATOR) && !path.endsWith(Page.DOCUMENT_TYPE))
363 {
364 path += Page.DOCUMENT_TYPE;
365 }
366 }
367
368
369 if (!path.equals(requestPath))
370 {
371
372
373
374
375
376 if (path.endsWith(Folder.PATH_SEPARATOR + Folder.FALLBACK_DEFAULT_PAGE))
377 {
378 path = path.substring(0, path.length() - Folder.FALLBACK_DEFAULT_PAGE.length());
379 }
380
381
382 if (log.isDebugEnabled() && !path.equals(requestPath))
383 {
384 log.debug("Request page modified by profile locator: request path=" + path);
385 }
386 }
387 return path;
388 }
389 }
390 }
391 }
392
393
394 return requestPath;
395 }
396
397 /***
398 * selectRequestPage - select page proxy for request for specified
399 * path given profile locators and site view
400 * associated with this context
401 *
402 * @param requestPath request path
403 * @param useHistory flag indicating whether to use visited page
404 * history to select default page per site folder
405 * @return selected page proxy for request
406 * @throws NodeNotFoundException if not found
407 * @throws SecurityException if view access not granted
408 */
409 private Page selectRequestPage(String requestPath, boolean useHistory) throws NodeNotFoundException
410 {
411
412 SecurityException accessException = null;
413
414
415 SiteView view = getSiteView();
416 if (view != null)
417 {
418
419 if (requestPath == null)
420 {
421 requestPath = Folder.PATH_SEPARATOR;
422 }
423
424
425 if (log.isDebugEnabled())
426 {
427 log.debug("Request page: request path=" + requestPath);
428 }
429
430
431
432
433 Node requestNode = null;
434 try
435 {
436
437 requestNode = view.getNodeProxy(requestPath, null, false, false);
438 }
439 catch (NodeNotFoundException nnfe)
440 {
441
442
443 if (requestPath.endsWith(Folder.PATH_SEPARATOR + Folder.FALLBACK_DEFAULT_PAGE))
444 {
445
446 requestPath = requestPath.substring(0, requestPath.length() - Folder.FALLBACK_DEFAULT_PAGE.length());
447 requestNode = view.getNodeProxy(requestPath, null, true, false);
448 }
449 else
450 {
451
452 throw nnfe;
453 }
454 }
455
456
457 if (requestNode instanceof Folder)
458 {
459 Folder requestFolder = (Folder)requestNode;
460
461
462
463
464 try
465 {
466 String defaultFolderName = requestFolder.getDefaultPage();
467 if (defaultFolderName != null)
468 {
469
470 Folder defaultRequestFolder = requestFolder;
471
472 while ((defaultRequestFolder != null) && (defaultFolderName != null) &&
473 defaultFolderName.equals(".."))
474 {
475 defaultRequestFolder = (Folder)defaultRequestFolder.getParent();
476 if (defaultRequestFolder != null)
477 {
478 defaultFolderName = defaultRequestFolder.getDefaultPage();
479 }
480 else
481 {
482 defaultFolderName = null;
483 }
484 }
485
486 while ((defaultRequestFolder != null) && (defaultFolderName != null) &&
487 !defaultFolderName.endsWith(Page.DOCUMENT_TYPE) && !defaultFolderName.equals(".."))
488 {
489 defaultRequestFolder = defaultRequestFolder.getFolder(defaultFolderName);
490 defaultFolderName = defaultRequestFolder.getDefaultPage();
491 }
492
493 if (defaultRequestFolder != null)
494 {
495 requestFolder = defaultRequestFolder;
496 }
497 }
498 }
499 catch (NodeException ne)
500 {
501 }
502 catch (NodeNotFoundException nnfe)
503 {
504 }
505 catch (SecurityException se)
506 {
507 requestFolder = null;
508 accessException = se;
509 }
510
511
512
513
514
515 NodeSet requestFolderPages = null;
516 if (requestFolder != null)
517 {
518 try
519 {
520 requestFolderPages = requestFolder.getPages();
521 while (((requestFolderPages == null) || requestFolderPages.isEmpty()) && (requestFolder.getParent() != null))
522 {
523 requestFolder = (Folder)requestFolder.getParent();
524 requestFolderPages = requestFolder.getPages();
525 }
526 }
527 catch (NodeException ne)
528 {
529 requestFolderPages = null;
530 }
531 catch (SecurityException se)
532 {
533 requestFolderPages = null;
534 accessException = se;
535 }
536 }
537 if ((requestFolder != null) && (requestFolderPages != null) && !requestFolderPages.isEmpty())
538 {
539 Page requestPage = null;
540
541
542
543
544
545 if (useHistory)
546 {
547 requestPage = (Page)getFolderPageHistory().get(requestFolder);
548 if ((requestPage != null) && requestFolderPages.contains(requestPage))
549 {
550
551 if (log.isDebugEnabled())
552 {
553 log.debug("Selected folder historical page: path=" + view.getManagedPage(requestPage).getPath());
554 }
555 return requestPage;
556 }
557 }
558
559
560
561 if (requestFolderPages.size() > 1)
562 {
563 String defaultPageName = requestFolder.getDefaultPage();
564 if (defaultPageName == null)
565 {
566
567
568 defaultPageName = Folder.FALLBACK_DEFAULT_PAGE;
569 }
570 try
571 {
572
573
574
575 requestPage = requestFolder.getPage(defaultPageName);
576 if (!requestPage.isHidden())
577 {
578 getFolderPageHistory().put(requestFolder, requestPage);
579 }
580
581
582 if (log.isDebugEnabled())
583 {
584 log.debug("Selected folder default page: path=" + view.getManagedPage(requestPage).getPath());
585 }
586 return requestPage;
587 }
588 catch (NodeException ne)
589 {
590 }
591 catch (NodeNotFoundException nnfe)
592 {
593 }
594 catch (SecurityException se)
595 {
596 accessException = se;
597 }
598 }
599
600
601
602
603
604 requestPage = (Page)requestFolderPages.iterator().next();
605 if (!requestPage.isHidden())
606 {
607 getFolderPageHistory().put(requestFolder, requestPage);
608 }
609
610
611 if (log.isDebugEnabled())
612 {
613 log.debug("Selected first folder page, path=" + view.getManagedPage(requestPage).getPath());
614 }
615 return requestPage;
616 }
617 }
618 else if (requestNode instanceof Page)
619 {
620 Page requestPage = (Page)requestNode;
621
622
623
624
625 Folder requestFolder = (Folder)requestPage.getParent();
626 if (!requestPage.isHidden())
627 {
628 getFolderPageHistory().put(requestFolder, requestPage);
629 }
630
631
632 if (log.isDebugEnabled())
633 {
634 log.debug("Selected page, path=" + view.getManagedPage(requestPage).getPath());
635 }
636 return requestPage;
637 }
638 }
639
640
641 if (accessException != null)
642 {
643 throw accessException;
644 }
645 throw new NodeNotFoundException("No page matched " + requestPath + " request in site view.");
646 }
647
648 /***
649 * getRequestRootFolder - select root folder proxy for given profile locators
650 *
651 * @param requestProfileLocators map of profile locators for request
652 * @return root folder proxy for request
653 * @throws NodeNotFoundException if not found
654 * @throws SecurityException if view access not granted
655 */
656 public Folder getRequestRootFolder(Map requestProfileLocators) throws NodeNotFoundException
657 {
658
659 if (updateSessionProfileLocators(requestProfileLocators))
660 {
661
662 SiteView view = getSiteView();
663 if (view != null)
664 {
665
666 return view.getRootFolderProxy();
667 }
668 }
669
670
671 throw new NodeNotFoundException("No root folder available in site view.");
672 }
673
674 /***
675 * updateSessionProfileLocators - detect modification of and update cached
676 * session profile locators
677 *
678 * @param requestProfileLocators map of profile locators for request
679 * @return profile locators validation flag
680 */
681 private boolean updateSessionProfileLocators(Map requestProfileLocators)
682 {
683
684 if ((requestProfileLocators != null) && !requestProfileLocators.isEmpty())
685 {
686
687
688 String currentUserPrincipal = null;
689 Subject subject = JSSubject.getSubject(AccessController.getContext());
690 if (subject != null)
691 {
692 Iterator principals = subject.getPrincipals().iterator();
693 while (principals.hasNext())
694 {
695 Principal principal = (Principal) principals.next();
696 if (principal instanceof UserPrincipal)
697 {
698 if (currentUserPrincipal == null)
699 {
700 currentUserPrincipal = principal.getName();
701 }
702 else
703 {
704 currentUserPrincipal += "|" + principal.getName();
705 }
706 }
707 }
708 }
709
710
711
712
713 boolean userUpdate = false;
714 boolean locatorsUpdate = false;
715 boolean updated = false;
716 synchronized (this)
717 {
718 userUpdate = (((userPrincipal == null) && (currentUserPrincipal != null)) ||
719 ((userPrincipal != null) && !userPrincipal.equals(currentUserPrincipal)));
720 locatorsUpdate = ((profileLocators == null) ||
721 !locatorsEquals(profileLocators, requestProfileLocators));
722 if (stale || userUpdate || locatorsUpdate)
723 {
724
725
726
727 clearSessionProfileLocators();
728 profileLocators = requestProfileLocators;
729 userPrincipal = currentUserPrincipal;
730 updated = true;
731 }
732 }
733
734
735 if (updated && log.isDebugEnabled())
736 {
737 StringBuffer debug = new StringBuffer();
738 if (userUpdate)
739 {
740 debug.append("Updated user");
741 if (locatorsUpdate)
742 {
743 debug.append("/locators");
744 }
745 if (stale)
746 {
747 debug.append("/stale");
748 }
749 }
750 else if (locatorsUpdate)
751 {
752 debug.append("Updated locators");
753 if (stale)
754 {
755 debug.append("/stale");
756 }
757 }
758 else
759 {
760 debug.append("Updated stale");
761 }
762 debug.append(" context: user=" + userPrincipal + ", profileLocators=(");
763 if (profileLocators != null)
764 {
765 boolean firstEntry = true;
766 Iterator entriesIter = profileLocators.entrySet().iterator();
767 while (entriesIter.hasNext())
768 {
769 Map.Entry entry = (Map.Entry)entriesIter.next();
770 String locatorName = (String)entry.getKey();
771 ProfileLocator locator = (ProfileLocator)entry.getValue();
772 if (!firstEntry)
773 {
774 debug.append(",");
775 }
776 else
777 {
778 firstEntry = false;
779 }
780 debug.append(locatorName);
781 debug.append("=");
782 debug.append(locator.toString());
783 }
784 }
785 else
786 {
787 debug.append("null");
788 }
789 debug.append(")");
790 log.debug(debug);
791 }
792
793
794 return true;
795 }
796
797
798 return false;
799 }
800
801 /***
802 * clearSessionProfileLocators - clear cache session profile locators
803 */
804 private void clearSessionProfileLocators()
805 {
806
807
808
809 synchronized (this)
810 {
811 profileLocators = null;
812 userPrincipal = null;
813 siteView = null;
814 folderPageHistory = null;
815 if (menuDefinitionLocatorCache != null)
816 {
817 menuDefinitionLocatorCache.clear();
818 }
819 stale = false;
820 }
821 }
822
823 /***
824 * getSiteView - lookup and/or create site view for
825 * profile locators of this context
826 *
827 * @return site view instance
828 */
829 public SiteView getSiteView()
830 {
831 if ((siteView == null) && (pageManager != null) && (profileLocators != null))
832 {
833
834 siteView = new SiteView(pageManager, profileLocators);
835
836
837 if (log.isDebugEnabled())
838 {
839 log.debug("Created site view: search paths=" + siteView.getSearchPathsString());
840 }
841 }
842 return siteView;
843 }
844
845 /***
846 * getPageManager - return PageManager component instance
847 *
848 * @return PageManager instance
849 */
850 public PageManager getPageManager()
851 {
852 return pageManager;
853 }
854
855 /***
856 * isValid - return flag indicating whether this context instance
857 * is valid or if it is stale after being persisted and
858 * reloaded as session state
859 *
860 * @return valid context status
861 */
862 public boolean isValid()
863 {
864
865 return (pageManager != null);
866 }
867
868 /***
869 * getProfileLocators - get session profile locators
870 */
871 public Map getProfileLocators()
872 {
873 return profileLocators;
874 }
875
876 /***
877 * getStandardMenuNames - get set of available standard menu names
878 *
879 * @return menu names set
880 */
881 public Set getStandardMenuNames()
882 {
883
884 SiteView view = getSiteView();
885 if (view != null)
886 {
887 return view.getStandardMenuNames();
888 }
889 return null;
890 }
891
892 /***
893 * getMenuDefinitionLocators - get list of node proxy menu definition
894 * locators from site view
895 *
896 * @param node site view node proxy
897 * @return definition locator list
898 */
899 public List getMenuDefinitionLocators(Node node)
900 {
901
902 SiteView view = getSiteView();
903 if (view != null)
904 {
905 return view.getMenuDefinitionLocators(node);
906 }
907 return null;
908 }
909
910 /***
911 * getMenuDefinitionLocator - get named node proxy menu definition
912 * locator from site view
913 *
914 * @param node site view node proxy
915 * @param name menu definition name
916 * @return menu definition locator
917 */
918 public SiteViewMenuDefinitionLocator getMenuDefinitionLocator(Node node, String name)
919 {
920
921 SiteView view = getSiteView();
922 if (view != null)
923 {
924 return view.getMenuDefinitionLocator(node, name);
925 }
926 return null;
927 }
928
929 /***
930 * getManagedPage - get concrete page instance from page proxy
931 *
932 * @param page page proxy
933 * @return managed page
934 */
935 public Page getManagedPage(Page page)
936 {
937
938 SiteView view = getSiteView();
939 if (view != null)
940 {
941 return view.getManagedPage(page);
942 }
943 return null;
944 }
945
946 /***
947 * getMenuDefinitionLocatorCache - get menu definition locators cache
948 * for absolute menus
949 *
950 * @return menu definition locators cache
951 */
952 public Map getMenuDefinitionLocatorCache()
953 {
954 return menuDefinitionLocatorCache;
955 }
956
957 /***
958 * setMenuDefinitionLocatorCache - set menu definition locators cache
959 * for absolute menus
960 *
961 * @return menu definition locators cache
962 */
963 public void setMenuDefinitionLocatorCache(Map cache)
964 {
965 menuDefinitionLocatorCache = cache;
966 }
967
968 /***
969 * locatorsEquals - test profile locator maps for equivalence
970 * ignoring request specifics
971 *
972 * @param locators0 request profile locator map
973 * @param locators1 request profile locator map
974 * @return boolean flag indicating equivalence
975 */
976 private static boolean locatorsEquals(Map locators0, Map locators1)
977 {
978
979 if (locators0 == locators1)
980 {
981 return true;
982 }
983
984
985 if (locators0.size() != locators1.size())
986 {
987 return false;
988 }
989
990
991 Iterator entriesIter = locators0.entrySet().iterator();
992 if (entriesIter.hasNext())
993 {
994 Map.Entry entry = (Map.Entry)entriesIter.next();
995 ProfileLocator locator0 = (ProfileLocator)entry.getValue();
996 ProfileLocator locator1 = (ProfileLocator)locators1.get(entry.getKey());
997 if (locator1 == null)
998 {
999 return false;
1000 }
1001
1002
1003
1004
1005 ProfileLocatorProperty [] properties0 = (ProfileLocatorProperty [])locator0.iterator().next();
1006 ProfileLocatorProperty [] properties1 = (ProfileLocatorProperty [])locator1.iterator().next();
1007 if ((properties0 != null) || (properties1 != null))
1008 {
1009 if ((properties0 == null) || (properties1 == null) || (properties0.length != properties1.length))
1010 {
1011 return false;
1012 }
1013
1014
1015 for (int i = 0, limit = properties0.length; (i < limit); i++)
1016 {
1017
1018
1019
1020
1021
1022 if (!properties0[i].getName().equals(properties1[i].getName()) ||
1023 (properties0[i].isControl() && !properties1[i].isControl()) ||
1024 (properties0[i].isNavigation() && !properties1[i].isNavigation()) ||
1025 ((properties0[i].isControl() || properties0[i].isNavigation()) &&
1026 (((properties0[i].getValue() == null) && (properties1[i].getValue() != null)) ||
1027 ((properties0[i].getValue() != null) && !properties0[i].getValue().equals(properties1[i].getValue())))))
1028 {
1029 return false;
1030 }
1031 }
1032 }
1033 }
1034 return true;
1035 }
1036
1037 /***
1038 * locatorRequestPath - extract request specific path from profile locator
1039 * using request path from locator
1040 *
1041 * @param locator request profile locator
1042 * @return request path
1043
1044 private static String locatorRequestPath(ProfileLocator locator)
1045 {
1046 // use request path in locator as default
1047 return locatorRequestPath(locator, locator.getRequestPath());
1048 }
1049 */
1050
1051 /***
1052 * locatorRequestPath - extract request specific path from profile locator
1053 *
1054 * @param locator request profile locator
1055 * @param requestPath request path
1056 * @return request path
1057
1058 private static String locatorRequestPath(ProfileLocator locator, String requestPath)
1059 {
1060 // search locator using the most specific,
1061 // (i.e. first), locator properties array
1062 // returned by the locator iterator and return
1063 // first valued property that is not a control
1064 // or navigation type
1065 ProfileLocatorProperty [] properties = (ProfileLocatorProperty [])locator.iterator().next();
1066 for (int i = 0, limit = properties.length; (i < limit); i++)
1067 {
1068 if (!properties[i].isControl() && !properties[i].isNavigation() && (properties[i].getValue() != null))
1069 {
1070 // use specified locator path
1071 String locatorPath = properties[i].getValue();
1072
1073 // return specified locatorPath if absolute
1074 if (locatorPath.startsWith(Folder.PATH_SEPARATOR))
1075 {
1076 return locatorPath;
1077 }
1078
1079 // page names and relative paths are assumed relative to
1080 // request path and that any locator paths with no url
1081 // separator should have the page extension appended
1082 // get default page if page path null
1083 if ((locatorPath.indexOf(Folder.PATH_SEPARATOR) == -1) && !locatorPath.endsWith(Page.DOCUMENT_TYPE))
1084 {
1085 locatorPath += Page.DOCUMENT_TYPE;
1086 }
1087
1088 // append locator path to request path, replacing
1089 // requested pages and preserving requested folders
1090 boolean rootFolderRequest = requestPath.equals(Folder.PATH_SEPARATOR);
1091 boolean folderRequest = (!requestPath.endsWith(Page.DOCUMENT_TYPE));
1092 int lastSeparatorIndex = requestPath.lastIndexOf(Folder.PATH_SEPARATOR_CHAR);
1093 if ((lastSeparatorIndex > 0) && (!folderRequest || requestPath.endsWith(Folder.PATH_SEPARATOR)))
1094 {
1095 // append locator to request path base path
1096 return requestPath.substring(0, lastSeparatorIndex) + Folder.PATH_SEPARATOR + locatorPath;
1097 }
1098 else if (!rootFolderRequest && folderRequest)
1099 {
1100 // append locator to request path root folder
1101 return requestPath + Folder.PATH_SEPARATOR + locatorPath;
1102 }
1103 else
1104 {
1105 // use root folder locator
1106 return Folder.PATH_SEPARATOR + locatorPath;
1107 }
1108 }
1109 }
1110 return requestPath;
1111 }
1112 */
1113
1114 /***
1115 * newNode - invoked when the definition of a node is
1116 * created by the page manager or when the
1117 * node creation is otherwise detected
1118 *
1119 * @param node new managed node if known
1120 */
1121 public void newNode(Node node)
1122 {
1123
1124 updatedNode(node);
1125 }
1126
1127 /***
1128 * updatedNode - invoked when the definition of a node is
1129 * updated by the page manager or when the
1130 * node modification is otherwise detected
1131 *
1132 * @param node updated managed node if known
1133 */
1134 public void updatedNode(Node node)
1135 {
1136
1137 synchronized (this)
1138 {
1139 stale = true;
1140 }
1141
1142
1143 if (log.isDebugEnabled())
1144 {
1145 if (node != null)
1146 {
1147 log.debug("Page manager update event, (node=" + node.getPath() + "): set session context state stale");
1148 }
1149 else
1150 {
1151 log.debug("Page manager update event: set session context state stale");
1152 }
1153 }
1154 }
1155
1156 /***
1157 * removedNode - invoked when the definition of a node is
1158 * removed by the page manager or when the
1159 * node removal is otherwise detected
1160 *
1161 * @param node removed managed node if known
1162 */
1163 public void removedNode(Node node)
1164 {
1165
1166 updatedNode(node);
1167 }
1168
1169 /***
1170 * sessionDidActivate - notification that the session has just
1171 * been activated
1172 *
1173 * @param event session activation event
1174 */
1175 public void sessionDidActivate(HttpSessionEvent event)
1176 {
1177
1178 synchronized (this)
1179 {
1180 stale = true;
1181 }
1182
1183
1184 if (log.isDebugEnabled())
1185 {
1186 log.debug("Session activation event: set session context state stale");
1187 }
1188 }
1189
1190 /***
1191 * sessionWillPassivate - notification that the session is about
1192 * to be passivated
1193 *
1194 * @param event session activation event
1195 */
1196 public void sessionWillPassivate(HttpSessionEvent event)
1197 {
1198
1199 clearSessionProfileLocators();
1200
1201
1202 if (log.isDebugEnabled())
1203 {
1204 log.debug("Session deactivation event: clear session context state");
1205 }
1206 }
1207
1208 /***
1209 * valueBound - notifies this context that it is being bound to
1210 * a session and identifies the session
1211 *
1212 * @param event session binding event
1213 */
1214 public void valueBound(HttpSessionBindingEvent event)
1215 {
1216
1217 synchronized (this)
1218 {
1219 if (!subscribed && (pageManager != null))
1220 {
1221 pageManager.addListener(this);
1222 subscribed = true;
1223 }
1224 }
1225
1226
1227 if (log.isDebugEnabled())
1228 {
1229 log.debug("Session bound event: setup page manager listener");
1230 }
1231 }
1232
1233 /***
1234 * valueUnbound - notifies this context that it is being unbound
1235 * from a session and identifies the session
1236 *
1237 * @param event session binding event
1238 */
1239 public void valueUnbound(HttpSessionBindingEvent event)
1240 {
1241
1242 synchronized (this)
1243 {
1244 if (subscribed && (pageManager != null))
1245 {
1246 pageManager.removeListener(this);
1247 subscribed = false;
1248 }
1249 }
1250
1251
1252 clearSessionProfileLocators();
1253
1254
1255 if (log.isDebugEnabled())
1256 {
1257 log.debug("Session unbound event: clear page manager listener and session context state");
1258 }
1259 }
1260
1261 private Map getFolderPageHistory()
1262 {
1263 if (folderPageHistory == null)
1264 {
1265 folderPageHistory = new HashMap();
1266 }
1267 return folderPageHistory;
1268 }
1269
1270 public void setPipeline(String pipeline)
1271 {
1272 this.pipeline = pipeline;
1273 }
1274
1275 public String getPipeline()
1276 {
1277 return this.pipeline;
1278 }
1279 }