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.impl;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.security.auth.Subject;
26  
27  import org.apache.jetspeed.JetspeedActions;
28  import org.apache.jetspeed.components.dao.InitablePersistenceBrokerDaoSupport;
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.folder.impl.FolderImpl;
40  import org.apache.jetspeed.om.folder.impl.FolderMenuDefinitionImpl;
41  import org.apache.jetspeed.om.folder.impl.FolderMenuExcludeDefinitionImpl;
42  import org.apache.jetspeed.om.folder.impl.FolderMenuIncludeDefinitionImpl;
43  import org.apache.jetspeed.om.folder.impl.FolderMenuOptionsDefinitionImpl;
44  import org.apache.jetspeed.om.folder.impl.FolderMenuSeparatorDefinitionImpl;
45  import org.apache.jetspeed.om.folder.impl.FolderSecurityConstraintImpl;
46  import org.apache.jetspeed.om.page.ContentPage;
47  import org.apache.jetspeed.om.page.ContentPageImpl;
48  import org.apache.jetspeed.om.page.Fragment;
49  import org.apache.jetspeed.om.page.Link;
50  import org.apache.jetspeed.om.page.Page;
51  import org.apache.jetspeed.om.page.PageSecurity;
52  import org.apache.jetspeed.om.page.SecurityConstraintsDef;
53  import org.apache.jetspeed.om.page.impl.FragmentImpl;
54  import org.apache.jetspeed.om.page.impl.FragmentPreferenceImpl;
55  import org.apache.jetspeed.om.page.impl.FragmentSecurityConstraintImpl;
56  import org.apache.jetspeed.om.page.impl.LinkImpl;
57  import org.apache.jetspeed.om.page.impl.LinkSecurityConstraintImpl;
58  import org.apache.jetspeed.om.page.impl.PageImpl;
59  import org.apache.jetspeed.om.page.impl.PageMenuDefinitionImpl;
60  import org.apache.jetspeed.om.page.impl.PageMenuExcludeDefinitionImpl;
61  import org.apache.jetspeed.om.page.impl.PageMenuIncludeDefinitionImpl;
62  import org.apache.jetspeed.om.page.impl.PageMenuOptionsDefinitionImpl;
63  import org.apache.jetspeed.om.page.impl.PageMenuSeparatorDefinitionImpl;
64  import org.apache.jetspeed.om.page.impl.PageSecurityConstraintImpl;
65  import org.apache.jetspeed.om.page.impl.PageSecurityImpl;
66  import org.apache.jetspeed.om.page.impl.PageSecuritySecurityConstraintImpl;
67  import org.apache.jetspeed.om.page.impl.SecurityConstraintsDefImpl;
68  import org.apache.jetspeed.om.page.impl.SecurityConstraintsImpl;
69  import org.apache.jetspeed.om.preference.FragmentPreference;
70  import org.apache.jetspeed.page.DelegatingPageManager;
71  import org.apache.jetspeed.page.FolderNotRemovedException;
72  import org.apache.jetspeed.page.FolderNotUpdatedException;
73  import org.apache.jetspeed.page.LinkNotRemovedException;
74  import org.apache.jetspeed.page.LinkNotUpdatedException;
75  import org.apache.jetspeed.page.PageManager;
76  import org.apache.jetspeed.page.PageManagerEventListener;
77  import org.apache.jetspeed.page.PageManagerSecurityUtils;
78  import org.apache.jetspeed.page.PageManagerUtils;
79  import org.apache.jetspeed.page.PageNotFoundException;
80  import org.apache.jetspeed.page.PageNotRemovedException;
81  import org.apache.jetspeed.page.PageNotUpdatedException;
82  import org.apache.jetspeed.page.document.DocumentException;
83  import org.apache.jetspeed.page.document.DocumentNotFoundException;
84  import org.apache.jetspeed.page.document.FailedToDeleteDocumentException;
85  import org.apache.jetspeed.page.document.FailedToUpdateDocumentException;
86  import org.apache.jetspeed.page.document.NodeException;
87  import org.apache.jetspeed.page.document.NodeSet;
88  import org.apache.jetspeed.page.document.impl.NodeImpl;
89  import org.apache.ojb.broker.core.proxy.ProxyHelper;
90  import org.apache.ojb.broker.query.Criteria;
91  import org.apache.ojb.broker.query.QueryByCriteria;
92  import org.apache.ojb.broker.query.QueryFactory;
93  
94  /***
95   * DatabasePageManager
96   * 
97   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
98   * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
99   * @version $Id: $
100  */
101 public class DatabasePageManager extends InitablePersistenceBrokerDaoSupport implements PageManager
102 {
103     private static final int DEFAULT_CACHE_SIZE = 128;
104     private static final int MIN_CACHE_EXPIRES_SECONDS = 30;
105     private static final int DEFAULT_CACHE_EXPIRES_SECONDS = 150;
106 
107     private static Map modelClasses = new HashMap();
108     static
109     {
110         modelClasses.put("FragmentImpl", FragmentImpl.class);
111         modelClasses.put("PageImpl", PageImpl.class);
112         modelClasses.put("FolderImpl", FolderImpl.class);
113         modelClasses.put("LinkImpl", LinkImpl.class);
114         modelClasses.put("PageSecurityImpl", PageSecurityImpl.class);
115         modelClasses.put("FolderMenuDefinitionImpl", FolderMenuDefinitionImpl.class);
116         modelClasses.put("FolderMenuExcludeDefinitionImpl", FolderMenuExcludeDefinitionImpl.class);
117         modelClasses.put("FolderMenuIncludeDefinitionImpl", FolderMenuIncludeDefinitionImpl.class);
118         modelClasses.put("FolderMenuOptionsDefinitionImpl", FolderMenuOptionsDefinitionImpl.class);
119         modelClasses.put("FolderMenuSeparatorDefinitionImpl", FolderMenuSeparatorDefinitionImpl.class);
120         modelClasses.put("PageMenuDefinitionImpl", PageMenuDefinitionImpl.class);
121         modelClasses.put("PageMenuExcludeDefinitionImpl", PageMenuExcludeDefinitionImpl.class);
122         modelClasses.put("PageMenuIncludeDefinitionImpl", PageMenuIncludeDefinitionImpl.class);
123         modelClasses.put("PageMenuOptionsDefinitionImpl", PageMenuOptionsDefinitionImpl.class);
124         modelClasses.put("PageMenuSeparatorDefinitionImpl", PageMenuSeparatorDefinitionImpl.class);
125         modelClasses.put("SecurityConstraintsImpl", SecurityConstraintsImpl.class);
126         modelClasses.put("FolderSecurityConstraintImpl", FolderSecurityConstraintImpl.class);
127         modelClasses.put("PageSecurityConstraintImpl", PageSecurityConstraintImpl.class);
128         modelClasses.put("FragmentSecurityConstraintImpl", FragmentSecurityConstraintImpl.class);
129         modelClasses.put("LinkSecurityConstraintImpl", LinkSecurityConstraintImpl.class);
130         modelClasses.put("PageSecuritySecurityConstraintImpl", PageSecuritySecurityConstraintImpl.class);
131         modelClasses.put("SecurityConstraintsDefImpl", SecurityConstraintsDefImpl.class);
132         modelClasses.put("FragmentPreferenceImpl", FragmentPreferenceImpl.class);
133     }
134 
135     private DelegatingPageManager delegator;
136     
137     private int cacheSize;
138 
139     private int cacheExpiresSeconds;
140 
141     private PageManager pageManagerProxy;
142 
143     public DatabasePageManager(String repositoryPath, int cacheSize, int cacheExpiresSeconds, boolean isPermissionsSecurity, boolean isConstraintsSecurity)
144     {
145         super(repositoryPath);
146         delegator = new DelegatingPageManager(isPermissionsSecurity, isConstraintsSecurity, modelClasses);
147         this.cacheSize = Math.max(cacheSize, DEFAULT_CACHE_SIZE);
148         if (cacheExpiresSeconds < 0)
149         {
150             this.cacheExpiresSeconds = DEFAULT_CACHE_EXPIRES_SECONDS;
151         }
152         else if (cacheExpiresSeconds == 0)
153         {
154             this.cacheExpiresSeconds = 0;
155         }
156         else
157         {
158             this.cacheExpiresSeconds = Math.max(cacheExpiresSeconds, MIN_CACHE_EXPIRES_SECONDS);
159         }
160         DatabasePageManagerCache.cacheInit(this);
161     }
162 
163     /***
164      * getCacheSize
165      *
166      * @return configured cache size
167      */
168     public int getCacheSize()
169     {
170         return cacheSize;
171     }
172 
173     /***
174      * getCacheExpiresSeconds
175      *
176      * @return configured cache expiration in seconds
177      */
178     public int getCacheExpiresSeconds()
179     {
180         return cacheExpiresSeconds;
181     }
182 
183     /***
184      * getPageManagerProxy
185      *
186      * @return proxied page manager interface used to
187      *         inject into Folder instances to provide
188      *         transaction/interception
189      */
190     public PageManager getPageManagerProxy()
191     {
192         return pageManagerProxy;
193     }
194 
195     /***
196      * setPageManagerProxy
197      *
198      * @param proxy proxied page manager interface used to
199      *              inject into Folder instances to provide
200      *              transaction/interception
201      */
202     public void setPageManagerProxy(PageManager proxy)
203     {
204         // set/reset page manager proxy and propagate to cache
205         if (pageManagerProxy != proxy)
206         {
207             pageManagerProxy = proxy;
208             DatabasePageManagerCache.setPageManagerProxy(proxy);
209         }
210     }
211 
212     /* (non-Javadoc)
213      * @see org.apache.jetspeed.page.PageManager#getConstraintsEnabled()
214      */
215     public boolean getConstraintsEnabled()
216     {
217         return delegator.getConstraintsEnabled();
218     }
219 
220     /* (non-Javadoc)
221      * @see org.apache.jetspeed.page.PageManager#getPermissionsEnabled()
222      */
223     public boolean getPermissionsEnabled()
224     {
225         return delegator.getPermissionsEnabled();
226     }
227 
228     /* (non-Javadoc)
229      * @see org.apache.jetspeed.page.PageManager#newPage(java.lang.String)
230      */
231     public Page newPage(String path)
232     {
233         return delegator.newPage(path);
234     }
235 
236     /* (non-Javadoc)
237      * @see org.apache.jetspeed.page.PageManager#newFolder(java.lang.String)
238      */
239     public Folder newFolder(String path)
240     {
241         return delegator.newFolder(path);
242     }
243 
244     /* (non-Javadoc)
245      * @see org.apache.jetspeed.page.PageManager#newLink(java.lang.String)
246      */
247     public Link newLink(String path)
248     {
249         return delegator.newLink(path);
250     }
251 
252     /* (non-Javadoc)
253      * @see org.apache.jetspeed.page.PageManager#newPageSecurity()
254      */
255     public PageSecurity newPageSecurity()
256     {
257         return delegator.newPageSecurity();
258     }
259 
260     /* (non-Javadoc)
261      * @see org.apache.jetspeed.page.PageManager#newFragment()
262      */
263     public Fragment newFragment()
264     {
265         return delegator.newFragment();    
266     }
267 
268     /* (non-Javadoc)
269      * @see org.apache.jetspeed.page.PageManager#newPortletFragment()
270      */
271     public Fragment newPortletFragment()
272     {
273         return delegator.newPortletFragment();
274     }
275 
276     /* (non-Javadoc)
277      * @see org.apache.jetspeed.page.PageManager#newFolderMenuDefinition()
278      */
279     public MenuDefinition newFolderMenuDefinition()
280     {
281         return delegator.newFolderMenuDefinition();
282     }
283 
284     /* (non-Javadoc)
285      * @see org.apache.jetspeed.page.PageManager#newFolderMenuExcludeDefinition()
286      */
287     public MenuExcludeDefinition newFolderMenuExcludeDefinition()
288     {
289         return delegator.newFolderMenuExcludeDefinition();
290     }
291 
292     /* (non-Javadoc)
293      * @see org.apache.jetspeed.page.PageManager#newFolderMenuIncludeDefinition()
294      */
295     public MenuIncludeDefinition newFolderMenuIncludeDefinition()
296     {
297         return delegator.newFolderMenuIncludeDefinition();
298     }
299 
300     /* (non-Javadoc)
301      * @see org.apache.jetspeed.page.PageManager#newFolderMenuOptionsDefinition()
302      */
303     public MenuOptionsDefinition newFolderMenuOptionsDefinition()
304     {
305         return delegator.newFolderMenuOptionsDefinition();
306     }
307 
308     /* (non-Javadoc)
309      * @see org.apache.jetspeed.page.PageManager#newFolderMenuSeparatorDefinition()
310      */
311     public MenuSeparatorDefinition newFolderMenuSeparatorDefinition()
312     {
313         return delegator.newFolderMenuSeparatorDefinition();
314     }
315 
316     /* (non-Javadoc)
317      * @see org.apache.jetspeed.page.PageManager#newPageMenuDefinition()
318      */
319     public MenuDefinition newPageMenuDefinition()
320     {
321         return delegator.newPageMenuDefinition();
322     }
323 
324     /* (non-Javadoc)
325      * @see org.apache.jetspeed.page.PageManager#newPageMenuExcludeDefinition()
326      */
327     public MenuExcludeDefinition newPageMenuExcludeDefinition()
328     {
329         return delegator.newPageMenuExcludeDefinition();
330     }
331 
332     /* (non-Javadoc)
333      * @see org.apache.jetspeed.page.PageManager#newPageMenuIncludeDefinition()
334      */
335     public MenuIncludeDefinition newPageMenuIncludeDefinition()
336     {
337         return delegator.newPageMenuIncludeDefinition();
338     }
339 
340     /* (non-Javadoc)
341      * @see org.apache.jetspeed.page.PageManager#newPageMenuOptionsDefinition()
342      */
343     public MenuOptionsDefinition newPageMenuOptionsDefinition()
344     {
345         return delegator.newPageMenuOptionsDefinition();
346     }
347 
348     /* (non-Javadoc)
349      * @see org.apache.jetspeed.page.PageManager#newPageMenuSeparatorDefinition()
350      */
351     public MenuSeparatorDefinition newPageMenuSeparatorDefinition()
352     {
353         return delegator.newPageMenuSeparatorDefinition();
354     }
355 
356     /* (non-Javadoc)
357      * @see org.apache.jetspeed.page.PageManager#newSecurityConstraints()
358      */
359     public SecurityConstraints newSecurityConstraints()
360     {
361         return delegator.newSecurityConstraints();
362     }
363 
364     /* (non-Javadoc)
365      * @see org.apache.jetspeed.page.PageManager#newFolderSecurityConstraint()
366      */
367     public SecurityConstraint newFolderSecurityConstraint()
368     {
369         return delegator.newFolderSecurityConstraint();
370     }
371 
372     /* (non-Javadoc)
373      * @see org.apache.jetspeed.page.PageManager#newPageSecurityConstraint()
374      */
375     public SecurityConstraint newPageSecurityConstraint()
376     {
377         return delegator.newPageSecurityConstraint();
378     }
379 
380     /* (non-Javadoc)
381      * @see org.apache.jetspeed.page.PageManager#newFragmentSecurityConstraint()
382      */
383     public SecurityConstraint newFragmentSecurityConstraint()
384     {
385         return delegator.newFragmentSecurityConstraint();
386     }
387 
388     /* (non-Javadoc)
389      * @see org.apache.jetspeed.page.PageManager#newLinkSecurityConstraint()
390      */
391     public SecurityConstraint newLinkSecurityConstraint()
392     {
393         return delegator.newLinkSecurityConstraint();
394     }
395 
396     /* (non-Javadoc)
397      * @see org.apache.jetspeed.page.PageManager#newPageSecuritySecurityConstraint()
398      */
399     public SecurityConstraint newPageSecuritySecurityConstraint()
400     {
401         return delegator.newPageSecuritySecurityConstraint();
402     }
403 
404     /* (non-Javadoc)
405      * @see org.apache.jetspeed.page.PageManager#newSecurityConstraintsDef()
406      */
407     public SecurityConstraintsDef newSecurityConstraintsDef()
408     {
409         return delegator.newSecurityConstraintsDef();
410     }
411 
412     /* (non-Javadoc)
413      * @see org.apache.jetspeed.page.PageManager#newFragmentPreference()
414      */
415     public FragmentPreference newFragmentPreference()
416     {
417         return delegator.newFragmentPreference();
418     }
419 
420     /* (non-Javadoc)
421      * @see org.apache.jetspeed.page.PageManager#addListener(org.apache.jetspeed.page.PageManagerEventListener)
422      */
423     public void addListener(PageManagerEventListener listener)
424     {
425         delegator.addListener(listener);
426     }
427 
428     /* (non-Javadoc)
429      * @see org.apache.jetspeed.page.PageManager#removeListener(org.apache.jetspeed.page.PageManagerEventListener)
430      */
431     public void removeListener(PageManagerEventListener listener)
432     {
433         delegator.removeListener(listener);
434     }
435 
436     /* (non-Javadoc)
437      * @see org.apache.jetspeed.page.PageManager#reset()
438      */
439     public void reset()
440     {
441         // propagate to delegator
442         delegator.reset();
443 
444         // clear cache to force subsequent refreshs from persistent store
445         DatabasePageManagerCache.cacheClear();
446     }
447 
448     /* (non-Javadoc)
449      * @see org.apache.jetspeed.page.PageManager#getPage(java.lang.String)
450      */
451     public Page getPage(String path) throws PageNotFoundException, NodeException
452     {
453         // construct page attributes from path
454         path = NodeImpl.getCanonicalNodePath(path);
455 
456         // optimized retrieval from cache by path if available
457         NodeImpl cachedNode = DatabasePageManagerCache.cacheLookup(path);
458         if (cachedNode instanceof Page)
459         {
460             // check for view access on page
461             cachedNode.checkAccess(JetspeedActions.VIEW);
462 
463             return (Page)cachedNode;
464         }
465 
466         // retrieve page from database
467         try
468         {
469             Criteria filter = new Criteria();
470             filter.addEqualTo("path", path);
471             QueryByCriteria query = QueryFactory.newQuery(PageImpl.class, filter);
472             Page page = (Page)getPersistenceBrokerTemplate().getObjectByQuery(query);
473             
474             // return page or throw exception
475             if (page == null)
476             {
477                 throw new PageNotFoundException("Page " + path + " not found.");
478             }
479 
480             // check for view access on page
481             page.checkAccess(JetspeedActions.VIEW);
482 
483             return page;
484         }
485         catch (PageNotFoundException pnfe)
486         {
487             throw pnfe;
488         }
489         catch (SecurityException se)
490         {
491             throw se;
492         }
493         catch (Exception e)
494         {
495             throw new PageNotFoundException("Page " + path + " not found.", e);
496         }
497     }
498 
499     /* (non-Javadoc)
500      * @see org.apache.jetspeed.page.PageManager#getContentPage(java.lang.String)
501      */
502     public ContentPage getContentPage(String path) throws PageNotFoundException, NodeException
503     {
504         // return proxied page
505         return new ContentPageImpl(getPage(path));
506     }
507 
508     /* (non-Javadoc)
509      * @see org.apache.jetspeed.page.PageManager#getLink(java.lang.String)
510      */
511     public Link getLink(String path) throws DocumentNotFoundException, NodeException
512     {
513         // construct link attributes from path
514         path = NodeImpl.getCanonicalNodePath(path);
515 
516         // optimized retrieval from cache by path if available
517         NodeImpl cachedNode = DatabasePageManagerCache.cacheLookup(path);
518         if (cachedNode instanceof Link)
519         {
520             // check for view access on link
521             cachedNode.checkAccess(JetspeedActions.VIEW);
522 
523             return (Link)cachedNode;
524         }
525 
526         // retrieve link from database
527         try
528         {
529             Criteria filter = new Criteria();
530             filter.addEqualTo("path", path);
531             QueryByCriteria query = QueryFactory.newQuery(LinkImpl.class, filter);
532             Link link = (Link)getPersistenceBrokerTemplate().getObjectByQuery(query);
533             
534             // return link or throw exception
535             if (link == null)
536             {
537                 throw new DocumentNotFoundException("Link " + path + " not found.");
538             }
539 
540             // check for view access on link
541             link.checkAccess(JetspeedActions.VIEW);
542 
543             return link;
544         }
545         catch (DocumentNotFoundException dnfe)
546         {
547             throw dnfe;
548         }
549         catch (SecurityException se)
550         {
551             throw se;
552         }
553         catch (Exception e)
554         {
555             throw new DocumentNotFoundException("Link " + path + " not found.", e);
556         }
557     }
558 
559     /***
560      * Given a securityConstraintName definition and a set of actions,
561      * run a security constraint checks
562      */
563     public boolean checkConstraint(String securityConstraintName, String actions)
564     {
565         try
566         {
567             PageSecurity security = this.getPageSecurity();
568             SecurityConstraintsDef def = security.getSecurityConstraintsDef(securityConstraintName);
569             if (def != null)
570             {
571                 return PageManagerSecurityUtils.checkConstraint(def, actions);
572             }            
573         }
574         catch(Exception e)
575         {
576             e.printStackTrace();
577         }           
578         return false;
579     }
580     
581     /* (non-Javadoc)
582      * @see org.apache.jetspeed.page.PageManager#getPageSecurity()
583      */
584     public PageSecurity getPageSecurity() throws DocumentNotFoundException, NodeException
585     {
586         // construct document attributes from path
587         String path = Folder.PATH_SEPARATOR + PageSecurity.DOCUMENT_TYPE;
588 
589         // optimized retrieval from cache by path if available
590         NodeImpl cachedNode = DatabasePageManagerCache.cacheLookup(path);
591         if (cachedNode instanceof PageSecurity)
592         {
593             // check for view access on document
594             cachedNode.checkAccess(JetspeedActions.VIEW);
595 
596             return (PageSecurity)cachedNode;
597         }
598 
599         // retrieve document from database
600         try
601         {
602             Criteria filter = new Criteria();
603             filter.addEqualTo("path", path);
604             QueryByCriteria query = QueryFactory.newQuery(PageSecurityImpl.class, filter);
605             PageSecurity document = (PageSecurity)getPersistenceBrokerTemplate().getObjectByQuery(query);
606             
607             // return page or throw exception
608             if (document == null)
609             {
610                 throw new DocumentNotFoundException("Document " + path + " not found.");
611             }
612 
613             // check for view access on document
614             document.checkAccess(JetspeedActions.VIEW);
615 
616             return document;
617         }
618         catch (DocumentNotFoundException dnfe)
619         {
620             throw dnfe;
621         }
622         catch (SecurityException se)
623         {
624             throw se;
625         }
626         catch (Exception e)
627         {
628             throw new DocumentNotFoundException("Document " + path + " not found.", e);
629         }
630     }
631 
632     /* (non-Javadoc)
633      * @see org.apache.jetspeed.page.PageManager#getFolder(java.lang.String)
634      */
635     public Folder getFolder(String folderPath) throws FolderNotFoundException, InvalidFolderException, NodeException
636     {
637         // construct folder attributes from path
638         folderPath = NodeImpl.getCanonicalNodePath(folderPath);
639 
640         // optimized retrieval from cache by path if available
641         NodeImpl cachedNode = DatabasePageManagerCache.cacheLookup(folderPath);
642         if (cachedNode instanceof Folder)
643         {
644             // check for view access on folder
645             cachedNode.checkAccess(JetspeedActions.VIEW);
646 
647             return (Folder)cachedNode;
648         }
649 
650         // retrieve folder from database
651         try
652         {
653             Criteria filter = new Criteria();
654             filter.addEqualTo("path", folderPath);
655             QueryByCriteria query = QueryFactory.newQuery(FolderImpl.class, filter);
656             Folder folder = (Folder)getPersistenceBrokerTemplate().getObjectByQuery(query);
657             
658             // return folder or throw exception
659             if (folder == null)
660             {
661                 throw new FolderNotFoundException("Folder " + folderPath + " not found.");
662             }
663 
664             // check for view access on folder
665             folder.checkAccess(JetspeedActions.VIEW);
666 
667             return folder;
668         }
669         catch (FolderNotFoundException fnfe)
670         {
671             throw fnfe;
672         }
673         catch (SecurityException se)
674         {
675             throw se;
676         }
677         catch (Exception e)
678         {
679             throw new FolderNotFoundException("Folder " + folderPath + " not found.", e);
680         }
681     }
682 
683     /* (non-Javadoc)
684      * @see org.apache.jetspeed.page.PageManager#getFolders(org.apache.jetspeed.om.folder.Folder)
685      */
686     public NodeSet getFolders(Folder folder) throws DocumentException
687     {
688         FolderImpl folderImpl = (FolderImpl)folder;
689 
690         // perform lookup of folder folders collection and cache in folder
691         try
692         {
693             // query for folders
694             Criteria filter = new Criteria();
695             filter.addEqualTo("parent", folderImpl.getId());
696             QueryByCriteria query = QueryFactory.newQuery(FolderImpl.class, filter);
697             Collection folders = getPersistenceBrokerTemplate().getCollectionByQuery(query);
698 
699             // cache folders in folder
700             folderImpl.accessFolders().clear();
701             if (folders != null)
702             {
703                 folderImpl.accessFolders().addAll(folders);
704             }
705             folderImpl.resetFolders(true);
706         }
707         catch (Exception e)
708         {
709             // reset cache in folder
710             folderImpl.resetFolders(false);
711             throw new DocumentException("Unable to access folders for folder " + folder.getPath() + ".");
712         }
713 
714         // folder folders cache populated, get folders from folder
715         // to provide packaging as filtered node set
716         return folder.getFolders();
717     }
718 
719     /* (non-Javadoc)
720      * @see org.apache.jetspeed.page.PageManager#getFolder(org.apache.jetspeed.om.folder.Folder,java.lang.String)
721      */
722     public Folder getFolder(Folder folder, String name) throws FolderNotFoundException, DocumentException
723     {
724         // perform lookup by path so that cache can be used
725         String folderPath = folder.getPath() + Folder.PATH_SEPARATOR + name;
726         try
727         {
728             return getFolder(folderPath);
729         }
730         catch (FolderNotFoundException fnfe)
731         {
732             throw fnfe;
733         }
734         catch (Exception e)
735         {
736             throw new FolderNotFoundException("Folder " + folderPath + " not found.", e);
737         }
738     }
739 
740     /* (non-Javadoc)
741      * @see org.apache.jetspeed.page.PageManager#getPages(org.apache.jetspeed.om.folder.Folder)
742      */
743     public NodeSet getPages(Folder folder) throws NodeException
744     {
745         FolderImpl folderImpl = (FolderImpl)folder;
746 
747         // perform lookup of folder pages collection and cache in folder
748         try
749         {
750             // query for pages
751             Criteria filter = new Criteria();
752             filter.addEqualTo("parent", folderImpl.getId());
753             QueryByCriteria query = QueryFactory.newQuery(PageImpl.class, filter);
754             Collection pages = getPersistenceBrokerTemplate().getCollectionByQuery(query);
755 
756             // cache pages in folder
757             folderImpl.accessPages().clear();
758             if (pages != null)
759             {
760                 folderImpl.accessPages().addAll(pages);
761             }
762             folderImpl.resetPages(true);
763         }
764         catch (Exception e)
765         {
766             // reset cache in folder
767             folderImpl.resetPages(false);
768             throw new NodeException("Unable to access pages for folder " + folder.getPath() + ".");
769         }
770 
771         // folder pages cache populated, get pages from folder
772         // to provide packaging as filtered node set
773         return folder.getPages();
774     }
775     
776     /* (non-Javadoc)
777      * @see org.apache.jetspeed.page.PageManager#getPage(org.apache.jetspeed.om.folder.Folder,java.lang.String)
778      */
779     public Page getPage(Folder folder, String name) throws PageNotFoundException, NodeException
780     {
781         // perform lookup by path so that cache can be used
782         String pagePath = folder.getPath() + Folder.PATH_SEPARATOR + name;
783         try
784         {
785             return getPage(pagePath);
786         }
787         catch (PageNotFoundException pnfe)
788         {
789             throw pnfe;
790         }
791         catch (Exception e)
792         {
793             throw new PageNotFoundException("Page " + pagePath + " not found.", e);
794         }
795     }
796     
797     /* (non-Javadoc)
798      * @see org.apache.jetspeed.page.PageManager#getLinks(org.apache.jetspeed.om.folder.Folder)
799      */    
800     public NodeSet getLinks(Folder folder) throws NodeException
801     {
802         FolderImpl folderImpl = (FolderImpl)folder;
803 
804         // perform lookup of folder links collection and cache in folder
805         try
806         {
807             // query for links
808             Criteria filter = new Criteria();
809             filter.addEqualTo("parent", folderImpl.getId());
810             QueryByCriteria query = QueryFactory.newQuery(LinkImpl.class, filter);
811             Collection links = getPersistenceBrokerTemplate().getCollectionByQuery(query);
812 
813             // cache links in folder
814             folderImpl.accessLinks().clear();
815             if (links != null)
816             {
817                 folderImpl.accessLinks().addAll(links);
818             }
819             folderImpl.resetLinks(true);
820         }
821         catch (Exception e)
822         {
823             // reset cache in folder
824             folderImpl.resetLinks(false);
825             throw new NodeException("Unable to access links for folder " + folder.getPath() + ".");
826         }
827 
828         // folder links cache populated, get links from folder
829         // to provide packaging as filtered node set
830         return folder.getLinks();
831     }
832     
833     /* (non-Javadoc)
834      * @see org.apache.jetspeed.page.PageManager#getLink(org.apache.jetspeed.om.folder.Folder,java.lang.String)
835      */    
836     public Link getLink(Folder folder, String name) throws DocumentNotFoundException, NodeException
837     {
838         // perform lookup by path so that cache can be used
839         String linkPath = folder.getPath() + Folder.PATH_SEPARATOR + name;
840         try
841         {
842             return getLink(linkPath);
843         }
844         catch (DocumentNotFoundException dnfe)
845         {
846             throw dnfe;
847         }
848         catch (Exception e)
849         {
850             throw new DocumentNotFoundException("Link " + linkPath + " not found.", e);
851         }
852     }
853     
854     /* (non-Javadoc)
855      * @see org.apache.jetspeed.page.PageManager#getPageSecurity(org.apache.jetspeed.om.folder.Folder)
856      */    
857     public PageSecurity getPageSecurity(Folder folder) throws DocumentNotFoundException, NodeException
858     {
859         FolderImpl folderImpl = (FolderImpl)folder;
860 
861         // perform lookup of page security document and cache
862         // in folder; limit lookup to root folder since page
863         // security document is currently supported only as a
864         // root folder singleton
865         if (folder.getPath().equals(Folder.PATH_SEPARATOR))
866         {
867             try
868             {
869                 // query for page security
870                 Criteria filter = new Criteria();
871                 filter.addEqualTo("parent", folderImpl.getId());
872                 QueryByCriteria query = QueryFactory.newQuery(PageSecurityImpl.class, filter);
873                 PageSecurity document = (PageSecurity)getPersistenceBrokerTemplate().getObjectByQuery(query);
874 
875                 // cache page security in folder
876                 folderImpl.resetPageSecurity((PageSecurityImpl)document, true);
877             }
878             catch (Exception e)
879             {
880                 // reset page security in folder
881                 folderImpl.resetPageSecurity(null, true);
882                 throw new NodeException("Unable to access page security for folder " + folder.getPath() + ".");
883             }
884         }
885         else
886         {
887             // cache page security in folder
888             folderImpl.resetPageSecurity(null, true);
889         }
890 
891         // folder page security instance cache populated, get
892         // instance from folder to provide security checks
893         return folder.getPageSecurity();
894     }
895 
896     /* (non-Javadoc)
897      * @see org.apache.jetspeed.page.PageManager#getAll(org.apache.jetspeed.om.folder.Folder)
898      */
899     public NodeSet getAll(Folder folder) throws DocumentException
900     {
901         FolderImpl folderImpl = (FolderImpl)folder;
902 
903         // perform lookup of folder nodes collection and cache in folder
904         try
905         {
906             // query for all nodes
907             List all = DatabasePageManagerUtils.createList();
908             Criteria filter = new Criteria();
909             filter.addEqualTo("parent", folderImpl.getId());
910             QueryByCriteria query = QueryFactory.newQuery(FolderImpl.class, filter);
911             Collection folders = getPersistenceBrokerTemplate().getCollectionByQuery(query);
912             if (folders != null)
913             {
914                 all.addAll(folders);
915             }
916             query = QueryFactory.newQuery(PageImpl.class, filter);
917             Collection pages = getPersistenceBrokerTemplate().getCollectionByQuery(query);
918             if (pages != null)
919             {
920                 all.addAll(pages);
921             }
922             query = QueryFactory.newQuery(LinkImpl.class, filter);
923             Collection links = getPersistenceBrokerTemplate().getCollectionByQuery(query);
924             if (links != null)
925             {
926                 all.addAll(links);
927             }
928             query = QueryFactory.newQuery(PageSecurityImpl.class, filter);
929             PageSecurity document = (PageSecurity)getPersistenceBrokerTemplate().getObjectByQuery(query);
930             if (document != null)
931             {
932                 all.add(document);
933             }
934 
935             // cache links in folder
936             folderImpl.accessAll().clear();
937             folderImpl.accessAll().addAll(all);
938             folderImpl.resetAll(true);
939         }
940         catch (Exception e)
941         {
942             // reset cache in folder
943             folderImpl.resetAll(false);
944             throw new DocumentException("Unable to access all nodes for folder " + folder.getPath() + ".");
945         }
946 
947         // folder all nodes cache populated, get all from folder
948         // to provide packaging as filtered node set
949         return folder.getAll();
950     }
951 
952     /* (non-Javadoc)
953      * @see org.apache.jetspeed.page.PageManager#updatePage(org.apache.jetspeed.om.page.Page)
954      */
955     public void updatePage(Page page) throws NodeException, PageNotUpdatedException
956     {
957         try
958         {
959             // dereference page in case proxy is supplied
960             if (page instanceof ContentPageImpl)
961             {
962                 page = ((ContentPageImpl)page).getPage();
963             }
964             page = (Page)ProxyHelper.getRealObject(page);
965 
966             // look up and set parent folder if necessary
967             FolderImpl parent = (FolderImpl)page.getParent();
968             if (parent == null)
969             {
970                 // access folder by path
971                 String pagePath = page.getPath();
972                 String parentPath = pagePath.substring(0, pagePath.lastIndexOf(Folder.PATH_SEPARATOR));
973                 if (parentPath.length() == 0)
974                 {
975                     parentPath = Folder.PATH_SEPARATOR;
976                 }
977                 try
978                 {
979                     parent = (FolderImpl)getFolder(parentPath);                    
980                 }
981                 catch (FolderNotFoundException fnfe)
982                 {
983                     throw new PageNotUpdatedException("Missing parent folder: " + parentPath);
984                 }
985                 
986                 // check for edit access on parent folder; page
987                 // access not checked on create
988                 parent.checkAccess(JetspeedActions.EDIT);
989 
990                 // update page and mark cache transaction
991                 page.setParent(parent);
992                 getPersistenceBrokerTemplate().store(page);
993                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(page.getPath(), TransactionedOperation.ADD_OPERATION));
994 
995                 // reset parent folder pages cache
996                 if (parent != null)
997                 {
998                     parent.resetPages(false);
999                 }
1000 
1001                 // notify page manager listeners
1002                 delegator.notifyNewNode(page);
1003             }
1004             else
1005             {
1006                 // check for edit access on page and parent folder
1007                 page.checkAccess(JetspeedActions.EDIT);
1008 
1009                 // update page and mark cache transaction
1010                 getPersistenceBrokerTemplate().store(page);
1011                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(page.getPath(), TransactionedOperation.UPDATE_OPERATION));
1012                 
1013                 // reset parent folder pages cache in case
1014                 // parent is holding an out of date copy of
1015                 // this page that was removed from the cache
1016                 // before this one was accessed
1017                 if (parent != null)
1018                 {
1019                     parent.resetPages(false);
1020                 }
1021 
1022                 // notify page manager listeners
1023                 delegator.notifyUpdatedNode(page);
1024             }
1025         }
1026         catch (PageNotUpdatedException pnue)
1027         {
1028             throw pnue;
1029         }
1030         catch (SecurityException se)
1031         {
1032             throw se;
1033         }
1034         catch (Exception e)
1035         {
1036             throw new PageNotUpdatedException("Page " + page.getPath() + " not updated.", e);
1037         }        
1038     }
1039     
1040     /* (non-Javadoc)
1041      * @see org.apache.jetspeed.page.PageManager#removePage(org.apache.jetspeed.om.page.Page)
1042      */
1043     public void removePage(Page page) throws NodeException, PageNotRemovedException
1044     {
1045         try
1046         {
1047             // dereference page in case proxy is supplied
1048             if (page instanceof ContentPageImpl)
1049             {
1050                 page = ((ContentPageImpl)page).getPage();
1051             }
1052             page = (Page)ProxyHelper.getRealObject(page);
1053 
1054             // check for edit access on page and parent folder
1055             page.checkAccess(JetspeedActions.EDIT);
1056 
1057             // look up and update parent folder if necessary
1058             if (page.getParent() != null)
1059             {
1060                 FolderImpl parent = (FolderImpl)ProxyHelper.getRealObject(page.getParent());
1061                 
1062                 // delete page
1063                 getPersistenceBrokerTemplate().delete(page);
1064                 
1065                 // reset parent folder pages cache
1066                 if (parent != null)
1067                 {
1068                     parent.resetPages(false);
1069                 }
1070             }
1071             else
1072             {
1073                 // delete page
1074                 getPersistenceBrokerTemplate().delete(page);
1075             }
1076 
1077             // notify page manager listeners
1078             delegator.notifyRemovedNode(page);
1079         }
1080         catch (SecurityException se)
1081         {
1082             throw se;
1083         }
1084         catch (Exception e)
1085         {
1086             throw new PageNotRemovedException("Page " + page.getPath() + " not removed.", e);
1087         }
1088     }
1089 
1090     /* (non-Javadoc)
1091      * @see org.apache.jetspeed.page.PageManager#updateFolder(org.apache.jetspeed.om.folder.Folder)
1092      */
1093     public void updateFolder(Folder folder) throws NodeException, FolderNotUpdatedException
1094     {
1095         // shallow update by default
1096         updateFolder(folder, false);
1097     }
1098 
1099     /* (non-Javadoc)
1100      * @see org.apache.jetspeed.page.PageManager#updateFolder(org.apache.jetspeed.om.folder.Folder,boolean)
1101      */
1102     public void updateFolder(Folder folder, boolean deep) throws NodeException, FolderNotUpdatedException
1103     {
1104         try
1105         {
1106             // dereference folder in case proxy is supplied
1107             folder = (Folder)ProxyHelper.getRealObject(folder);
1108 
1109             // look up and set parent folder if required
1110             FolderImpl parent = (FolderImpl)folder.getParent();
1111             if ((parent == null) && !folder.getPath().equals(Folder.PATH_SEPARATOR))
1112             {
1113                 // access folder by path
1114                 String folderPath = folder.getPath();
1115                 String parentPath = folderPath.substring(0, folderPath.lastIndexOf(Folder.PATH_SEPARATOR));
1116                 if (parentPath.length() == 0)
1117                 {
1118                     parentPath = Folder.PATH_SEPARATOR;
1119                 }
1120                 try
1121                 {
1122                     parent = (FolderImpl)getFolder(parentPath);
1123                 }
1124                 catch (FolderNotFoundException fnfe)
1125                 {
1126                     throw new FolderNotUpdatedException("Missing parent folder: " + parentPath);
1127                 }
1128                 
1129                 // check for edit access on parent folder; folder
1130                 // access not checked on create
1131                 parent.checkAccess(JetspeedActions.EDIT);
1132 
1133                 // update folder and mark cache transaction
1134                 folder.setParent(parent);
1135                 getPersistenceBrokerTemplate().store(folder);
1136                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(folder.getPath(), TransactionedOperation.ADD_OPERATION));
1137 
1138                 // reset parent folder folders cache
1139                 if (parent != null)
1140                 {
1141                     parent.resetFolders(false);
1142                 }
1143 
1144                 // notify page manager listeners
1145                 delegator.notifyNewNode(folder);
1146             }
1147             else
1148             {
1149                 // determine if folder is new by checking autoincrement id
1150                 boolean newFolder = folder.getId().equals("0");
1151 
1152                 // check for edit access on folder and parent folder
1153                 // if not being initially created; access is not
1154                 // checked on create
1155                 if (!newFolder || !folder.getPath().equals(Folder.PATH_SEPARATOR))
1156                 {
1157                     folder.checkAccess(JetspeedActions.EDIT);
1158                 }
1159 
1160                 // create root folder or update folder and mark cache transaction
1161                 getPersistenceBrokerTemplate().store(folder);
1162                 if (newFolder && !folder.getId().equals("0"))
1163                 {
1164                     DatabasePageManagerCache.addTransaction(new TransactionedOperation(folder.getPath(), TransactionedOperation.ADD_OPERATION));
1165                 }
1166                 else
1167                 {
1168                     DatabasePageManagerCache.addTransaction(new TransactionedOperation(folder.getPath(), TransactionedOperation.UPDATE_OPERATION));
1169                 }
1170 
1171                 // reset parent folder folders cache in case
1172                 // parent is holding an out of date copy of
1173                 // this folder that was removed from the cache
1174                 // before this one was accessed
1175                 if (parent != null)
1176                 {
1177                     parent.resetFolders(false);
1178                 }
1179 
1180                 // notify page manager listeners
1181                 if (newFolder && !folder.getId().equals("0"))
1182                 {
1183                     delegator.notifyNewNode(folder);
1184                 }
1185                 else
1186                 {
1187                     delegator.notifyUpdatedNode(folder);
1188                 }
1189             }
1190 
1191             // update deep recursively if specified
1192             if (deep)
1193             {
1194                 // update recursively, (breadth first)
1195                 updateFolderNodes((FolderImpl)folder);
1196             }
1197         }
1198         catch (FolderNotUpdatedException fnue)
1199         {
1200             throw fnue;
1201         }
1202         catch (SecurityException se)
1203         {
1204             throw se;
1205         }
1206         catch (Exception e)
1207         {
1208             throw new FolderNotUpdatedException("Folder " + folder.getPath() + " not updated.", e);
1209         }
1210     }
1211 
1212     /***
1213      * updateFolderNodes - recusively update all folder nodes
1214      *
1215      * @param folderImpl folder whose nodes are to be updated
1216      * @param throws FolderNotUpdatedException
1217      */
1218     private void updateFolderNodes(FolderImpl folderImpl) throws FolderNotUpdatedException
1219     {
1220         try
1221         {
1222             // construct general node query criteria
1223             Criteria filter = new Criteria();
1224             filter.addEqualTo("parent", folderImpl.getId());
1225 
1226             // update pages
1227             QueryByCriteria query = QueryFactory.newQuery(PageImpl.class, filter);
1228             Collection pages = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1229             if (pages != null)
1230             {
1231                 Iterator pagesIter = pages.iterator();
1232                 while (pagesIter.hasNext())
1233                 {
1234                     updatePage((Page)pagesIter.next());
1235                 }
1236             }
1237 
1238             // update links
1239             query = QueryFactory.newQuery(LinkImpl.class, filter);
1240             Collection links = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1241             if (links != null)
1242             {
1243                 Iterator linksIter = links.iterator();
1244                 while (linksIter.hasNext())
1245                 {
1246                     updateLink((Link)linksIter.next());
1247                 }
1248             }
1249 
1250             // update page security
1251             query = QueryFactory.newQuery(PageSecurityImpl.class, filter);
1252             PageSecurity document = (PageSecurity)getPersistenceBrokerTemplate().getObjectByQuery(query);
1253             if (document != null)
1254             {
1255                 updatePageSecurity(document);
1256             }
1257 
1258             // update folders last: breadth first recursion
1259             query = QueryFactory.newQuery(FolderImpl.class, filter);
1260             Collection folders = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1261             if (folders != null)
1262             {
1263                 Iterator foldersIter = folders.iterator();
1264                 while (foldersIter.hasNext())
1265                 {
1266                     updateFolder((Folder)foldersIter.next(), true);
1267                 }
1268             }
1269         }
1270         catch (FolderNotUpdatedException fnue)
1271         {
1272             throw fnue;
1273         }
1274         catch (SecurityException se)
1275         {
1276             throw se;
1277         }
1278         catch (Exception e)
1279         {
1280             throw new FolderNotUpdatedException("Folder " + folderImpl.getPath() + " not updated.", e);
1281         }
1282     }
1283 
1284     /* (non-Javadoc)
1285      * @see org.apache.jetspeed.page.PageManager#removeFolder(org.apache.jetspeed.om.folder.Folder)
1286      */
1287     public void removeFolder(Folder folder) throws NodeException, FolderNotRemovedException
1288     {
1289         try
1290         {
1291             // dereference folder in case proxy is supplied
1292             folder = (Folder)ProxyHelper.getRealObject(folder);
1293 
1294             // check for edit access on folder and parent folder
1295             folder.checkAccess(JetspeedActions.EDIT);
1296 
1297             // reset folder nodes cache
1298             ((FolderImpl)folder).resetAll(false);
1299 
1300             // remove recursively, (depth first)
1301             removeFolderNodes((FolderImpl)folder);
1302 
1303             // look up and update parent folder if necessary
1304             if (folder.getParent() != null)
1305             {
1306                 FolderImpl parent = (FolderImpl)ProxyHelper.getRealObject(folder.getParent());
1307 
1308                 // delete folder
1309                 getPersistenceBrokerTemplate().delete(folder);
1310 
1311                 // reset parent folder folders cache
1312                 if (parent != null)
1313                 {
1314                     parent.resetFolders(false);
1315                 }
1316             }
1317             else
1318             {
1319                 // delete folder: depth recursion
1320                 getPersistenceBrokerTemplate().delete(folder);
1321             }
1322 
1323             // notify page manager listeners
1324             delegator.notifyRemovedNode((FolderImpl)folder);
1325         }
1326         catch (SecurityException se)
1327         {
1328             throw se;
1329         }
1330         catch (Exception e)
1331         {
1332             throw new FolderNotRemovedException("Folder " + folder.getPath() + " not removed.", e);
1333         }
1334     }
1335 
1336     /***
1337      * removeFolderNodes - recusively remove all folder nodes
1338      *
1339      * @param folderImpl folder whose nodes are to be removed
1340      * @param throws FolderNotRemovedException
1341      */
1342     private void removeFolderNodes(FolderImpl folderImpl) throws FolderNotRemovedException
1343     {
1344         try
1345         {
1346             // construct general node query criteria
1347             Criteria filter = new Criteria();
1348             filter.addEqualTo("parent", folderImpl.getId());
1349 
1350             // remove folders first: depth first recursion
1351             QueryByCriteria query = QueryFactory.newQuery(FolderImpl.class, filter);
1352             Collection folders = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1353             if (folders != null)
1354             {
1355                 Iterator foldersIter = folders.iterator();
1356                 while (foldersIter.hasNext())
1357                 {
1358                     removeFolder((Folder)foldersIter.next());
1359                 }
1360             }
1361 
1362             // remove pages
1363             query = QueryFactory.newQuery(PageImpl.class, filter);
1364             Collection pages = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1365             if (pages != null)
1366             {
1367                 Iterator pagesIter = pages.iterator();
1368                 while (pagesIter.hasNext())
1369                 {
1370                     removePage((Page)pagesIter.next());
1371                 }
1372             }
1373 
1374             // remove links
1375             query = QueryFactory.newQuery(LinkImpl.class, filter);
1376             Collection links = getPersistenceBrokerTemplate().getCollectionByQuery(query);
1377             if (links != null)
1378             {
1379                 Iterator linksIter = links.iterator();
1380                 while (linksIter.hasNext())
1381                 {
1382                     removeLink((Link)linksIter.next());
1383                 }
1384             }
1385 
1386             // remove page security
1387             query = QueryFactory.newQuery(PageSecurityImpl.class, filter);
1388             PageSecurity document = (PageSecurity)getPersistenceBrokerTemplate().getObjectByQuery(query);
1389             if (document != null)
1390             {
1391                 removePageSecurity(document);
1392             }
1393         }
1394         catch (FolderNotRemovedException fnre)
1395         {
1396             throw fnre;
1397         }
1398         catch (SecurityException se)
1399         {
1400             throw se;
1401         }
1402         catch (Exception e)
1403         {
1404             throw new FolderNotRemovedException("Folder " + folderImpl.getPath() + " not removed.", e);
1405         }
1406     }
1407 
1408     /* (non-Javadoc)
1409      * @see org.apache.jetspeed.page.PageManager#updateLink(org.apache.jetspeed.om.page.Link)
1410      */
1411     public void updateLink(Link link) throws NodeException, LinkNotUpdatedException
1412     {
1413         try
1414         {
1415             // dereference link in case proxy is supplied
1416             link = (Link)ProxyHelper.getRealObject(link);
1417 
1418             // look up and set parent folder if necessary
1419             FolderImpl parent = (FolderImpl)link.getParent();
1420             if (parent == null)
1421             {
1422                 // access folder by path
1423                 String linkPath = link.getPath();
1424                 String parentPath = linkPath.substring(0, linkPath.lastIndexOf(Folder.PATH_SEPARATOR));
1425                 if (parentPath.length() == 0)
1426                 {
1427                     parentPath = Folder.PATH_SEPARATOR;
1428                 }
1429                 try
1430                 {
1431                     parent = (FolderImpl)getFolder(parentPath);
1432                 }
1433                 catch (FolderNotFoundException fnfe)
1434                 {
1435                     throw new FailedToUpdateDocumentException("Missing parent folder: " + parentPath);
1436                 }
1437                 
1438                 // check for edit access on parent folder; link
1439                 // access not checked on create
1440                 parent.checkAccess(JetspeedActions.EDIT);
1441 
1442                 // update link and mark cache transaction
1443                 link.setParent(parent);
1444                 getPersistenceBrokerTemplate().store(link);
1445                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(link.getPath(), TransactionedOperation.ADD_OPERATION));
1446 
1447                 // reset parent folder links cache
1448                 if (parent != null)
1449                 {
1450                     parent.resetLinks(false);
1451                 }
1452 
1453                 // notify page manager listeners
1454                 delegator.notifyNewNode(link);
1455             }
1456             else
1457             {
1458                 // check for edit access on link and parent folder
1459                 link.checkAccess(JetspeedActions.EDIT);
1460 
1461                 // update link and mark cache transaction
1462                 getPersistenceBrokerTemplate().store(link);
1463                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(link.getPath(), TransactionedOperation.UPDATE_OPERATION));
1464 
1465                 // reset parent folder links cache in case
1466                 // parent is holding an out of date copy of
1467                 // this link that was removed from the cache
1468                 // before this one was accessed
1469                 if (parent != null)
1470                 {
1471                     parent.resetLinks(false);
1472                 }
1473 
1474                 // notify page manager listeners
1475                 delegator.notifyUpdatedNode(link);
1476             }
1477         }
1478         catch (FailedToUpdateDocumentException fude)
1479         {
1480             throw fude;
1481         }
1482         catch (SecurityException se)
1483         {
1484             throw se;
1485         }
1486         catch (Exception e)
1487         {
1488             throw new FailedToUpdateDocumentException("Link " + link.getPath() + " not updated.", e);
1489         }
1490     }
1491 
1492     /* (non-Javadoc)
1493      * @see org.apache.jetspeed.page.PageManager#removeLink(org.apache.jetspeed.om.page.Link)
1494      */
1495     public void removeLink(Link link) throws NodeException, LinkNotRemovedException
1496     {
1497         try
1498         {
1499             // dereference link in case proxy is supplied
1500             link = (Link)ProxyHelper.getRealObject(link);
1501 
1502             // check for edit access on link and parent folder
1503             link.checkAccess(JetspeedActions.EDIT);
1504 
1505             // look up and update parent folder if necessary
1506             if (link.getParent() != null)
1507             {
1508                 FolderImpl parent = (FolderImpl)ProxyHelper.getRealObject(link.getParent());
1509 
1510                 // delete link
1511                 getPersistenceBrokerTemplate().delete(link);
1512 
1513                 // reset parent folder links cache
1514                 if (parent != null)
1515                 {                
1516                     parent.resetLinks(false);
1517                 }
1518             }
1519             else
1520             {
1521                 // delete link
1522                 getPersistenceBrokerTemplate().delete(link);
1523             }
1524 
1525             // notify page manager listeners
1526             delegator.notifyRemovedNode(link);
1527         }
1528         catch (SecurityException se)
1529         {
1530             throw se;
1531         }
1532         catch (Exception e)
1533         {
1534             throw new FailedToDeleteDocumentException("Link " + link.getPath() + " not removed.", e);
1535         }
1536     }
1537 
1538     /* (non-Javadoc)
1539      * @see org.apache.jetspeed.page.PageManager#updatePageSecurity(org.apache.jetspeed.om.page.PageSecurity)
1540      */
1541     public void updatePageSecurity(PageSecurity pageSecurity) throws NodeException, FailedToUpdateDocumentException
1542     {
1543         try
1544         {
1545             // dereference document in case proxy is supplied
1546             pageSecurity = (PageSecurity)ProxyHelper.getRealObject(pageSecurity);
1547 
1548             // look up and set parent folder if necessary
1549             FolderImpl parent = (FolderImpl)pageSecurity.getParent();
1550             if (parent == null)
1551             {
1552                 // access folder by path
1553                 String pageSecurityPath = pageSecurity.getPath();
1554                 String parentPath = pageSecurityPath.substring(0, pageSecurityPath.lastIndexOf(Folder.PATH_SEPARATOR));
1555                 if (parentPath.length() == 0)
1556                 {
1557                     parentPath = Folder.PATH_SEPARATOR;
1558                 }
1559                 try
1560                 {
1561                     parent = (FolderImpl)getFolder(parentPath);
1562                 }
1563                 catch (FolderNotFoundException fnfe)
1564                 {
1565                     throw new FailedToUpdateDocumentException("Missing parent folder: " + parentPath);
1566                 }
1567 
1568                 // do not replace existing page security documents
1569                 try
1570                 {
1571                     parent.getPageSecurity();
1572                     throw new FailedToUpdateDocumentException("Parent folder page security exists: " + parentPath);
1573                 }
1574                 catch (DocumentNotFoundException dnfe)
1575                 {
1576                     // check for edit access on parent folder; document
1577                     // access not checked on create
1578                     parent.checkAccess(JetspeedActions.EDIT);
1579                     
1580                     // update document and mark cache transaction
1581                     pageSecurity.setParent(parent);
1582                     getPersistenceBrokerTemplate().store(pageSecurity);
1583                     DatabasePageManagerCache.addTransaction(new TransactionedOperation(pageSecurity.getPath(), TransactionedOperation.ADD_OPERATION));
1584 
1585                     // reset parent folder page security cache
1586                     if (parent != null)
1587                     {                    
1588                         parent.resetPageSecurity((PageSecurityImpl)pageSecurity, true);
1589                     }
1590                 }
1591                 catch (Exception e)
1592                 {
1593                     throw new FailedToUpdateDocumentException("Parent folder page security exists: " + parentPath);
1594                 }
1595 
1596                 // notify page manager listeners
1597                 delegator.notifyNewNode(pageSecurity);
1598             }
1599             else
1600             {
1601                 // check for edit access on document and parent folder
1602                 pageSecurity.checkAccess(JetspeedActions.EDIT);
1603 
1604                 // update document and mark cache transaction
1605                 getPersistenceBrokerTemplate().store(pageSecurity);
1606                 DatabasePageManagerCache.addTransaction(new TransactionedOperation(pageSecurity.getPath(), TransactionedOperation.UPDATE_OPERATION));
1607 
1608                 // reset parent folder page security cache in case
1609                 // parent is holding an out of date copy of this
1610                 // page security that was removed from the cache
1611                 // before this one was accessed
1612                 if (parent != null)
1613                 {                
1614                     parent.resetPageSecurity((PageSecurityImpl)pageSecurity, true);
1615                 }
1616 
1617                 // notify page manager listeners
1618                 delegator.notifyUpdatedNode(pageSecurity);
1619             }
1620 
1621             // reset all cached security constraints
1622             DatabasePageManagerCache.resetCachedSecurityConstraints();
1623         }
1624         catch (FailedToUpdateDocumentException fude)
1625         {
1626             throw fude;
1627         }
1628         catch (SecurityException se)
1629         {
1630             throw se;
1631         }
1632         catch (Exception e)
1633         {
1634             throw new FailedToUpdateDocumentException("Document " + pageSecurity.getPath() + " not updated.", e);
1635         }
1636     }
1637 
1638     /* (non-Javadoc)
1639      * @see org.apache.jetspeed.page.PageManager#removePageSecurity(org.apache.jetspeed.om.page.PageSecurity)
1640      */
1641     public void removePageSecurity(PageSecurity pageSecurity) throws NodeException, FailedToDeleteDocumentException
1642     {
1643         try
1644         {
1645             // dereference document in case proxy is supplied
1646             pageSecurity = (PageSecurity)ProxyHelper.getRealObject(pageSecurity);
1647 
1648             // check for edit access on document and parent folder
1649             pageSecurity.checkAccess(JetspeedActions.EDIT);
1650 
1651             // look up and update parent folder if necessary
1652             if (pageSecurity.getParent() != null)
1653             {
1654                 FolderImpl parent = (FolderImpl)ProxyHelper.getRealObject(pageSecurity.getParent());
1655 
1656                 // delete document
1657                 getPersistenceBrokerTemplate().delete(pageSecurity);
1658 
1659                 // reset parent folder page security cache
1660                 if (parent != null)
1661                 {                
1662                     parent.resetPageSecurity(null, true);
1663                 }
1664             }
1665             else
1666             {
1667                 // delete document
1668                 getPersistenceBrokerTemplate().delete(pageSecurity);
1669             }
1670 
1671             // reset all cached security constraints
1672             DatabasePageManagerCache.resetCachedSecurityConstraints();
1673 
1674             // notify page manager listeners
1675             delegator.notifyRemovedNode(pageSecurity);
1676         }
1677         catch (SecurityException se)
1678         {
1679             throw se;
1680         }
1681         catch (Exception e)
1682         {
1683             throw new FailedToDeleteDocumentException("Document " + pageSecurity.getPath() + " not removed.", e);
1684         }
1685     }
1686 
1687     /* (non-Javadoc)
1688      * @see org.apache.jetspeed.page.PageManager#copyPage(org.apache.jetspeed.om.page.Page,java.lang.String)
1689      */
1690     public Page copyPage(Page source, String path)
1691     throws NodeException, PageNotUpdatedException
1692     {
1693         return this.delegator.copyPage(source, path);
1694     }
1695 
1696     /* (non-Javadoc)
1697      * @see org.apache.jetspeed.page.PageManager#copyLink(org.apache.jetspeed.om.page.Link,java.lang.String)
1698      */
1699     public Link copyLink(Link source, String path)
1700     throws NodeException, LinkNotUpdatedException
1701     {
1702         return this.delegator.copyLink(source, path);
1703     }
1704 
1705     /* (non-Javadoc)
1706      * @see org.apache.jetspeed.page.PageManager#copyFolder(org.apache.jetspeed.om.folder.Folder,java.lang.String)
1707      */
1708     public Folder copyFolder(Folder source, String path)
1709     throws NodeException, PageNotUpdatedException
1710     {
1711         return this.delegator.copyFolder(source, path);
1712     }
1713 
1714     /* (non-Javadoc)
1715      * @see org.apache.jetspeed.page.PageManager#copyFragment(org.apache.jetspeed.om.page.Fragment,java.lang.String)
1716      */
1717     public Fragment copyFragment(Fragment source, String name)
1718     throws NodeException, PageNotUpdatedException
1719     {
1720         return this.delegator.copyFragment(source, name);
1721     }
1722     
1723     /* (non-Javadoc)
1724      * @see org.apache.jetspeed.page.PageManager#copyPageSecurity(org.apache.jetspeed.om.page.PageSecurity)
1725      */
1726     public PageSecurity copyPageSecurity(PageSecurity source) 
1727     throws NodeException
1728     {
1729         return this.delegator.copyPageSecurity(source);
1730     }
1731     
1732     /* (non-Javadoc)
1733      * @see org.apache.jetspeed.page.PageManager#getUserPage(java.lang.String,java.lang.String)
1734      */
1735     public Page getUserPage(String userName, String pageName)
1736     throws PageNotFoundException, NodeException
1737     {
1738         return this.getPage(Folder.USER_FOLDER + userName + Folder.PATH_SEPARATOR + pageName);
1739     }
1740     
1741     /* (non-Javadoc)
1742      * @see org.apache.jetspeed.page.PageManager#getUserFolder(java.lang.String)
1743      */
1744     public Folder getUserFolder(String userName) 
1745         throws FolderNotFoundException, InvalidFolderException, NodeException
1746     {
1747         return this.getFolder(Folder.USER_FOLDER + userName);        
1748     }
1749 
1750     /* (non-Javadoc)
1751      * @see org.apache.jetspeed.page.PageManager#folderExists(java.lang.String)
1752      */
1753     public boolean folderExists(String folderName)
1754     {
1755         try
1756         {
1757             getFolder(folderName);
1758         }
1759         catch (Exception e)
1760         {
1761             return false;
1762         }
1763         return true;
1764     }
1765 
1766     /* (non-Javadoc)
1767      * @see org.apache.jetspeed.page.PageManager#pageExists(java.lang.String)
1768      */
1769     public boolean pageExists(String pageName)
1770     {
1771         try
1772         {
1773             getPage(pageName);
1774         }
1775         catch (Exception e)
1776         {
1777             return false;
1778         }
1779         return true;
1780     }
1781     
1782     /* (non-Javadoc)
1783      * @see org.apache.jetspeed.page.PageManager#linkExists(java.lang.String)
1784      */
1785     public boolean linkExists(String linkName)
1786     {
1787         try
1788         {
1789             getLink(linkName);
1790         }
1791         catch (Exception e)
1792         {
1793             return false;
1794         }
1795         return true;
1796     }
1797 
1798     /* (non-Javadoc)
1799      * @see org.apache.jetspeed.page.PageManager#userFolderExists(java.lang.String)
1800      */
1801     public boolean userFolderExists(String userName)
1802     {
1803         try
1804         {
1805             getFolder(Folder.USER_FOLDER + userName);
1806         }
1807         catch (Exception e)
1808         {
1809             return false;
1810         }
1811         return true;
1812     }
1813     
1814     /* (non-Javadoc)
1815      * @see org.apache.jetspeed.page.PageManager#userPageExists(java.lang.String)
1816      */
1817     public boolean userPageExists(String userName, String pageName)
1818     {
1819         try
1820         {
1821             getPage(Folder.USER_FOLDER + userName + Folder.PATH_SEPARATOR + pageName);
1822         }
1823         catch (Exception e)
1824         {
1825             return false;
1826         }
1827         return true;
1828     }
1829     
1830     /* (non-Javadoc)
1831      * @see org.apache.jetspeed.page.PageManager#createUserHomePagesFromRoles(java.security.auth.Subject)
1832      */
1833     public void createUserHomePagesFromRoles(Subject subject)
1834     throws NodeException
1835     {
1836         PageManagerUtils.createUserHomePagesFromRoles(this, subject);
1837     }
1838     
1839     /* (non-Javadoc)
1840      * @see org.apache.jetspeed.page.PageManager#deepCopyFolder(org.apache.jetspeed.om.folder.Folder,java.lang.String,java.lang.String)
1841      */
1842     public void deepCopyFolder(Folder srcFolder, String destinationPath, String owner)
1843     throws NodeException, PageNotUpdatedException
1844     {
1845         PageManagerUtils.deepCopyFolder(this, srcFolder, destinationPath, owner);
1846     }
1847     
1848     /* (non-Javadoc)
1849      * @see org.apache.jetspeed.page.PageManager#addPages(org.apache.jetspeed.om.page.Page[])
1850      */
1851     public int addPages(Page[] pages)
1852     throws NodeException
1853     {   
1854         if (pages.length > 0 && pages[0].getPath().equals("/tx__test1.psml"))
1855         {
1856             // for tx testing
1857             System.out.println("Adding first page");
1858             this.updatePage(pages[0]);
1859             System.out.println("Adding second page");
1860             this.updatePage(pages[1]);
1861             System.out.println("About to throw ex");
1862             throw new NodeException("Its gonna blow captain!");
1863         }
1864         for (int ix = 0; ix < pages.length; ix++)
1865         {
1866             this.updatePage(pages[ix]);
1867         }
1868         return pages.length;
1869     }
1870     
1871 }