View Javadoc

1   /*
2    * Copyright 2000-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.portals.graffito.jcr.persistence.impl;
17  
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.jcr.InvalidItemStateException;
26  import javax.jcr.Item;
27  import javax.jcr.Node;
28  import javax.jcr.NodeIterator;
29  import javax.jcr.PathNotFoundException;
30  import javax.jcr.RepositoryException;
31  import javax.jcr.Session;
32  import javax.jcr.UnsupportedRepositoryOperationException;
33  import javax.jcr.lock.Lock;
34  import javax.jcr.lock.LockException;
35  import javax.jcr.nodetype.NoSuchNodeTypeException;
36  import javax.jcr.query.InvalidQueryException;
37  import javax.jcr.query.QueryResult;
38  import javax.jcr.version.VersionHistory;
39  
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  import org.apache.portals.graffito.jcr.exception.IllegalUnlockException;
43  import org.apache.portals.graffito.jcr.exception.JcrMappingException;
44  import org.apache.portals.graffito.jcr.exception.LockedException;
45  import org.apache.portals.graffito.jcr.exception.PersistenceException;
46  import org.apache.portals.graffito.jcr.exception.VersionException;
47  import org.apache.portals.graffito.jcr.mapper.Mapper;
48  import org.apache.portals.graffito.jcr.mapper.impl.DigesterMapperImpl;
49  import org.apache.portals.graffito.jcr.mapper.model.ClassDescriptor;
50  import org.apache.portals.graffito.jcr.persistence.PersistenceManager;
51  import org.apache.portals.graffito.jcr.persistence.atomictypeconverter.impl.DefaultAtomicTypeConverterProvider;
52  import org.apache.portals.graffito.jcr.persistence.objectconverter.ObjectConverter;
53  import org.apache.portals.graffito.jcr.persistence.objectconverter.impl.ObjectConverterImpl;
54  import org.apache.portals.graffito.jcr.query.Query;
55  import org.apache.portals.graffito.jcr.query.QueryManager;
56  import org.apache.portals.graffito.jcr.query.impl.QueryManagerImpl;
57  import org.apache.portals.graffito.jcr.version.Version;
58  import org.apache.portals.graffito.jcr.version.VersionIterator;
59  
60  /***
61   *
62   * Default implementation for {@link org.apache.portals.graffito.jcr.persistence.PersistenceManager}
63   *
64   * @author Sandro Boehme
65   * @author <a href="mailto:christophe.lombart@sword-technologies.com">Lombart Christophe</a>
66   * @author Martin Koci
67   * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
68   */
69  public class PersistenceManagerImpl implements PersistenceManager {
70      /***
71       * Logger.
72       */
73      private final static Log log = LogFactory.getLog(PersistenceManagerImpl.class);
74  
75      /***
76       * JCR session.
77       */
78      protected Session session;
79  
80      protected Mapper mapper;
81  
82      /***
83       * The Graffito query manager
84       */
85      protected QueryManager queryManager;
86  
87      /***
88       * Object Converter
89       */
90      protected ObjectConverter objectConverter;
91  
92      
93      /***
94       * Creates a new <code>PersistenceManager</code> that uses the passed in
95       * <code>Mapper</code>, <code>QueryManager</code> and a default 
96       * <code>ObjectConverter</code>
97       *
98       * @param mapper the Mapper component
99       * @param queryManager the query manager to used
100      * @param session The JCR session
101      */
102     public PersistenceManagerImpl(Mapper mapper,
103                                   QueryManager queryManager,
104                                   Session session) {
105         this.mapper = mapper;
106         this.session = session;
107         this.objectConverter = new ObjectConverterImpl(mapper, new DefaultAtomicTypeConverterProvider());
108         this.queryManager = queryManager;
109     }
110 
111     /***
112      * Creates a new <code>PersistenceManager</code> based on a JCR session and some xml mapping files. 
113      *
114      * @param session The JCR session
115      * @param xmlMappingFiles Graffito JCR mapping file used mainly to create the <code>Mapper</code> component
116      */
117     public PersistenceManagerImpl(Session session,String[] xmlMappingFiles ) 
118     {
119         this.session = session;
120 		this.mapper = new DigesterMapperImpl(xmlMappingFiles);
121 		DefaultAtomicTypeConverterProvider converterProvider = new DefaultAtomicTypeConverterProvider();
122         Map atomicTypeConverters = converterProvider.getAtomicTypeConverters();
123 		this.queryManager = new QueryManagerImpl(mapper, atomicTypeConverters);
124         this.objectConverter = new ObjectConverterImpl(mapper, converterProvider);
125 		
126         
127     }
128     
129     
130     /***
131      * Full constructor.
132      * 
133      * @param mapper the Mapper component
134      * @param converter the <code>ObjectConverter</code> to be used internally
135      * @param queryManager the query manager to used
136      * @param session The JCR session
137      */
138     public PersistenceManagerImpl(Mapper mapper,
139                                   ObjectConverter converter,
140                                   QueryManager queryManager,
141                                   Session session) {
142         this.mapper = mapper;
143         this.session = session;
144         this.objectConverter = converter;
145         this.queryManager = queryManager;
146     }
147     
148     /***
149      * Sets the <code>Mapper</code> used by this persistence manager.
150      * 
151      * @param mapper mapping solver
152      */
153     public void setMapper(Mapper mapper) {
154         this.mapper = mapper;
155     }
156     
157     /***
158      * Sets the <code>ObjectConverter</code> that is used internally by this persistence manager.
159      * 
160      * @param objectConverter the internal <code>ObjectConverter</code>
161      */
162     public void setObjectConverter(ObjectConverter objectConverter) {
163         this.objectConverter = objectConverter;
164     }
165     
166     /***
167      * Sets the <code>QueryManager</code> used by the persistence manager.
168      * 
169      * @param queryManager a <code>QueryManager</code>
170      */
171     public void setQueryManager(QueryManager queryManager) {
172         this.queryManager= queryManager;
173     }
174     
175     /***
176      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObject(java.lang.Class, java.lang.String)
177      * @throws org.apache.portals.graffito.jcr.exception.RepositoryException if the underlying repository
178      *  has thrown a javax.jcr.RepositoryException
179      * @throws JcrMappingException if the mapping for the class is not correct
180      * @throws PersistenceException if the object cannot be retrieved from the path
181      */
182     public Object getObject( String path) {
183         try {
184             if (!session.itemExists(path)) {
185                 return null;
186             }
187         }         
188         catch(RepositoryException e) {
189             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
190                     "Impossible to get the object at " + path, e);
191         }
192 
193         return objectConverter.getObject(session,  path);
194 
195     }
196 
197     /***
198      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObject(java.lang.Class, java.lang.String, java.lang.String)
199      */
200     public Object getObject( String path, String versionName) {
201         String pathVersion = null;
202         try {
203             if (!session.itemExists(path)) {
204                 return null;
205             }
206 
207             Version version = this.getVersion(path, versionName);
208             pathVersion = version.getPath() + "/jcr:frozenNode";
209 
210         } 
211         catch(RepositoryException e) {
212             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
213                     "Impossible to get the object at " + path + " - version :" + versionName,
214                     e);
215         }
216 
217         return objectConverter.getObject(session,  pathVersion);
218     }
219 
220     /***
221      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObject(java.lang.Class, java.lang.String)
222      * @throws org.apache.portals.graffito.jcr.exception.RepositoryException if the underlying repository
223      *  has thrown a javax.jcr.RepositoryException
224      * @throws JcrMappingException if the mapping for the class is not correct
225      * @throws PersistenceException if the object cannot be retrieved from the path
226      */
227     public Object getObject(Class objectClass, String path) {
228         try {
229             if (!session.itemExists(path)) {
230                 return null;
231             }
232         }         
233         catch(RepositoryException e) {
234             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
235                     "Impossible to get the object at " + path, e);
236         }
237 
238         return objectConverter.getObject(session, objectClass, path);
239 
240     }
241 
242     /***
243      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObject(java.lang.Class, java.lang.String, java.lang.String)
244      */
245     public Object getObject(Class objectClass, String path, String versionName) {
246         String pathVersion = null;
247         try {
248             if (!session.itemExists(path)) {
249                 return null;
250             }
251 
252             Version version = this.getVersion(path, versionName);
253             pathVersion = version.getPath() + "/jcr:frozenNode";
254 
255         } 
256         catch(RepositoryException e) {
257             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
258                     "Impossible to get the object at " + path + " - version :" + versionName,
259                     e);
260         }
261 
262         return objectConverter.getObject(session, objectClass, pathVersion);
263     }    
264     
265     /***
266      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#retrieveAllMappedAttributes(Object)
267      */
268     public void retrieveAllMappedAttributes(Object object) {
269 		objectConverter.retrieveAllMappedAttributes(session, object);
270       
271 	}
272 
273     /***
274      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#retrieveMappedAttribute(Object, String)
275      */    
276 	public void retrieveMappedAttribute(Object object, String attributeName) {
277 		objectConverter.retrieveMappedAttribute(session, object, attributeName);
278 		
279 	}
280 
281 	/***
282      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#insert(java.lang.Object)
283      */
284     public void insert(Object object) {
285         String path = objectConverter.getPath(session, object);
286 
287         try {
288             if (session.itemExists(path)) {
289                 Item item = session.getItem(path);
290                 if (item.isNode()) {
291                     if (!((Node) item).getDefinition().allowsSameNameSiblings()) {
292                         throw new PersistenceException("Path already exists and it is not supporting the same name sibling : "
293                                                        + path);
294                     }
295                 } 
296                 else {
297                     throw new PersistenceException("Path already exists and it is a property : "
298                                                    + path);
299                 }
300 
301             }
302         } 
303         catch(RepositoryException e) {
304             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
305                     "Impossible to insert the object at " + path, e);
306         }
307 
308         objectConverter.insert(session, object);
309     }
310 
311     /***
312      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#update(java.lang.Object)
313      */
314     public void update(Object object) {
315         String path = objectConverter.getPath(session, object);
316         try {
317             if (!session.itemExists(path)) {
318                 throw new PersistenceException("Path is not existing : " + path);
319             } 
320             else {
321                 checkIfNodeLocked(path);
322             }
323         } 
324         catch(javax.jcr.RepositoryException e) {
325             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Impossible to update", e);
326         }
327 
328         objectConverter.update(session, object);
329     }
330 
331     /***
332      *
333      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#remove(java.lang.String)
334      */
335     public void remove(String path) {
336         try {
337             if (!session.itemExists(path)) {
338                 throw new PersistenceException("Path does not exist : " + path);
339             } 
340             else {
341                 checkIfNodeLocked(path);
342             }
343 
344             Item item = session.getItem(path);
345             item.remove();
346 
347         } 
348         catch(RepositoryException e) {
349             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
350                     "Impossible to remove the object at " + path);
351         }
352     }
353 
354     /***
355      *
356      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#remove(java.lang.Object)
357      */
358     public void remove(Object object) {
359         this.remove(objectConverter.getPath(session, object));
360     }
361 
362     /***
363      *
364      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#remove(org.apache.portals.graffito.jcr.query.Query)
365      */
366     public void remove(Query query) {
367         try {
368             String jcrExpression = this.queryManager.buildJCRExpression(query);
369             log.debug("Remove Objects with expression : " + jcrExpression);
370 
371             javax.jcr.query.Query jcrQuery = session.getWorkspace().getQueryManager()
372                 .createQuery(jcrExpression, javax.jcr.query.Query.XPATH);
373             
374             QueryResult queryResult = jcrQuery.execute();
375             NodeIterator nodeIterator = queryResult.getNodes();
376             List nodes = new ArrayList();
377 
378             while (nodeIterator.hasNext()) {
379                 Node node = nodeIterator.nextNode();
380                 log.debug("Remove node : " + node.getPath());
381 
382                 // it is not possible to remove nodes from an NodeIterator
383                 // So, we add the node found in a collection to remove them after
384                 nodes.add(node);
385             }
386 
387             // Remove all collection nodes
388             for (int i = 0; i < nodes.size(); i++) {
389                 Node node = (Node) nodes.get(i);
390                 checkIfNodeLocked(node.getPath());
391                 try {
392                     node.remove();
393                 }
394                 catch(javax.jcr.RepositoryException re) {
395                     throw new PersistenceException("Cannot remove node at path " 
396                             + node.getPath() + " returned from query "
397                             + jcrExpression,
398                             re);
399                 }
400             }
401 
402         } 
403         catch(InvalidQueryException iqe) {
404             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Invalid query expression", iqe);
405         }
406         catch(RepositoryException e) {
407             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Impossible to get the object collection", e);
408         }
409     }
410 
411     /***
412      *
413      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#objectExists(java.lang.String)
414      */
415     public boolean objectExists(String path) {
416         try {
417             //TODO : Check also if it is an object
418             return session.itemExists(path);
419         } 
420         catch(RepositoryException e) {
421             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Impossible to check if the object exist", e);
422         }
423     }
424 
425     /***
426      *
427      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#isPersistent(java.lang.Class)
428      */
429     public boolean isPersistent(final Class clazz) {
430         boolean isPersistent = false;
431         ClassDescriptor classDescriptor = mapper.getClassDescriptorByClass(clazz);
432         if (classDescriptor != null) {
433             isPersistent = true;
434         }
435 
436         return isPersistent;
437     }
438 
439     /***
440      *
441      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObject(org.apache.portals.graffito.jcr.query.Query)
442      */
443     public Object getObject(Query query) {
444         try {
445             String jcrExpression = this.queryManager.buildJCRExpression(query);
446             log.debug("Get Object with expression : " + jcrExpression);
447 
448             javax.jcr.query.Query jcrQuery = session.getWorkspace().getQueryManager().createQuery(
449                     jcrExpression, javax.jcr.query.Query.XPATH);
450             QueryResult queryResult = jcrQuery.execute();
451             NodeIterator nodeIterator = queryResult.getNodes();
452 
453             if (nodeIterator.getSize() > 1) {
454                 throw new PersistenceException("Impossible to get the object - the query returns more than one object");
455             }
456 
457             Object object = null;
458             if (nodeIterator.hasNext()) {
459                 Node node = nodeIterator.nextNode();
460                 object = objectConverter.getObject(session, node.getPath());
461             }
462 
463             return object;
464         } 
465         catch(InvalidQueryException iqe) {
466             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Invalid query expression", iqe);
467         }
468         catch(RepositoryException e) {
469             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
470                     "Impossible to get the object collection", e);
471         }
472     }
473 
474     /***
475      *
476      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObjects(org.apache.portals.graffito.jcr.query.Query)
477      */
478     public Collection getObjects(Query query) {
479         try {
480             String jcrExpression = this.queryManager.buildJCRExpression(query);
481             log.debug("Get Objects with expression : " + jcrExpression);
482 
483             javax.jcr.query.Query jcrQuery = session.getWorkspace().getQueryManager()
484                 .createQuery(jcrExpression, javax.jcr.query.Query.XPATH);
485             QueryResult queryResult = jcrQuery.execute();
486             NodeIterator nodeIterator = queryResult.getNodes();
487 
488             List result = new ArrayList();
489             while (nodeIterator.hasNext()) {
490                 Node node = nodeIterator.nextNode();
491                 log.debug("Node found : " + node.getPath());
492                 result.add(objectConverter.getObject(session,  node.getPath()));
493             }
494 
495             return result;
496         } 
497         catch(InvalidQueryException iqe) {
498             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Invalid query expression", iqe);
499         }
500         catch(RepositoryException e) {
501             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
502                     "Impossible to get the object collection", e);
503         }
504     }
505 
506     /***
507      *
508      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getObjectIterator(org.apache.portals.graffito.jcr.query.Query)
509      */
510     public Iterator getObjectIterator(Query query) {
511         try {
512             String jcrExpression = this.queryManager.buildJCRExpression(query);
513             log.debug("Get Object with expression : " + jcrExpression);
514 
515             javax.jcr.query.Query jcrQuery = session.getWorkspace().getQueryManager()
516                 .createQuery(jcrExpression, javax.jcr.query.Query.XPATH);
517             QueryResult queryResult = jcrQuery.execute();
518             NodeIterator nodeIterator = queryResult.getNodes();
519 
520             return new ObjectIterator(nodeIterator,
521                                       query.getFilter().getFilterClass(),
522                                       this.objectConverter,
523                                       this.session);
524 
525         } 
526         catch(InvalidQueryException iqe) {
527             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Invalid query expression", iqe);
528         }
529         catch(RepositoryException e) {
530             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
531                     "Impossible to get the object collection", e);
532         }
533     }
534 
535     /***
536      *
537      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#checkin(java.lang.String)
538      */
539     public void checkin(String path) {
540         this.checkin(path, null);
541     }
542 
543     /***
544      *
545      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#checkin(java.lang.String, java.lang.String[])
546      */
547     public void checkin(String path, String[] versionLabels) {
548         try {
549             Node node = (Node) session.getItem(path);
550             checkIfNodeLocked(node.getPath());
551             if (!node.isNodeType("mix:versionable")) {
552                 throw new VersionException("The object " + path + "is not versionable");
553             }
554             javax.jcr.version.Version newVersion = node.checkin();
555 
556             if (versionLabels != null) {
557                 VersionHistory versionHistory = node.getVersionHistory();
558                 for (int i = 0; i < versionLabels.length; i++) {
559                     versionHistory.addVersionLabel(newVersion.getName(),
560                                                    versionLabels[i], false);
561                 }
562             }
563         } 
564         catch(ClassCastException cce) {
565             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
566         }
567         catch(PathNotFoundException pnfe) {
568             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
569         }
570         catch(InvalidItemStateException iise) {
571             throw new PersistenceException("Cannot checking modified object at path " + path, iise);
572         }
573         catch(javax.jcr.version.VersionException ve) {
574             throw new VersionException("Impossible to checkin the object " + path, ve);
575         }
576         catch(UnsupportedRepositoryOperationException uroe) {
577             throw new VersionException("Cannot checkin unversionable node at path " + path, uroe);
578         }
579         catch(LockException le) {
580             throw new VersionException("Cannot checkin locked node at path " + path, le);
581         }
582         catch (RepositoryException e) {
583             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
584                     "Impossible to checkin the object " + path, e);
585         }
586 
587     }
588 
589     /***
590      *
591      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#checkout(java.lang.String)
592      */
593     public void checkout(String path) {
594         Node node = null;
595         try {
596             node = (Node) session.getItem(path);
597             if (!node.isNodeType("mix:versionable")) {
598                 throw new VersionException("The object " + path + "is not versionable");
599             }
600 
601             node.checkout();
602         }         
603         catch(ClassCastException cce) {
604             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
605         }
606         catch(PathNotFoundException pnfe) {
607             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
608         }
609         catch(UnsupportedRepositoryOperationException uroe) {
610             throw new VersionException("Cannot checkout unversionable node at path " + path, uroe);
611         }
612         catch(LockException le) {
613             throw new VersionException("Cannot checkout locked node at path " + path, le);
614         }
615         catch(javax.jcr.RepositoryException e) {
616             throw new org.apache.portals.graffito.jcr.exception.RepositoryException("Impossible to checkout the object " + path, e);
617         }
618 
619     }
620 
621     /***
622      *
623      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#addVersionLabel(java.lang.String, java.lang.String, java.lang.String)
624      */
625     public void addVersionLabel(String path, String versionName, String versionLabel) {
626         try {
627             Node node = (Node) session.getItem(path);
628             checkIfNodeLocked(path);
629             if (!node.isNodeType("mix:versionable")) {
630                 throw new VersionException("The object " + path + "is not versionable");
631             }
632 
633             VersionHistory history = node.getVersionHistory();
634             history.addVersionLabel(versionName, versionLabel, false);
635         } 
636         catch(ClassCastException cce) {
637             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
638         }
639         catch(PathNotFoundException pnfe) {
640             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
641         }
642         catch(javax.jcr.version.VersionException ve) {
643             throw new VersionException("Impossible to add a new version label to  " + path
644                     + " - version name : " + versionName,
645                     ve);
646         }
647         catch(UnsupportedRepositoryOperationException uroe) {
648             throw new VersionException("Impossible to add a new version label to  " + path
649                     + " - version name : " + versionName,
650                     uroe);
651         }
652         catch(javax.jcr.RepositoryException e) {
653             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
654         }
655     }
656 
657     /***
658      *
659      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getVersion(java.lang.String, java.lang.String)
660      */
661     public Version getVersion(String path, String versionName) {
662         try {
663             Node node = (Node) session.getItem(path);
664             if (!node.isNodeType("mix:versionable")) {
665                 throw new VersionException("The object " + path + "is not versionable");
666             }
667 
668             VersionHistory history = node.getVersionHistory();
669 
670             return new Version(history.getVersion(versionName));
671         }
672         catch(ClassCastException cce) {
673             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
674         }
675         catch(PathNotFoundException pnfe) {
676             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
677         }
678         catch(javax.jcr.version.VersionException ve) {
679             throw new VersionException("The version name " + versionName + "does not exist", ve);
680         }
681         catch(UnsupportedRepositoryOperationException uroe) {
682             throw new VersionException("Impossible to retrieve versions for path " + path, uroe);
683         }
684         catch(javax.jcr.RepositoryException e) {
685             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
686         }
687     }
688 
689     /***
690      *
691      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getVersionLabels(java.lang.String, java.lang.String)
692      */
693     public String[] getVersionLabels(String path, String versionName) {
694         try {
695             Node node = (Node) session.getItem(path);
696             if (!node.isNodeType("mix:versionable")) {
697                 throw new VersionException("The object " + path + "is not versionable");
698             }
699 
700             VersionHistory history = node.getVersionHistory();
701             javax.jcr.version.Version version = history.getVersion(versionName);
702 
703             return history.getVersionLabels(version);
704         } 
705         catch(ClassCastException cce) {
706             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
707         }
708         catch(PathNotFoundException pnfe) {
709             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
710         }
711         catch(javax.jcr.version.VersionException ve) {
712             throw new VersionException("Impossible to get the version labels : " + path
713                     + " - version name : " + versionName,
714                     ve);
715         }
716         catch(UnsupportedRepositoryOperationException uroe) {
717             throw new VersionException("Impossible to retrieve versions for path " + path, uroe);
718         }
719         catch(RepositoryException e) {
720             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
721         }
722     }
723 
724     /***
725      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getAllVersionLabels(java.lang.String)
726      */
727     public String[] getAllVersionLabels(String path) {
728         try {
729             Node node = (Node) session.getItem(path);
730             if (!node.isNodeType("mix:versionable")) {
731                 throw new VersionException("The object " + path + "is not versionable");
732             }
733 
734             VersionHistory history = node.getVersionHistory();
735 
736             return history.getVersionLabels();
737         } 
738         catch(ClassCastException cce) {
739             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
740         }
741         catch(PathNotFoundException pnfe) {
742             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
743         }
744         catch(UnsupportedRepositoryOperationException uroe) {
745             throw new VersionException("Impossible to retrieve version history for path " + path, uroe);
746         }
747         catch(RepositoryException e) {
748             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
749         }
750     }
751 
752     /***
753      *
754      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getAllVersions(java.lang.String)
755      */
756     public VersionIterator getAllVersions(String path) {
757         try {
758             Node node = (Node) session.getItem(path);
759             if (!node.isNodeType("mix:versionable")) {
760                 throw new VersionException("The object " + path
761                                            + "is not versionable");
762             }
763 
764             VersionHistory history = node.getVersionHistory();
765 
766             return new VersionIterator(history.getAllVersions());
767         } 
768         catch(ClassCastException cce) {
769             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
770         }
771         catch(PathNotFoundException pnfe) {
772             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
773         }
774         catch(UnsupportedRepositoryOperationException uroe) {
775             throw new VersionException("Impossible to retrieve version history for path " + path, uroe);
776         }
777         catch(RepositoryException e) {
778             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
779         }
780     }
781 
782     /***
783      *
784      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getRootVersion(java.lang.String)
785      */
786     public Version getRootVersion(String path) {
787         try {
788             Node node = (Node) session.getItem(path);
789             if (!node.isNodeType("mix:versionable")) {
790                 throw new VersionException("The object " + path + "is not versionable");
791             }
792 
793             VersionHistory history = node.getVersionHistory();
794 
795             return new Version(history.getRootVersion());
796         } 
797         catch(ClassCastException cce) {
798             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
799         }
800         catch(PathNotFoundException pnfe) {
801             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
802         }
803         catch(UnsupportedRepositoryOperationException uroe) {
804             throw new VersionException("Impossible to get the root version  for the object " + path,
805                                        uroe);
806         }
807         catch(RepositoryException e) {
808             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
809         }
810     }
811 
812     /***
813      *
814      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getBaseVersion(java.lang.String)
815      */
816     public Version getBaseVersion(String path) {
817         try {
818             Node node = (Node) session.getItem(path);
819             if (!node.isNodeType("mix:versionable")) {
820                 throw new VersionException("The object " + path + "is not versionable");
821             }
822 
823             return new Version(node.getBaseVersion());
824         } 
825         catch(ClassCastException cce) {
826             throw new PersistenceException("Cannot retrieve an object from a property path " + path);
827         }
828         catch(PathNotFoundException pnfe) {
829             throw new PersistenceException("Cannot retrieve an object at path " + path, pnfe);
830         }
831         catch(UnsupportedRepositoryOperationException uroe) {
832             throw new VersionException("Impossible to get the base version for the object " + path,
833                                         uroe);
834         }
835         catch(javax.jcr.RepositoryException e) {
836             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e);
837         }
838     }
839 
840     /***
841      *
842      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#lock(java.lang.String, java.lang.Object, boolean, boolean)
843      */
844     public String lock(final String absPath, final boolean isDeep, final boolean isSessionScoped) 
845     throws LockedException {
846         try {
847 
848             // Calling this method will throw exception if node is locked
849             // and this operation cant be done (exception translation)
850             checkIfNodeLocked(absPath);
851 
852             Node node = getNode(absPath);
853             Lock lock = node.lock(isDeep, isSessionScoped);
854 
855             return lock.getLockToken();
856         } 
857         catch (LockException e) {
858             // Only one case with LockException remains: if node is not mix:lockable, propably error in custom node types definitions
859             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
860                     "Node of type is not type mix:lockable", e);
861         } 
862         catch (RepositoryException e) {
863             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e.getMessage(),
864                                                                                     e);
865         }
866     }
867 
868     /***
869      *
870      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#unlock(java.lang.String, java.lang.Object, java.lang.String)
871      */
872     public void unlock(final String absPath, final String lockToken) 
873     throws IllegalUnlockException {
874         String lockOwner = null;
875         try {
876             maybeAddLockToken(lockToken);
877 
878             Node node = getNode(absPath);
879             if (node.isLocked() == false) {
880                 // Safe - if not locked return
881                 return;
882             }
883 
884             Lock lock = node.getLock();
885             lockOwner = lock.getLockOwner();
886 
887             node.unlock();
888         } 
889         catch (LockException e) {
890             // LockException if this node does not currently hold a lock (see upper code)
891             // or holds a lock for which this Session does not have the correct lock token
892             log.error("Cannot unlock path: "
893                       + absPath
894                       + " Jcr user: "
895                       + session.getUserID()
896                       + " has no lock token to do this. Lock was placed with user: "
897                       + lockOwner);
898             throw new IllegalUnlockException(lockOwner, absPath);
899         } 
900         catch (RepositoryException e) {
901             // This also catch UnsupportedRepositoryOperationException - we assume that implementation supports it (jackrabbit does)
902             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(e.getMessage(),
903                                                                                     e);
904         }
905     }
906 
907     /***
908      *
909      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#isLocked(java.lang.String)
910      */
911     public boolean isLocked(final String absPath) {
912         try {
913             final Node node = getNode(absPath);
914 
915             return node.isLocked();
916         } 
917         catch (RepositoryException e) {
918             // node.isLocked() RepositoryException if an error occurs.
919             throw new org.apache.portals.graffito.jcr.exception.RepositoryException(
920                     "An exception was thrown while checking the lock at path : " + absPath, e);
921         }
922     }
923 
924     /***
925      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#getQueryManager()
926      */
927     public QueryManager getQueryManager() {
928         return this.queryManager;
929     }
930 
931     /***
932      * Throws {@link LockedException} id node is locked so alter nopde cannot be done
933      *
934      * @param absPath
935      *            abs path to node
936      * @throws RepositoryException
937      * @throws LockedException
938      *             if node is locked
939      */
940     protected void checkIfNodeLocked(final String absPath) throws RepositoryException, LockedException {
941         Node node = getNode(absPath);
942 
943         // Node can hold nock or can be locked with precedencor
944         if (node.isLocked()) {
945             Lock lock = node.getLock();
946             String lockOwner = lock.getLockOwner();
947             final String path = lock.getNode().getPath();
948             throw new LockedException(lockOwner, path);
949         }
950     }
951 
952     protected void maybeAddLockToken(final String lockToken) {
953         if (lockToken != null) {
954             // This user (this instance of PM) potentionally placed lock so
955             // session already has lock token
956             final String[] lockTokens = getSession().getLockTokens();
957             if (lockTokens != null) {
958                 for(int i= 0; i < lockTokens.length; i++) {
959                     if(lockTokens[i].equals(lockToken)) {
960                         // we are already holding a lock
961                         break;
962                     }
963                 }
964             } else {
965                 getSession().addLockToken(lockToken);
966             }
967         }
968     }
969 
970     protected Node getNode(final String absPath) throws PathNotFoundException, RepositoryException {
971         if (!getSession().itemExists(absPath)) {
972             throw new PersistenceException("No object stored on path: " + absPath);
973         }
974         Item item = getSession().getItem(absPath);
975         if (!item.isNode()) {
976             throw new PersistenceException("No object stored on path: " + absPath
977                                            + " on absPath is item (leaf)");
978         }
979 
980         return (Node) item;
981     }
982 
983     /***
984      *
985      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#logout()
986      */
987     public void logout() {
988         try {
989             log.debug("Logout. Persisting current session changes.");
990             this.session.save();
991             this.session.logout();
992             log.debug("Session closed");
993         }
994         catch(NoSuchNodeTypeException nsnte) {
995             throw new JcrMappingException(
996                     "Cannot persist current session changes. An unknown node type was used.", nsnte);
997         }
998         catch(javax.jcr.version.VersionException ve) {
999             throw new VersionException(
1000                     "Cannot persist current session changes. Attempt to overwrite checked-in node", ve);
1001         }
1002         catch(LockException le) {
1003             throw new PersistenceException(
1004                     "Cannot persist current session changes. Violation of a lock detected", le);
1005         }
1006         catch(javax.jcr.RepositoryException e) {
1007             throw new PersistenceException(
1008                     "Cannot persist current session changes.", e);
1009         }
1010     }
1011 
1012     /***
1013      *
1014      * @see org.apache.portals.graffito.jcr.persistence.PersistenceManager#save()
1015      */
1016     public void save() {
1017         try {
1018             this.session.save();
1019         }
1020         catch(NoSuchNodeTypeException nsnte) {
1021             throw new JcrMappingException(
1022                     "Cannot persist current session changes. An unknown node type was used.", nsnte);
1023         }
1024         catch(javax.jcr.version.VersionException ve) {
1025             throw new VersionException(
1026                     "Cannot persist current session changes. Attempt to overwrite checked-in node", ve);
1027         }
1028         catch(LockException le) {
1029             throw new PersistenceException(
1030                     "Cannot persist current session changes. Violation of a lock detected", le);
1031         }
1032         catch(RepositoryException e) {
1033             throw new PersistenceException(
1034                     "Cannot persist current session changes.", e);
1035         }
1036     }
1037 
1038     /***
1039      * @return The JCR Session
1040      */
1041     public Session getSession() {
1042         return this.session;
1043     }
1044 
1045 }