View Javadoc
1   /*
2    * Copyright (C) 2003-2009 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.services.cms.link;
18  
19  import java.io.InputStream;
20  import java.security.AccessControlException;
21  import java.util.Calendar;
22  import java.util.Map;
23  
24  import javax.jcr.AccessDeniedException;
25  import javax.jcr.InvalidItemStateException;
26  import javax.jcr.Item;
27  import javax.jcr.ItemExistsException;
28  import javax.jcr.ItemNotFoundException;
29  import javax.jcr.MergeException;
30  import javax.jcr.NoSuchWorkspaceException;
31  import javax.jcr.Node;
32  import javax.jcr.NodeIterator;
33  import javax.jcr.PathNotFoundException;
34  import javax.jcr.Property;
35  import javax.jcr.PropertyIterator;
36  import javax.jcr.ReferentialIntegrityException;
37  import javax.jcr.RepositoryException;
38  import javax.jcr.Session;
39  import javax.jcr.UnsupportedRepositoryOperationException;
40  import javax.jcr.Value;
41  import javax.jcr.ValueFormatException;
42  import javax.jcr.lock.Lock;
43  import javax.jcr.lock.LockException;
44  import javax.jcr.nodetype.ConstraintViolationException;
45  import javax.jcr.nodetype.NoSuchNodeTypeException;
46  import javax.jcr.nodetype.NodeDefinition;
47  import javax.jcr.nodetype.NodeType;
48  import javax.jcr.version.Version;
49  import javax.jcr.version.VersionException;
50  import javax.jcr.version.VersionHistory;
51  
52  import org.exoplatform.services.jcr.access.AccessControlList;
53  import org.exoplatform.services.jcr.core.ExtendedNode;
54  import org.exoplatform.services.jcr.datamodel.InternalQName;
55  import org.exoplatform.services.log.ExoLogger;
56  import org.exoplatform.services.log.Log;
57  import org.exoplatform.services.wcm.core.NodeLocation;
58  
59  /**
60   * Created by The eXo Platform SAS Author : eXoPlatform
61   * nicolas.filotto@exoplatform.com 31 mars 2009
62   */
63  public class NodeLinkAware extends ItemLinkAware implements ExtendedNode {
64  
65    final static public String    EXO_RESTORE_LOCATION = "exo:restoreLocation";
66  
67    /**
68     * Logger.
69     */
70    private static final Log LOG = ExoLogger.getLogger(NodeLinkAware.class.getName());
71  
72    private final NodeLocation    nodeLocation;
73  
74    private volatile NodeLocation targetNodeLocation;
75  
76    public NodeLinkAware(String originalWorkspace, String virtualPath, Node node) {
77      super(originalWorkspace, virtualPath, node);
78      this.nodeLocation = NodeLocation.getNodeLocationByNode(node);
79    }
80  
81    public String getRealPath() {
82      return nodeLocation.getPath();
83    }
84  
85    public Node getRealNode() {
86      return NodeLocation.getNodeByLocation(nodeLocation);
87    }
88  
89    public NodeLinkAware getTargetNode() throws RepositoryException {
90      return new NodeLinkAware(originalWorkspaceName, virtualPath, getTarget());
91    }
92  
93    public Session getNodeSession() throws RepositoryException {
94      return getRealNode().getSession();
95    }
96  
97    Node getTarget() throws RepositoryException {
98      Node targetNode = null;
99      if (targetNodeLocation == null) {
100       synchronized (this) {
101         if (targetNodeLocation == null) {
102           LinkManager linkManager = LinkUtils.getLinkManager();
103           Node node = getRealNode();
104           if (linkManager.isLink(node)) {
105             targetNode = linkManager.getTarget(node);
106           } else {
107             targetNode = node;
108           }
109         }
110       }
111     }
112     return targetNode;
113   }
114 
115   private Node getTargetReachable() throws RepositoryException {
116     try {
117       return getTarget();
118     } catch (AccessDeniedException e) {
119       if (LOG.isWarnEnabled()) {
120         LOG.warn("Cannot access to the target of the node " + nodeLocation.getPath());
121       }
122     } catch (ItemNotFoundException e) {
123       if (LOG.isWarnEnabled()) {
124         LOG.warn("The target of the node " + nodeLocation.getPath() + " doesn't exist anymore");
125       }
126     }
127     return null;
128   }
129 
130   private ExtendedNode getExtendedTarget() throws RepositoryException {
131     return (ExtendedNode) getTarget();
132   }
133 
134   private ExtendedNode getExtendedRealNode() {
135     return (ExtendedNode) getRealNode();
136   }
137 
138   private String getVirtualPath(String relativePath) {
139     return LinkUtils.createPath(virtualPath, relativePath);
140   }
141 
142   /**
143    * {@inheritDoc}
144    */
145   public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException,
146       ConstraintViolationException, LockException, RepositoryException {
147     getTarget().addMixin(mixinName);
148   }
149 
150   /**
151    * {@inheritDoc}
152    */
153   public Node addNode(String relPath) throws ItemExistsException, PathNotFoundException,
154       VersionException, ConstraintViolationException, LockException, RepositoryException {
155     return new NodeLinkAware(originalWorkspaceName, getVirtualPath(relPath), getTarget().addNode(
156         relPath));
157   }
158 
159   /**
160    * {@inheritDoc}
161    */
162   public Node addNode(String relPath, String primaryNodeTypeName) throws ItemExistsException,
163       PathNotFoundException, NoSuchNodeTypeException, LockException, VersionException,
164       ConstraintViolationException, RepositoryException {
165     return new NodeLinkAware(originalWorkspaceName, getVirtualPath(relPath), getTarget().addNode(
166         relPath, primaryNodeTypeName));
167   }
168 
169   /**
170    * {@inheritDoc}
171    */
172   public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException {
173     return getTarget().canAddMixin(mixinName);
174   }
175 
176   /**
177    * {@inheritDoc}
178    */
179   public void cancelMerge(Version version) throws VersionException, InvalidItemStateException,
180       UnsupportedRepositoryOperationException, RepositoryException {
181     getTarget().cancelMerge(version);
182   }
183 
184   /**
185    * {@inheritDoc}
186    */
187   public Version checkin() throws VersionException, UnsupportedRepositoryOperationException,
188       InvalidItemStateException, LockException, RepositoryException {
189     return getTarget().checkin();
190   }
191 
192   /**
193    * {@inheritDoc}
194    */
195   public void checkout() throws UnsupportedRepositoryOperationException, LockException,
196       RepositoryException {
197     getTarget().checkout();
198   }
199 
200   /**
201    * {@inheritDoc}
202    */
203   public void doneMerge(Version version) throws VersionException, InvalidItemStateException,
204       UnsupportedRepositoryOperationException, RepositoryException {
205     getTarget().doneMerge(version);
206   }
207 
208   /**
209    * {@inheritDoc}
210    */
211   public Version getBaseVersion() throws UnsupportedRepositoryOperationException,
212       RepositoryException {
213     return getTarget().getBaseVersion();
214   }
215 
216   /**
217    * {@inheritDoc}
218    */
219   public String getCorrespondingNodePath(String workspaceName) throws ItemNotFoundException,
220       NoSuchWorkspaceException, AccessDeniedException, RepositoryException {
221     return getTarget().getCorrespondingNodePath(workspaceName);
222   }
223 
224   /**
225    * {@inheritDoc}
226    */
227   public NodeDefinition getDefinition() throws RepositoryException {
228     return getTarget().getDefinition();
229   }
230 
231   /**
232    * {@inheritDoc}
233    */
234   public int getIndex() throws RepositoryException {
235     return getRealNode().getIndex();
236   }
237 
238   /**
239    * {@inheritDoc}
240    */
241   public Lock getLock() throws UnsupportedRepositoryOperationException, LockException,
242       AccessDeniedException, RepositoryException {
243     return getTarget().getLock();
244   }
245 
246   /**
247    * {@inheritDoc}
248    */
249   public NodeType[] getMixinNodeTypes() throws RepositoryException {
250     return getTarget().getMixinNodeTypes();
251   }
252 
253   /**
254    * {@inheritDoc}
255    */
256   public Node getNode(String relPath) throws PathNotFoundException, RepositoryException {
257     return new NodeLinkAware(originalWorkspaceName, getVirtualPath(relPath), (Node) LinkUtils
258         .getNodeFinder().getItem(getNodeSession(), getVirtualPath(relPath)));
259   }
260 
261   /**
262    * {@inheritDoc}
263    */
264   public NodeIterator getNodes() throws RepositoryException {
265     return new NodeIteratorLinkAware(originalWorkspaceName, virtualPath, getTarget().getNodes());
266   }
267 
268   /**
269    * {@inheritDoc}
270    */
271   public NodeIterator getNodes(String namePattern) throws RepositoryException {
272     return new NodeIteratorLinkAware(originalWorkspaceName, virtualPath, getTarget().getNodes(
273         namePattern));
274   }
275 
276   /**
277    * {@inheritDoc}
278    */
279   public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException {
280     return ItemLinkAware.newInstance(originalWorkspaceName, getVirtualPath(super.getName()),
281         getTarget().getPrimaryItem());
282   }
283 
284   /**
285    * {@inheritDoc}
286    */
287   public NodeType getPrimaryNodeType() throws RepositoryException {
288     return new NodeTypeLinkAware(this);
289   }
290 
291   /**
292    * {@inheritDoc}
293    */
294   public PropertyIterator getProperties() throws RepositoryException {
295     return new PropertyIteratorLinkAware(originalWorkspaceName, virtualPath, getTarget()
296         .getProperties());
297   }
298 
299   /**
300    * {@inheritDoc}
301    */
302   public PropertyIterator getProperties(String namePattern) throws RepositoryException {
303     return new PropertyIteratorLinkAware(originalWorkspaceName, virtualPath, getTarget()
304         .getProperties(namePattern));
305   }
306 
307   /**
308    * {@inheritDoc}
309    */
310   public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException {
311     String path = getVirtualPath(relPath);
312     return new PropertyLinkAware(originalWorkspaceName, path, (Property) LinkUtils.getNodeFinder()
313         .getItem(getOriginalSession(), path));
314   }
315 
316   /**
317    * {@inheritDoc}
318    */
319   public PropertyIterator getReferences() throws RepositoryException {
320     return getTarget().getReferences();
321   }
322 
323   /**
324    * {@inheritDoc}
325    */
326   public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException {
327     return getTarget().getUUID();
328   }
329 
330   /**
331    * {@inheritDoc}
332    */
333   public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException,
334       RepositoryException {
335     return getTarget().getVersionHistory();
336   }
337 
338   /**
339    * {@inheritDoc}
340    */
341   public boolean hasNode(String relPath) throws RepositoryException {
342     try {
343       return LinkUtils.getNodeFinder().getItem(getOriginalSession(), getVirtualPath(relPath)) instanceof Node;
344     } catch (PathNotFoundException e) {
345       return false;
346     }
347   }
348 
349   /**
350    * {@inheritDoc}
351    */
352   public boolean hasNodes() throws RepositoryException {
353     return getTarget().hasNodes();
354   }
355 
356   /**
357    * {@inheritDoc}
358    */
359   public boolean hasProperties() throws RepositoryException {
360     return getTarget().hasProperties();
361   }
362 
363   /**
364    * {@inheritDoc}
365    */
366   public boolean hasProperty(String relPath) throws RepositoryException {
367     try {
368       return LinkUtils.getNodeFinder().getItem(getOriginalSession(), getVirtualPath(relPath)) instanceof Property;
369     } catch (PathNotFoundException e) {
370       return false;
371     }
372   }
373 
374   /**
375    * {@inheritDoc}
376    */
377   public boolean holdsLock() throws RepositoryException {
378     Node node = getTargetReachable();
379     return node == null ? false : node.holdsLock();
380   }
381 
382   /**
383    * {@inheritDoc}
384    */
385   public boolean isCheckedOut() throws RepositoryException {
386     Node node = getTargetReachable();
387     return node == null ? false : node.isCheckedOut();
388   }
389 
390   /**
391    * {@inheritDoc}
392    */
393   public boolean isLocked() throws RepositoryException {
394     Node node = getTargetReachable();
395     return node == null ? false : node.isLocked();
396   }
397 
398   /**
399    * {@inheritDoc}
400    */
401   public boolean isNodeType(String nodeTypeName) throws RepositoryException {
402     if (EXO_RESTORE_LOCATION.equals(nodeTypeName))
403       return this.getRealNode().isNodeType(nodeTypeName);
404     Node node = getTargetReachable();
405     return node == null ? false : node.isNodeType(nodeTypeName);
406   }
407 
408   /**
409    * {@inheritDoc}
410    */
411   public Lock lock(boolean isDeep, boolean isSessionScoped)
412       throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException,
413       InvalidItemStateException, RepositoryException {
414     return getTarget().lock(isDeep, isSessionScoped);
415   }
416 
417   /**
418    * {@inheritDoc}
419    */
420   public NodeIterator merge(String srcWorkspace, boolean bestEffort)
421       throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException,
422       InvalidItemStateException, RepositoryException {
423     return getTarget().merge(srcWorkspace, bestEffort);
424   }
425 
426   /**
427    * {@inheritDoc}
428    */
429   public void orderBefore(String srcChildRelPath, String destChildRelPath)
430       throws UnsupportedRepositoryOperationException, VersionException,
431       ConstraintViolationException, ItemNotFoundException, LockException, RepositoryException {
432     getTarget().orderBefore(srcChildRelPath, destChildRelPath);
433   }
434 
435   /**
436    * {@inheritDoc}
437    */
438   public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException,
439       ConstraintViolationException, LockException, RepositoryException {
440     getTarget().removeMixin(mixinName);
441   }
442 
443   /**
444    * {@inheritDoc}
445    */
446   public void restore(String versionName, boolean removeExisting) throws VersionException,
447       ItemExistsException, UnsupportedRepositoryOperationException, LockException,
448       InvalidItemStateException, RepositoryException {
449     getTarget().restore(versionName, removeExisting);
450   }
451 
452   /**
453    * {@inheritDoc}
454    */
455   public void restore(Version version, boolean removeExisting) throws VersionException,
456       ItemExistsException, UnsupportedRepositoryOperationException, LockException,
457       RepositoryException {
458     getTarget().restore(version, removeExisting);
459   }
460 
461   /**
462    * {@inheritDoc}
463    */
464   public void restore(Version version, String relPath, boolean removeExisting)
465       throws PathNotFoundException, ItemExistsException, VersionException,
466       ConstraintViolationException, UnsupportedRepositoryOperationException, LockException,
467       InvalidItemStateException, RepositoryException {
468     getTarget().restore(version, relPath, removeExisting);
469   }
470 
471   /**
472    * {@inheritDoc}
473    */
474   public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException,
475       ItemExistsException, UnsupportedRepositoryOperationException, LockException,
476       InvalidItemStateException, RepositoryException {
477     getTarget().restoreByLabel(versionLabel, removeExisting);
478   }
479 
480   /**
481    * {@inheritDoc}
482    */
483   public Property setProperty(String name, Value value) throws ValueFormatException,
484       VersionException, LockException, ConstraintViolationException, RepositoryException {
485     return getTarget().setProperty(name, value);
486   }
487 
488   /**
489    * {@inheritDoc}
490    */
491   public Property setProperty(String name, Value[] values) throws ValueFormatException,
492       VersionException, LockException, ConstraintViolationException, RepositoryException {
493     return getTarget().setProperty(name, values);
494   }
495 
496   /**
497    * {@inheritDoc}
498    */
499   public Property setProperty(String name, String[] values) throws ValueFormatException,
500       VersionException, LockException, ConstraintViolationException, RepositoryException {
501     return getTarget().setProperty(name, values);
502   }
503 
504   /**
505    * {@inheritDoc}
506    */
507   public Property setProperty(String name, String value) throws ValueFormatException,
508       VersionException, LockException, ConstraintViolationException, RepositoryException {
509     return getTarget().setProperty(name, value);
510   }
511 
512   /**
513    * {@inheritDoc}
514    */
515   public Property setProperty(String name, InputStream value) throws ValueFormatException,
516       VersionException, LockException, ConstraintViolationException, RepositoryException {
517     return getTarget().setProperty(name, value);
518   }
519 
520   /**
521    * {@inheritDoc}
522    */
523   public Property setProperty(String name, boolean value) throws ValueFormatException,
524       VersionException, LockException, ConstraintViolationException, RepositoryException {
525     return getTarget().setProperty(name, value);
526   }
527 
528   /**
529    * {@inheritDoc}
530    */
531   public Property setProperty(String name, double value) throws ValueFormatException,
532       VersionException, LockException, ConstraintViolationException, RepositoryException {
533     return getTarget().setProperty(name, value);
534   }
535 
536   /**
537    * {@inheritDoc}
538    */
539   public Property setProperty(String name, long value) throws ValueFormatException,
540       VersionException, LockException, ConstraintViolationException, RepositoryException {
541     return getTarget().setProperty(name, value);
542   }
543 
544   /**
545    * {@inheritDoc}
546    */
547   public Property setProperty(String name, Calendar value) throws ValueFormatException,
548       VersionException, LockException, ConstraintViolationException, RepositoryException {
549     return getTarget().setProperty(name, value);
550   }
551 
552   /**
553    * {@inheritDoc}
554    */
555   public Property setProperty(String name, Node value) throws ValueFormatException,
556       VersionException, LockException, ConstraintViolationException, RepositoryException {
557     return getTarget().setProperty(name, value);
558   }
559 
560   /**
561    * {@inheritDoc}
562    */
563   public Property setProperty(String name, Value value, int type) throws ValueFormatException,
564       VersionException, LockException, ConstraintViolationException, RepositoryException {
565     return getTarget().setProperty(name, value, type);
566   }
567 
568   /**
569    * {@inheritDoc}
570    */
571   public Property setProperty(String name, Value[] values, int type) throws ValueFormatException,
572       VersionException, LockException, ConstraintViolationException, RepositoryException {
573     return getTarget().setProperty(name, values, type);
574   }
575 
576   /**
577    * {@inheritDoc}
578    */
579   public Property setProperty(String name, String[] values, int type) throws ValueFormatException,
580       VersionException, LockException, ConstraintViolationException, RepositoryException {
581     return getTarget().setProperty(name, values, type);
582   }
583 
584   /**
585    * {@inheritDoc}
586    */
587   public Property setProperty(String name, String value, int type) throws ValueFormatException,
588       VersionException, LockException, ConstraintViolationException, RepositoryException {
589     return getTarget().setProperty(name, value, type);
590   }
591 
592   /**
593    * {@inheritDoc}
594    */
595   public void unlock() throws UnsupportedRepositoryOperationException, LockException,
596       AccessDeniedException, InvalidItemStateException, RepositoryException {
597     getTarget().unlock();
598   }
599 
600   /**
601    * {@inheritDoc}
602    */
603   public void update(String srcWorkspaceName) throws NoSuchWorkspaceException,
604       AccessDeniedException, LockException, InvalidItemStateException, RepositoryException {
605     getTarget().update(srcWorkspaceName);
606   }
607 
608   /**
609    * {@inheritDoc}
610    */
611   public void save() throws AccessDeniedException, ItemExistsException,
612       ConstraintViolationException, InvalidItemStateException, ReferentialIntegrityException,
613       VersionException, LockException, NoSuchNodeTypeException, RepositoryException {
614     getTarget().save();
615   }
616 
617   /**
618    * {@inheritDoc}
619    */
620   public void checkPermission(String actions) throws AccessControlException, RepositoryException {
621     getExtendedRealNode().checkPermission(actions);
622   }
623 
624   /**
625    * {@inheritDoc}
626    */
627   public void clearACL() throws RepositoryException, AccessControlException {
628     getExtendedRealNode().clearACL();
629   }
630 
631   /**
632    * {@inheritDoc}
633    */
634   public AccessControlList getACL() throws RepositoryException {
635     return getExtendedRealNode().getACL();
636   }
637 
638   /**
639    * {@inheritDoc}
640    */
641   public boolean isNodeType(InternalQName name) throws RepositoryException {
642     ExtendedNode node = (ExtendedNode) getTargetReachable();
643     return node == null ? false : node.isNodeType(name);
644   }
645 
646   /**
647    * {@inheritDoc}
648    */
649   public Lock lock(boolean isDeep, long timeOut) throws UnsupportedRepositoryOperationException,
650       LockException, AccessDeniedException, InvalidItemStateException, RepositoryException {
651     return getExtendedTarget().lock(isDeep, timeOut);
652   }
653 
654   /**
655    * {@inheritDoc}
656    */
657   public void removePermission(String identity) throws RepositoryException, AccessControlException {
658     getExtendedRealNode().removePermission(identity);
659   }
660 
661   /**
662    * {@inheritDoc}
663    */
664   public void removePermission(String identity, String permission) throws RepositoryException,
665       AccessControlException {
666     getExtendedRealNode().removePermission(identity, permission);
667   }
668 
669   /**
670    * {@inheritDoc}
671    */
672   public void setPermission(String identity, String[] permission) throws RepositoryException,
673       AccessControlException {
674     getExtendedRealNode().setPermission(identity, permission);
675   }
676 
677   /**
678    * {@inheritDoc}
679    */
680   public void setPermissions(Map<String, String[]> permissions) throws RepositoryException,
681       AccessControlException {
682     getExtendedRealNode().setPermissions(permissions);
683   }
684 
685   /**
686    * {@inheritDoc}
687    */
688   public String getIdentifier() throws RepositoryException {
689     ExtendedNode node = (ExtendedNode) getTarget();
690     return node.getIdentifier();
691   }
692 
693   /**
694    * {@inheritDoc}
695    */
696   public NodeIterator getNodesLazily() throws RepositoryException {
697     ExtendedNode node = (ExtendedNode) getTarget();
698     return node.getNodesLazily();
699   }
700 
701   @Override
702   public NodeIterator getNodesLazily(int pageSize) throws RepositoryException {
703     ExtendedNode node = (ExtendedNode) getTarget();
704     return node.getNodesLazily(pageSize);
705   }
706 
707   @Override
708   public long getNodesCount() throws RepositoryException {
709     ExtendedNode node = (ExtendedNode) getTarget();
710     return node.getNodesCount();
711   }
712 }