View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.page;
18  
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.LinkedList;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.security.auth.Subject;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.jetspeed.om.common.SecurityConstraint;
30  import org.apache.jetspeed.om.common.SecurityConstraints;
31  import org.apache.jetspeed.om.folder.Folder;
32  import org.apache.jetspeed.om.folder.FolderNotFoundException;
33  import org.apache.jetspeed.om.folder.InvalidFolderException;
34  import org.apache.jetspeed.om.folder.MenuDefinition;
35  import org.apache.jetspeed.om.folder.MenuExcludeDefinition;
36  import org.apache.jetspeed.om.folder.MenuIncludeDefinition;
37  import org.apache.jetspeed.om.folder.MenuOptionsDefinition;
38  import org.apache.jetspeed.om.folder.MenuSeparatorDefinition;
39  import org.apache.jetspeed.om.page.Fragment;
40  import org.apache.jetspeed.om.page.Link;
41  import org.apache.jetspeed.om.page.Page;
42  import org.apache.jetspeed.om.page.PageSecurity;
43  import org.apache.jetspeed.om.page.SecurityConstraintsDef;
44  import org.apache.jetspeed.om.preference.FragmentPreference;
45  import org.apache.jetspeed.page.document.Node;
46  import org.apache.jetspeed.page.document.NodeException;
47  import org.apache.jetspeed.page.impl.DatabasePageManagerUtils;
48  
49  /***
50   * AbstractPageManagerService
51   *
52   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
53   * @version $Id: AbstractPageManager.java 517124 2007-03-12 08:10:25Z ate $
54   */
55  public abstract class AbstractPageManager 
56      implements PageManager    
57  {
58      private final static Log log = LogFactory.getLog(AbstractPageManager.class);
59      
60      private final static String FOLDER_NODE_TYPE = "folder";
61      private final static String PAGE_NODE_TYPE = "page";
62      private final static String FRAGMENT_NODE_TYPE = "fragment";
63      private final static String LINK_NODE_TYPE = "link";
64      protected Class fragmentClass;
65      protected Class pageClass;
66      protected Class folderClass;
67      protected Class linkClass;
68      protected Class pageSecurityClass;
69      protected Class propertyClass;
70      protected Class folderMenuDefinitionClass;
71      protected Class folderMenuExcludeDefinitionClass;
72      protected Class folderMenuIncludeDefinitionClass;
73      protected Class folderMenuOptionsDefinitionClass;
74      protected Class folderMenuSeparatorDefinitionClass;
75      protected Class pageMenuDefinitionClass;
76      protected Class pageMenuExcludeDefinitionClass;
77      protected Class pageMenuIncludeDefinitionClass;
78      protected Class pageMenuOptionsDefinitionClass;
79      protected Class pageMenuSeparatorDefinitionClass;
80      protected Class securityConstraintsClass;
81      protected Class folderSecurityConstraintClass;
82      protected Class pageSecurityConstraintClass;
83      protected Class fragmentSecurityConstraintClass;
84      protected Class linkSecurityConstraintClass;
85      protected Class pageSecuritySecurityConstraintClass;
86      protected Class securityConstraintsDefClass;
87      protected Class fragmentPreferenceClass;
88  
89      private boolean permissionsEnabled;
90  
91      private boolean constraintsEnabled;
92  
93      private List listeners = new LinkedList();
94  
95      public AbstractPageManager(boolean permissionsEnabled, boolean constraintsEnabled)
96      {    
97          this.permissionsEnabled = permissionsEnabled;
98          this.constraintsEnabled = constraintsEnabled;
99      }
100     
101     public AbstractPageManager(boolean permissionsEnabled, boolean constraintsEnabled, Map modelClasses)
102     {
103         this(permissionsEnabled, constraintsEnabled);     
104 
105         this.fragmentClass = (Class)modelClasses.get("FragmentImpl");
106         this.pageClass = (Class)modelClasses.get("PageImpl");
107         this.folderClass = (Class)modelClasses.get("FolderImpl");
108         this.linkClass = (Class)modelClasses.get("LinkImpl");
109         this.pageSecurityClass = (Class)modelClasses.get("PageSecurityImpl");
110         this.folderMenuDefinitionClass = (Class)modelClasses.get("FolderMenuDefinitionImpl");
111         this.folderMenuExcludeDefinitionClass = (Class)modelClasses.get("FolderMenuExcludeDefinitionImpl");
112         this.folderMenuIncludeDefinitionClass = (Class)modelClasses.get("FolderMenuIncludeDefinitionImpl");
113         this.folderMenuOptionsDefinitionClass = (Class)modelClasses.get("FolderMenuOptionsDefinitionImpl");
114         this.folderMenuSeparatorDefinitionClass = (Class)modelClasses.get("FolderMenuSeparatorDefinitionImpl");
115         this.pageMenuDefinitionClass = (Class)modelClasses.get("PageMenuDefinitionImpl");
116         this.pageMenuExcludeDefinitionClass = (Class)modelClasses.get("PageMenuExcludeDefinitionImpl");
117         this.pageMenuIncludeDefinitionClass = (Class)modelClasses.get("PageMenuIncludeDefinitionImpl");
118         this.pageMenuOptionsDefinitionClass = (Class)modelClasses.get("PageMenuOptionsDefinitionImpl");
119         this.pageMenuSeparatorDefinitionClass = (Class)modelClasses.get("PageMenuSeparatorDefinitionImpl");
120         this.securityConstraintsClass = (Class)modelClasses.get("SecurityConstraintsImpl");
121         this.folderSecurityConstraintClass = (Class)modelClasses.get("FolderSecurityConstraintImpl");
122         this.pageSecurityConstraintClass = (Class)modelClasses.get("PageSecurityConstraintImpl");
123         this.fragmentSecurityConstraintClass = (Class)modelClasses.get("FragmentSecurityConstraintImpl");
124         this.linkSecurityConstraintClass = (Class)modelClasses.get("LinkSecurityConstraintImpl");
125         this.pageSecuritySecurityConstraintClass = (Class)modelClasses.get("PageSecuritySecurityConstraintImpl");
126         this.securityConstraintsDefClass = (Class)modelClasses.get("SecurityConstraintsDefImpl");
127         this.fragmentPreferenceClass = (Class)modelClasses.get("FragmentPreferenceImpl");
128     }
129     
130     /***
131      * <p>
132      * getPermissionsEnabled
133      * </p>
134      *
135      * @see org.apache.jetspeed.page.PageManager#getPermissionsEnabled()
136      * @return
137      */
138     public boolean getPermissionsEnabled()
139     {
140         return permissionsEnabled;
141     }
142 
143     /***
144      * <p>
145      * getConstraintsEnabled
146      * </p>
147      *
148      * @see org.apache.jetspeed.page.PageManager#getConstraintsEnabled()
149      * @return
150      */
151     public boolean getConstraintsEnabled()
152     {
153         return constraintsEnabled;
154     }
155 
156     /* (non-Javadoc)
157      * @see org.apache.jetspeed.page.PageManager#newPage(java.lang.String)
158      */
159     public Page newPage(String path)
160     {
161         Page page = null;
162         try
163         {
164             // factory create the page and set id/path
165             page = (Page)createObject(this.pageClass);            
166             if (!path.startsWith(Folder.PATH_SEPARATOR))
167             {
168                 path = Folder.PATH_SEPARATOR + path;
169             }
170             if (!path.endsWith(Page.DOCUMENT_TYPE))
171             {
172                 path += Page.DOCUMENT_TYPE;
173             }
174             page.setPath(path);
175             
176             // create the default fragment
177             page.setRootFragment(newFragment());            
178         }
179         catch (ClassCastException e)
180         {
181             String message = "Failed to create page object for " + this.pageClass;
182             log.error(message, e);
183         }
184         return page;        
185     }
186     
187     /* (non-Javadoc)
188      * @see org.apache.jetspeed.page.PageManager#newFolder(java.lang.String)
189      */
190     public Folder newFolder(String path)
191     {
192         Folder folder = null;
193         try
194         {
195             // factory create the folder and set id/path
196             folder = (Folder)createObject(this.folderClass);            
197             if (!path.startsWith(Folder.PATH_SEPARATOR))
198             {
199                 path = Folder.PATH_SEPARATOR + path;
200             }
201             folder.setPath(path);
202         }
203         catch (ClassCastException e)
204         {
205             String message = "Failed to create link object for " + this.linkClass;
206             log.error(message, e);
207         }
208         return folder;        
209     }
210     
211     /* (non-Javadoc)
212      * @see org.apache.jetspeed.page.PageManager#newLink(java.lang.String)
213      */
214     public Link newLink(String path)
215     {
216         Link link = null;
217         try
218         {
219             // factory create the page and set id/path
220             link = (Link)createObject(this.linkClass);            
221             if (!path.startsWith(Folder.PATH_SEPARATOR))
222             {
223                 path = Folder.PATH_SEPARATOR + path;
224             }
225             if (!path.endsWith(Link.DOCUMENT_TYPE))
226             {
227                 path += Link.DOCUMENT_TYPE;
228             }
229             link.setPath(path);
230         }
231         catch (ClassCastException e)
232         {
233             String message = "Failed to create link object for " + this.linkClass;
234             log.error(message, e);
235         }
236         return link;        
237     }
238     
239     /* (non-Javadoc)
240      * @see org.apache.jetspeed.page.PageManager#newPageSecurity()
241      */
242     public PageSecurity newPageSecurity()
243     {
244         PageSecurity pageSecurity = null;
245         try
246         {
247             // factory create the document and set id/path
248             pageSecurity = (PageSecurity)createObject(this.pageSecurityClass);            
249             pageSecurity.setPath(Folder.PATH_SEPARATOR + PageSecurity.DOCUMENT_TYPE);
250         }
251         catch (ClassCastException e)
252         {
253             String message = "Failed to create page security object for " + this.pageClass;
254             log.error(message, e);
255         }
256         return pageSecurity;        
257     }
258     
259     /* (non-Javadoc)
260      * @see org.apache.jetspeed.page.PageManager#newFragment()
261      */
262     public Fragment newFragment()
263     {
264         Fragment fragment = null;
265         try
266         {
267             fragment = (Fragment)createObject(this.fragmentClass);
268             fragment.setType(Fragment.LAYOUT);          
269         }
270         catch (ClassCastException e)
271         {
272             String message = "Failed to create page object for " + this.pageClass;
273             log.error(message, e);
274             // throw new NodeException(message, e);
275         }
276         return fragment;        
277     }
278 
279     /* (non-Javadoc)
280      * @see org.apache.jetspeed.page.PageManager#newPortletFragment()
281      */
282     public Fragment newPortletFragment()
283     {
284         Fragment fragment = null;
285         try
286         {
287             fragment = (Fragment)createObject(this.fragmentClass);
288             fragment.setType(Fragment.PORTLET);          
289         }
290         catch (ClassCastException e)
291         {
292             String message = "Failed to create page object for " + this.pageClass;
293             log.error(message, e);
294             // throw new NodeException(message, e);
295         }
296         return fragment;        
297     }
298     
299     /***
300      * newFolderMenuDefinition - creates a new empty menu definition
301      *
302      * @return a newly created MenuDefinition object
303      */
304     public MenuDefinition newFolderMenuDefinition()
305     {
306         try
307         {
308             return (MenuDefinition)createObject(this.folderMenuDefinitionClass);
309         }
310         catch (ClassCastException e)
311         {
312             String message = "Failed to create menu definition object for " + this.folderMenuDefinitionClass;
313             log.error(message, e);
314         }
315         return null;
316     }
317 
318     /***
319      * newFolderMenuExcludeDefinition - creates a new empty menu exclude definition
320      *
321      * @return a newly created MenuExcludeDefinition object
322      */
323     public MenuExcludeDefinition newFolderMenuExcludeDefinition()
324     {
325         try
326         {
327             return (MenuExcludeDefinition)createObject(this.folderMenuExcludeDefinitionClass);
328         }
329         catch (ClassCastException e)
330         {
331             String message = "Failed to create menu exclude definition object for " + this.folderMenuExcludeDefinitionClass;
332             log.error(message, e);
333         }
334         return null;
335     }
336 
337     /***
338      * newFolderMenuIncludeDefinition - creates a new empty menu include definition
339      *
340      * @return a newly created MenuIncludeDefinition object
341      */
342     public MenuIncludeDefinition newFolderMenuIncludeDefinition()
343     {
344         try
345         {
346             return (MenuIncludeDefinition)createObject(this.folderMenuIncludeDefinitionClass);
347         }
348         catch (ClassCastException e)
349         {
350             String message = "Failed to create menu include definition object for " + this.folderMenuIncludeDefinitionClass;
351             log.error(message, e);
352         }
353         return null;
354     }
355 
356     /***
357      * newFolderMenuOptionsDefinition - creates a new empty menu options definition
358      *
359      * @return a newly created MenuOptionsDefinition object
360      */
361     public MenuOptionsDefinition newFolderMenuOptionsDefinition()
362     {
363         try
364         {
365             return (MenuOptionsDefinition)createObject(this.folderMenuOptionsDefinitionClass);
366         }
367         catch (ClassCastException e)
368         {
369             String message = "Failed to create menu options definition object for " + this.folderMenuOptionsDefinitionClass;
370             log.error(message, e);
371         }
372         return null;
373     }
374 
375     /***
376      * newFolderMenuSeparatorDefinition - creates a new empty menu separator definition
377      *
378      * @return a newly created MenuSeparatorDefinition object
379      */
380     public MenuSeparatorDefinition newFolderMenuSeparatorDefinition()
381     {
382         try
383         {
384             return (MenuSeparatorDefinition)createObject(this.folderMenuSeparatorDefinitionClass);
385         }
386         catch (ClassCastException e)
387         {
388             String message = "Failed to create menu separator definition object for " + this.folderMenuSeparatorDefinitionClass;
389             log.error(message, e);
390         }
391         return null;
392     }
393 
394     /***
395      * newPageMenuDefinition - creates a new empty menu definition
396      *
397      * @return a newly created MenuDefinition object
398      */
399     public MenuDefinition newPageMenuDefinition()
400     {
401         try
402         {
403             return (MenuDefinition)createObject(this.pageMenuDefinitionClass);
404         }
405         catch (ClassCastException e)
406         {
407             String message = "Failed to create menu definition object for " + this.pageMenuDefinitionClass;
408             log.error(message, e);
409         }
410         return null;
411     }
412 
413     /***
414      * newPageMenuExcludeDefinition - creates a new empty menu exclude definition
415      *
416      * @return a newly created MenuExcludeDefinition object
417      */
418     public MenuExcludeDefinition newPageMenuExcludeDefinition()
419     {
420         try
421         {
422             return (MenuExcludeDefinition)createObject(this.pageMenuExcludeDefinitionClass);
423         }
424         catch (ClassCastException e)
425         {
426             String message = "Failed to create menu exclude definition object for " + this.pageMenuExcludeDefinitionClass;
427             log.error(message, e);
428         }
429         return null;
430     }
431 
432     /***
433      * newPageMenuIncludeDefinition - creates a new empty menu include definition
434      *
435      * @return a newly created MenuIncludeDefinition object
436      */
437     public MenuIncludeDefinition newPageMenuIncludeDefinition()
438     {
439         try
440         {
441             return (MenuIncludeDefinition)createObject(this.pageMenuIncludeDefinitionClass);
442         }
443         catch (ClassCastException e)
444         {
445             String message = "Failed to create menu include definition object for " + this.pageMenuIncludeDefinitionClass;
446             log.error(message, e);
447         }
448         return null;
449     }
450 
451     /***
452      * newPageMenuOptionsDefinition - creates a new empty menu options definition
453      *
454      * @return a newly created MenuOptionsDefinition object
455      */
456     public MenuOptionsDefinition newPageMenuOptionsDefinition()
457     {
458         try
459         {
460             return (MenuOptionsDefinition)createObject(this.pageMenuOptionsDefinitionClass);
461         }
462         catch (ClassCastException e)
463         {
464             String message = "Failed to create menu options definition object for " + this.pageMenuOptionsDefinitionClass;
465             log.error(message, e);
466         }
467         return null;
468     }
469 
470     /***
471      * newPageMenuSeparatorDefinition - creates a new empty menu separator definition
472      *
473      * @return a newly created MenuSeparatorDefinition object
474      */
475     public MenuSeparatorDefinition newPageMenuSeparatorDefinition()
476     {
477         try
478         {
479             return (MenuSeparatorDefinition)createObject(this.pageMenuSeparatorDefinitionClass);
480         }
481         catch (ClassCastException e)
482         {
483             String message = "Failed to create menu separator definition object for " + this.pageMenuSeparatorDefinitionClass;
484             log.error(message, e);
485         }
486         return null;
487     }
488 
489     /***
490      * newSecurityConstraints - creates a new empty security constraints definition
491      *
492      * @return a newly created SecurityConstraints object
493      */
494     public SecurityConstraints newSecurityConstraints()
495     {
496         try
497         {
498             return (SecurityConstraints)createObject(this.securityConstraintsClass);
499         }
500         catch (ClassCastException e)
501         {
502             String message = "Failed to create security constraints definition object for " + this.securityConstraintsClass;
503             log.error(message, e);
504         }
505         return null;
506     }
507 
508     /***
509      * newFolderSecurityConstraint - creates a new security constraint definition
510      *
511      * @return a newly created SecurityConstraint object
512      */
513     public SecurityConstraint newFolderSecurityConstraint()
514     {
515         try
516         {
517             return (SecurityConstraint)createObject(this.folderSecurityConstraintClass);
518         }
519         catch (ClassCastException e)
520         {
521             String message = "Failed to create security constraint definition object for " + this.folderSecurityConstraintClass;
522             log.error(message, e);
523         }
524         return null;
525     }
526 
527     /***
528      * newPageSecurityConstraint - creates a new security constraint definition
529      *
530      * @return a newly created SecurityConstraint object
531      */
532     public SecurityConstraint newPageSecurityConstraint()
533     {
534         try
535         {
536             return (SecurityConstraint)createObject(this.pageSecurityConstraintClass);
537         }
538         catch (ClassCastException e)
539         {
540             String message = "Failed to create security constraint definition object for " + this.pageSecurityConstraintClass;
541             log.error(message, e);
542         }
543         return null;
544     }
545 
546     /***
547      * newFragmentSecurityConstraint - creates a new security constraint definition
548      *
549      * @return a newly created SecurityConstraint object
550      */
551     public SecurityConstraint newFragmentSecurityConstraint()
552     {
553         try
554         {
555             return (SecurityConstraint)createObject(this.fragmentSecurityConstraintClass);
556         }
557         catch (ClassCastException e)
558         {
559             String message = "Failed to create security constraint definition object for " + this.fragmentSecurityConstraintClass;
560             log.error(message, e);
561         }
562         return null;
563     }
564 
565     /***
566      * newLinkSecurityConstraint - creates a new security constraint definition
567      *
568      * @return a newly created SecurityConstraint object
569      */
570     public SecurityConstraint newLinkSecurityConstraint()
571     {
572         try
573         {
574             return (SecurityConstraint)createObject(this.linkSecurityConstraintClass);
575         }
576         catch (ClassCastException e)
577         {
578             String message = "Failed to create security constraint definition object for " + this.linkSecurityConstraintClass;
579             log.error(message, e);
580         }
581         return null;
582     }
583 
584     /***
585      * newPageSecuritySecurityConstraint - creates a new security constraint definition
586      *
587      * @return a newly created SecurityConstraint object
588      */
589     public SecurityConstraint newPageSecuritySecurityConstraint()
590     {
591         try
592         {
593             return (SecurityConstraint)createObject(this.pageSecuritySecurityConstraintClass);
594         }
595         catch (ClassCastException e)
596         {
597             String message = "Failed to create security constraint definition object for " + this.pageSecuritySecurityConstraintClass;
598             log.error(message, e);
599         }
600         return null;
601     }
602 
603     /***
604      * newSecurityConstraintsDef - creates a new security constraints definition
605      *
606      * @return a newly created SecurityConstraintsDef object
607      */
608     public SecurityConstraintsDef newSecurityConstraintsDef()
609     {
610         try
611         {
612             return (SecurityConstraintsDef)createObject(this.securityConstraintsDefClass);
613         }
614         catch (ClassCastException e)
615         {
616             String message = "Failed to create security constraints definition object for " + this.securityConstraintsDefClass;
617             log.error(message, e);
618         }
619         return null;
620     }
621 
622     /***
623      * newFragmentPreference - creates a new security constraints definition
624      *
625      * @return a newly created FragmentPreference object
626      */
627     public FragmentPreference newFragmentPreference()
628     {
629         try
630         {
631             return (FragmentPreference)createObject(this.fragmentPreferenceClass);
632         }
633         catch (ClassCastException e)
634         {
635             String message = "Failed to create security constraints definition object for " + this.fragmentPreferenceClass;
636             log.error(message, e);
637         }
638         return null;
639     }
640 
641     /***
642      * createObject - creates a new page manager implementation object
643      *
644      * @param classe implementation class
645      * @return a newly created implementation object
646      */
647     private Object createObject(Class classe)
648     {
649         Object object = null;
650         try
651         {
652             object = classe.newInstance();
653         }
654         catch (Exception e)
655         {
656             log.error("Factory failed to create object: " + classe.getName(), e);            
657         }
658         return object;        
659     }    
660 
661     /***
662      * addListener - add page manager event listener
663      *
664      * @param listener page manager event listener
665      */
666     public void addListener(PageManagerEventListener listener)
667     {
668         // add listener to listeners list
669         synchronized (listeners)
670         {
671             listeners.add(listener);
672         }
673     }
674 
675     /***
676      * removeListener - remove page manager event listener
677      *
678      * @param listener page manager event listener
679      */
680     public void removeListener(PageManagerEventListener listener)
681     {
682         // remove listener from listeners list
683         synchronized (listeners)
684         {
685             listeners.remove(listener);
686         }
687     }
688 
689     /* (non-Javadoc)
690      * @see org.apache.jetspeed.page.PageManager#reset()
691      */
692     public void reset()
693     {
694         // nothing to reset by default
695     }
696 
697     /***
698      * notifyNewNode - notify page manager event listeners of
699      *                 new node event
700      *
701      * @param node new managed node if known
702      */
703     public void notifyNewNode(Node node)
704     {
705         // copy listeners list to reduce synchronization deadlock
706         List listenersList = null;
707         synchronized (listeners)
708         {
709             listenersList = new ArrayList(listeners);
710         }
711         // notify listeners
712         Iterator listenersIter = listenersList.iterator();
713         while (listenersIter.hasNext())
714         {
715             PageManagerEventListener listener = (PageManagerEventListener)listenersIter.next();
716             try
717             {
718                 listener.newNode(node);
719             }
720             catch (Exception e)
721             {
722                 log.error("Failed to notify page manager event listener", e);
723             }
724         }
725     }
726 
727     /***
728      * notifyUpdatedNode - notify page manager event listeners of
729      *                     updated node event
730      *
731      * @param node updated managed node if known
732      */
733     public void notifyUpdatedNode(Node node)
734     {
735         // copy listeners list to reduce synchronization deadlock
736         List listenersList = null;
737         synchronized (listeners)
738         {
739             listenersList = new ArrayList(listeners);
740         }
741         // notify listeners
742         Iterator listenersIter = listenersList.iterator();
743         while (listenersIter.hasNext())
744         {
745             PageManagerEventListener listener = (PageManagerEventListener)listenersIter.next();
746             try
747             {
748                 listener.updatedNode(node);
749             }
750             catch (Exception e)
751             {
752                 log.error("Failed to notify page manager event listener", e);
753             }
754         }
755     }
756 
757     /***
758      * notifyRemovedNode - notify page manager event listeners of
759      *                     removed node event
760      *
761      * @param node removed managed node if known
762      */
763     public void notifyRemovedNode(Node node)
764     {
765         // copy listeners list to reduce synchronization deadlock
766         List listenersList = null;
767         synchronized (listeners)
768         {
769             listenersList = new ArrayList(listeners);
770         }
771         // notify listeners
772         Iterator listenersIter = listenersList.iterator();
773         while (listenersIter.hasNext())
774         {
775             PageManagerEventListener listener = (PageManagerEventListener)listenersIter.next();
776             try
777             {
778                 listener.removedNode(node);
779             }
780             catch (Exception e)
781             {
782                 log.error("Failed to notify page manager event listener", e);
783             }
784         }
785     }
786         
787     public Folder copyFolder(Folder source, String path)
788     throws NodeException
789     {
790         // create the new folder and copy attributes
791         Folder folder = newFolder(path);
792         folder.setDefaultPage(source.getDefaultPage()); 
793         folder.setShortTitle(source.getShortTitle());
794         folder.setTitle(source.getTitle());
795         folder.setHidden(source.isHidden());
796         folder.setDefaultDecorator(source.getDefaultDecorator(Fragment.LAYOUT), Fragment.LAYOUT);
797         folder.setDefaultDecorator(source.getDefaultDecorator(Fragment.PORTLET), Fragment.PORTLET);
798         folder.setSkin(source.getSkin());
799 
800         // copy locale specific metadata
801         folder.getMetadata().copyFields(source.getMetadata().getFields());
802         
803         // copy security constraints
804         SecurityConstraints srcSecurity = source.getSecurityConstraints();        
805         if ((srcSecurity != null) && !srcSecurity.isEmpty())
806         {
807             SecurityConstraints copiedSecurity = copySecurityConstraints(FOLDER_NODE_TYPE, srcSecurity);
808             folder.setSecurityConstraints(copiedSecurity);
809         }    
810         
811         // copy document orders
812         folder.setDocumentOrder(DatabasePageManagerUtils.createList());
813         Iterator documentOrders = source.getDocumentOrder().iterator();
814         while (documentOrders.hasNext())
815         {
816             String name = (String)documentOrders.next();
817             folder.getDocumentOrder().add(name);
818         }
819 
820         // copy menu definitions
821         List menus = source.getMenuDefinitions();
822         if (menus != null)
823         {
824             List copiedMenus = copyMenuDefinitions(FOLDER_NODE_TYPE, menus);
825             folder.setMenuDefinitions(copiedMenus);
826         }        
827                 
828         return folder;
829     }
830     
831     public Page copyPage(Page source, String path)
832     throws NodeException
833     {
834         // create the new page and copy attributes
835         Page page = newPage(path);
836         page.setTitle(source.getTitle());
837         page.setShortTitle(source.getShortTitle());
838         page.setVersion(source.getVersion());
839         page.setDefaultDecorator(source.getDefaultDecorator(Fragment.LAYOUT), Fragment.LAYOUT);
840         page.setDefaultDecorator(source.getDefaultDecorator(Fragment.PORTLET), Fragment.PORTLET);
841         page.setSkin(source.getSkin());
842         page.setHidden(source.isHidden());
843         
844         // copy locale specific metadata
845         page.getMetadata().copyFields(source.getMetadata().getFields());
846         
847         // copy security constraints
848         SecurityConstraints srcSecurity = source.getSecurityConstraints();        
849         if ((srcSecurity != null) && !srcSecurity.isEmpty())
850         {
851             SecurityConstraints copiedSecurity = copySecurityConstraints(PAGE_NODE_TYPE, srcSecurity);
852             page.setSecurityConstraints(copiedSecurity);
853         }    
854 
855         // copy menu definitions
856         List menus = source.getMenuDefinitions();
857         if (menus != null)
858         {
859             List copiedMenus = copyMenuDefinitions(PAGE_NODE_TYPE, menus);
860             page.setMenuDefinitions(copiedMenus);
861         }        
862         
863         // copy fragments
864         Fragment root = copyFragment(source.getRootFragment(), source.getRootFragment().getName());
865         page.setRootFragment(root);
866         
867         return page;
868     }
869 
870     public Fragment copyFragment(Fragment source, String name)
871     throws NodeException
872     {
873         // create the new fragment and copy attributes
874         Fragment copy = newFragment();
875         copy.setDecorator(source.getDecorator());
876         copy.setName(name);
877         copy.setShortTitle(source.getShortTitle());
878         copy.setSkin(source.getSkin());
879         copy.setTitle(source.getTitle());
880         copy.setType(source.getType());
881         copy.setState(source.getState());
882 
883         // copy security constraints
884         SecurityConstraints srcSecurity = source.getSecurityConstraints();        
885         if ((srcSecurity != null) && !srcSecurity.isEmpty())
886         {
887             SecurityConstraints copiedSecurity = copySecurityConstraints(FRAGMENT_NODE_TYPE, srcSecurity);
888             copy.setSecurityConstraints(copiedSecurity);
889         }    
890         
891         // copy properties
892         Iterator props = source.getProperties().entrySet().iterator();
893         while (props.hasNext())
894         {
895             Map.Entry prop = (Map.Entry)props.next();
896             copy.getProperties().put(prop.getKey(), prop.getValue());
897         }
898                   
899         // copy preferences
900         copy.setPreferences(DatabasePageManagerUtils.createList());
901         Iterator prefs = source.getPreferences().iterator();
902         while (prefs.hasNext())
903         {
904             FragmentPreference pref = (FragmentPreference)prefs.next();
905             FragmentPreference newPref = this.newFragmentPreference();
906             newPref.setName(pref.getName());
907             newPref.setReadOnly(pref.isReadOnly());
908             newPref.setValueList(DatabasePageManagerUtils.createList());
909             Iterator values = pref.getValueList().iterator();            
910             while (values.hasNext())
911             {
912                 String value = (String)values.next();
913                 newPref.getValueList().add(value);
914             }
915             copy.getPreferences().add(newPref);
916         }
917 
918         // recursively copy fragments
919         Iterator fragments = source.getFragments().iterator();
920         while (fragments.hasNext())
921         {
922             Fragment fragment = (Fragment)fragments.next();
923             Fragment copiedFragment = copyFragment(fragment, fragment.getName());
924             copy.getFragments().add(copiedFragment);
925         }
926         return copy;
927     }
928     
929     public Link copyLink(Link source, String path)
930     throws NodeException
931     {
932         // create the new link and copy attributes
933         Link link = newLink(path);
934         link.setTitle(source.getTitle());
935         link.setShortTitle(source.getShortTitle());
936         link.setSkin(source.getSkin());
937         link.setVersion(source.getVersion());
938         link.setTarget(source.getTarget());
939         link.setUrl(source.getUrl());
940         link.setHidden(source.isHidden());
941         
942         // copy locale specific metadata
943         link.getMetadata().copyFields(source.getMetadata().getFields());
944         
945         // copy security constraints
946         SecurityConstraints srcSecurity = source.getSecurityConstraints();        
947         if ((srcSecurity != null) && !srcSecurity.isEmpty())
948         {
949             SecurityConstraints copiedSecurity = copySecurityConstraints(LINK_NODE_TYPE, srcSecurity);
950             link.setSecurityConstraints(copiedSecurity);
951         }    
952 
953         return link;
954     }
955 
956     public PageSecurity copyPageSecurity(PageSecurity source) 
957     throws NodeException
958     {
959         // create the new page security document and copy attributes
960         PageSecurity copy = this.newPageSecurity();
961         copy.setPath(source.getPath());
962         copy.setVersion(source.getVersion());        
963 
964         // copy security constraint defintions
965         copy.setSecurityConstraintsDefs(DatabasePageManagerUtils.createList());                
966         Iterator defs = source.getSecurityConstraintsDefs().iterator();
967         while (defs.hasNext())
968         {
969             SecurityConstraintsDef def = (SecurityConstraintsDef)defs.next();
970             SecurityConstraintsDef defCopy = this.newSecurityConstraintsDef();            
971             defCopy.setName(def.getName());
972             List copiedConstraints = DatabasePageManagerUtils.createList();
973             Iterator constraints = def.getSecurityConstraints().iterator();
974             while (constraints.hasNext())
975             {
976                 SecurityConstraint srcConstraint = (SecurityConstraint)constraints.next();
977                 SecurityConstraint dstConstraint = newPageSecuritySecurityConstraint();
978                 copyConstraint(srcConstraint, dstConstraint);
979                 copiedConstraints.add(dstConstraint);
980             }                                            
981             defCopy.setSecurityConstraints(copiedConstraints);
982             copy.getSecurityConstraintsDefs().add(defCopy);
983         }
984         
985         // copy global security constraint references
986         copy.setGlobalSecurityConstraintsRefs(DatabasePageManagerUtils.createList());
987         Iterator globals = source.getGlobalSecurityConstraintsRefs().iterator();
988         while (globals.hasNext())
989         {
990             String global = (String)globals.next();
991             copy.getGlobalSecurityConstraintsRefs().add(global);
992         }
993         
994         return copy;
995     }
996 
997     protected List copyMenuDefinitions(String type, List srcMenus)
998     {
999         List copiedMenus = DatabasePageManagerUtils.createList(); 
1000         Iterator menus = srcMenus.iterator();
1001         while (menus.hasNext())
1002         {
1003             MenuDefinition srcMenu = (MenuDefinition)menus.next();
1004             MenuDefinition copiedMenu = (MenuDefinition)copyMenuElement(type, srcMenu);
1005             if (copiedMenu != null)
1006             {
1007                 copiedMenus.add(copiedMenu);
1008             }
1009         }
1010         return copiedMenus;
1011     }
1012     
1013     protected Object copyMenuElement(String type, Object srcElement)
1014     {
1015         if (srcElement instanceof MenuDefinition)
1016         {
1017             // create the new menu element and copy attributes
1018             MenuDefinition source = (MenuDefinition)srcElement;
1019             MenuDefinition menu = null;
1020             if (type.equals(PAGE_NODE_TYPE))
1021             {
1022                 menu = newPageMenuDefinition();
1023             }
1024             else if (type.equals(FOLDER_NODE_TYPE))
1025             {
1026                 menu = newFolderMenuDefinition();
1027             }
1028             menu.setDepth(source.getDepth());
1029             menu.setName(source.getName());
1030             menu.setOptions(source.getOptions());
1031             menu.setOrder(source.getOrder());
1032             menu.setPaths(source.isPaths());
1033             menu.setProfile(source.getProfile());
1034             menu.setRegexp(source.isRegexp());
1035             menu.setShortTitle(source.getShortTitle());
1036             menu.setSkin(source.getSkin());
1037             menu.setTitle(source.getTitle());
1038 
1039             // copy locale specific metadata
1040             menu.getMetadata().copyFields(source.getMetadata().getFields());
1041         
1042             // recursively copy menu elements
1043             List elements = source.getMenuElements();
1044             if (elements != null)
1045             {
1046                 List copiedElements = DatabasePageManagerUtils.createList(); 
1047                 Iterator elementsIter = elements.iterator();
1048                 while (elementsIter.hasNext())
1049                 {
1050                     Object element = elementsIter.next();
1051                     Object copiedElement = copyMenuElement(type, element);
1052                     if (copiedElement != null)
1053                     {
1054                         copiedElements.add(copiedElement);
1055                     }
1056                 }
1057                 menu.setMenuElements(copiedElements);
1058             }
1059 
1060             return menu;
1061         }
1062         else if (srcElement instanceof MenuExcludeDefinition)
1063         {
1064             // create the new menu exclude element and copy attributes
1065             MenuExcludeDefinition source = (MenuExcludeDefinition)srcElement;
1066             MenuExcludeDefinition menuExclude = null;
1067             if (type.equals(PAGE_NODE_TYPE))
1068             {
1069                 menuExclude = newPageMenuExcludeDefinition();
1070             }
1071             else if (type.equals(FOLDER_NODE_TYPE))
1072             {
1073                 menuExclude = newFolderMenuExcludeDefinition();
1074             }
1075             menuExclude.setName(source.getName());
1076             return menuExclude;
1077         }
1078         else if (srcElement instanceof MenuIncludeDefinition)
1079         {
1080             // create the new menu include element and copy attributes
1081             MenuIncludeDefinition source = (MenuIncludeDefinition)srcElement;
1082             MenuIncludeDefinition menuInclude = null;
1083             if (type.equals(PAGE_NODE_TYPE))
1084             {
1085                 menuInclude = newPageMenuIncludeDefinition();
1086             }
1087             else if (type.equals(FOLDER_NODE_TYPE))
1088             {
1089                 menuInclude = newFolderMenuIncludeDefinition();
1090             }
1091             menuInclude.setName(source.getName());
1092             menuInclude.setNest(source.isNest());
1093             return menuInclude;
1094         }
1095         else if (srcElement instanceof MenuOptionsDefinition)
1096         {
1097             // create the new menu options element and copy attributes
1098             MenuOptionsDefinition source = (MenuOptionsDefinition)srcElement;
1099             MenuOptionsDefinition menuOptions = null;
1100             if (type.equals(PAGE_NODE_TYPE))
1101             {
1102                 menuOptions = newPageMenuOptionsDefinition();
1103             }
1104             else if (type.equals(FOLDER_NODE_TYPE))
1105             {
1106                 menuOptions = newFolderMenuOptionsDefinition();
1107             }
1108             menuOptions.setDepth(source.getDepth());
1109             menuOptions.setOptions(source.getOptions());
1110             menuOptions.setOrder(source.getOrder());
1111             menuOptions.setPaths(source.isPaths());
1112             menuOptions.setProfile(source.getProfile());
1113             menuOptions.setRegexp(source.isRegexp());
1114             menuOptions.setSkin(source.getSkin());
1115             return menuOptions;
1116         }
1117         else if (srcElement instanceof MenuSeparatorDefinition)
1118         {
1119             // create the new menu separator element and copy attributes
1120             MenuSeparatorDefinition source = (MenuSeparatorDefinition)srcElement;
1121             MenuSeparatorDefinition menuSeparator = null;
1122             if (type.equals(PAGE_NODE_TYPE))
1123             {
1124                 menuSeparator = newPageMenuSeparatorDefinition();
1125             }
1126             else if (type.equals(FOLDER_NODE_TYPE))
1127             {
1128                 menuSeparator = newFolderMenuSeparatorDefinition();
1129             }
1130             menuSeparator.setSkin(source.getSkin());
1131             menuSeparator.setTitle(source.getTitle());
1132             menuSeparator.setText(source.getText());
1133 
1134             // copy locale specific metadata
1135             menuSeparator.getMetadata().copyFields(source.getMetadata().getFields());
1136         
1137             return menuSeparator;
1138         }
1139         return null;
1140     }
1141 
1142     protected void copyConstraint(SecurityConstraint srcConstraint, SecurityConstraint dstConstraint)
1143     {
1144         dstConstraint.setUsers(srcConstraint.getUsers());                
1145         dstConstraint.setRoles(srcConstraint.getRoles());
1146         dstConstraint.setGroups(srcConstraint.getGroups());
1147         dstConstraint.setPermissions(srcConstraint.getPermissions());        
1148     }
1149     
1150     protected SecurityConstraints copySecurityConstraints(String type, SecurityConstraints source)
1151     {
1152         SecurityConstraints security = newSecurityConstraints();
1153         if (source.getOwner() != null)        
1154         {
1155             security.setOwner(source.getOwner());
1156         }
1157         if (source.getSecurityConstraints() != null)
1158         {
1159             List copiedConstraints = DatabasePageManagerUtils.createList();
1160             Iterator constraints = source.getSecurityConstraints().iterator();
1161             while (constraints.hasNext())
1162             {
1163                 SecurityConstraint srcConstraint = (SecurityConstraint)constraints.next();
1164                 SecurityConstraint dstConstraint = null;
1165                 if (type.equals(PAGE_NODE_TYPE))
1166                 {
1167                     dstConstraint = newPageSecurityConstraint();
1168                 }
1169                 else if (type.equals(FOLDER_NODE_TYPE))
1170                 {
1171                     dstConstraint = newFolderSecurityConstraint();
1172                 }
1173                 else if (type.equals(LINK_NODE_TYPE))
1174                 {
1175                     dstConstraint = newLinkSecurityConstraint();
1176                 }
1177                 else if (type.equals(FRAGMENT_NODE_TYPE))
1178                 {
1179                     dstConstraint = newFragmentSecurityConstraint();
1180                 }
1181                 copyConstraint(srcConstraint, dstConstraint);
1182                 copiedConstraints.add(dstConstraint);
1183             }
1184             security.setSecurityConstraints(copiedConstraints);
1185         }
1186         if (source.getSecurityConstraintsRefs() != null)
1187         {
1188             List copiedRefs = DatabasePageManagerUtils.createList();
1189             Iterator refs = source.getSecurityConstraintsRefs().iterator();
1190             while (refs.hasNext())
1191             {                
1192                 String constraintsRef = (String)refs.next();                
1193                 copiedRefs.add(constraintsRef);
1194             }
1195             security.setSecurityConstraintsRefs(copiedRefs);            
1196         }
1197         return security;
1198     }
1199     
1200     /***
1201      * Deep copy a folder
1202      *  
1203      * @param source source folder
1204      * @param dest destination folder
1205      */
1206     public void deepCopyFolder(Folder srcFolder, String destinationPath, String owner)
1207     throws NodeException
1208     {
1209         PageManagerUtils.deepCopyFolder(this, srcFolder, destinationPath, owner);
1210     }
1211             
1212     public Page getUserPage(String userName, String pageName)
1213     throws PageNotFoundException, NodeException
1214     {
1215         return this.getPage(Folder.USER_FOLDER + userName + Folder.PATH_SEPARATOR + pageName);
1216     }
1217     
1218     public Folder getUserFolder(String userName) 
1219         throws FolderNotFoundException, InvalidFolderException, NodeException
1220     {
1221         return this.getFolder(Folder.USER_FOLDER + userName);        
1222     }
1223 
1224     public boolean folderExists(String folderName)
1225     {
1226         try
1227         {
1228             getFolder(folderName);
1229         }
1230         catch (Exception e)
1231         {
1232             return false;
1233         }
1234         return true;
1235     }
1236     public boolean pageExists(String pageName)
1237     {
1238         try
1239         {
1240             getPage(pageName);
1241         }
1242         catch (Exception e)
1243         {
1244             return false;
1245         }
1246         return true;
1247     }
1248     
1249     public boolean linkExists(String linkName)
1250     {
1251         try
1252         {
1253             getLink(linkName);
1254         }
1255         catch (Exception e)
1256         {
1257             return false;
1258         }
1259         return true;
1260     }
1261 
1262     public boolean userFolderExists(String userName)
1263     {
1264         try
1265         {
1266             getFolder(Folder.USER_FOLDER + userName);
1267         }
1268         catch (Exception e)
1269         {
1270             return false;
1271         }
1272         return true;
1273     }
1274     
1275     public boolean userPageExists(String userName, String pageName)
1276     {
1277         try
1278         {
1279             getPage(Folder.USER_FOLDER + userName + Folder.PATH_SEPARATOR + pageName);
1280         }
1281         catch (Exception e)
1282         {
1283             return false;
1284         }
1285         return true;
1286     }
1287     
1288     /***
1289      * Creates a user's home page from the roles of the current user.
1290      * The use case: when a portal is setup to use shared pages, but then
1291      * the user attempts to customize. At this point, we create the new page(s) for the user.
1292      * 
1293      * @param subject
1294      */
1295     public void createUserHomePagesFromRoles(Subject subject)
1296     throws NodeException
1297     {
1298         PageManagerUtils.createUserHomePagesFromRoles(this, subject);
1299     }
1300 
1301 }