KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > service > cmr > repository > TemplateNode


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.service.cmr.repository;
18
19 import java.io.Serializable JavaDoc;
20 import java.io.StringReader JavaDoc;
21 import java.io.UnsupportedEncodingException JavaDoc;
22 import java.net.URLEncoder JavaDoc;
23 import java.text.MessageFormat JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import org.alfresco.model.ContentModel;
30 import org.alfresco.repo.security.permissions.AccessDeniedException;
31 import org.alfresco.repo.template.LuceneSearchResultsMap;
32 import org.alfresco.repo.template.NamePathResultsMap;
33 import org.alfresco.repo.template.SavedSearchResultsMap;
34 import org.alfresco.repo.template.XPathResultsMap;
35 import org.alfresco.service.ServiceRegistry;
36 import org.alfresco.service.cmr.dictionary.DictionaryService;
37 import org.alfresco.service.cmr.lock.LockStatus;
38 import org.alfresco.service.namespace.QName;
39 import org.alfresco.service.namespace.QNameMap;
40 import org.alfresco.service.namespace.RegexQNamePattern;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.springframework.util.StringUtils;
44 import org.xml.sax.InputSource JavaDoc;
45
46 import freemarker.ext.dom.NodeModel;
47
48 /**
49  * Node class specific for use by Template pages that support Bean objects as part of the model.
50  * The default template engine FreeMarker can use these objects and they are provided to support it.
51  * A single method is completely freemarker specific - getXmlNodeModel()
52  * <p>
53  * The class exposes Node properties, children as dynamically populated maps and lists.
54  * <p>
55  * Various helper methods are provided to access common and useful node variables such
56  * as the content url and type information.
57  *
58  * @author Kevin Roast
59  */

60 public final class TemplateNode implements Serializable JavaDoc
61 {
62     private static final long serialVersionUID = 1234390333739034171L;
63     
64     private static Log logger = LogFactory.getLog(TemplateNode.class);
65     
66     private final static String JavaDoc NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN;
67     private final static String JavaDoc CONTENT_DEFAULT_URL = "/download/direct/{0}/{1}/{2}/{3}";
68     private final static String JavaDoc CONTENT_PROP_URL = "/download/direct/{0}/{1}/{2}/{3}?property={4}";
69     
70     /** The children of this node */
71     private List JavaDoc<TemplateNode> children = null;
72     
73     /** The associations from this node */
74     private Map JavaDoc<String JavaDoc, List JavaDoc<TemplateNode>> assocs = null;
75     
76     /** Cached values */
77     private NodeRef nodeRef;
78     private String JavaDoc name;
79     private QName type;
80     private String JavaDoc path;
81     private String JavaDoc id;
82     private Set JavaDoc<QName> aspects = null;
83     private QNameMap<String JavaDoc, Object JavaDoc> properties;
84     private boolean propsRetrieved = false;
85     private ServiceRegistry services = null;
86     private Boolean JavaDoc isDocument = null;
87     private Boolean JavaDoc isContainer = null;
88     private String JavaDoc displayPath = null;
89     private String JavaDoc mimetype = null;
90     private Long JavaDoc size = null;
91     private TemplateImageResolver imageResolver = null;
92     private TemplateNode parent = null;
93     
94     
95     /**
96      * Constructor
97      *
98      * @param nodeRef The NodeRef this Node wrapper represents
99      * @param services The ServiceRegistry the TemplateNode can use to access services
100      * @param resolver Image resolver to use to retrieve icons
101      */

102     public TemplateNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver)
103     {
104         if (nodeRef == null)
105         {
106             throw new IllegalArgumentException JavaDoc("NodeRef must be supplied.");
107         }
108       
109         if (services == null)
110         {
111             throw new IllegalArgumentException JavaDoc("The ServiceRegistry must be supplied.");
112         }
113         
114         this.nodeRef = nodeRef;
115         this.id = nodeRef.getId();
116         this.services = services;
117         this.imageResolver = resolver;
118         
119         this.properties = new QNameMap<String JavaDoc, Object JavaDoc>(this.services.getNamespaceService());
120     }
121     
122     /**
123      * @return The GUID for the node
124      */

125     public String JavaDoc getId()
126     {
127         return this.id;
128     }
129     
130     /**
131      * @return Returns the NodeRef this Node object represents
132      */

133     public NodeRef getNodeRef()
134     {
135         return this.nodeRef;
136     }
137     
138     /**
139      * @return Returns the type.
140      */

141     public QName getType()
142     {
143         if (this.type == null)
144         {
145             this.type = this.services.getNodeService().getType(this.nodeRef);
146         }
147         
148         return type;
149     }
150     
151     /**
152      * @return The display name for the node
153      */

154     public String JavaDoc getName()
155     {
156         if (this.name == null)
157         {
158             // try and get the name from the properties first
159
this.name = (String JavaDoc)getProperties().get("cm:name");
160             
161             // if we didn't find it as a property get the name from the association name
162
if (this.name == null)
163             {
164                 ChildAssociationRef parentRef = this.services.getNodeService().getPrimaryParent(this.nodeRef);
165                 if (parentRef != null && parentRef.getQName() != null)
166                 {
167                     this.name = parentRef.getQName().getLocalName();
168                 }
169                 else
170                 {
171                     this.name = "";
172                 }
173             }
174         }
175         
176         return this.name;
177     }
178     
179     /**
180      * @return The children of this Node as TemplateNode wrappers
181      */

182     public List JavaDoc<TemplateNode> getChildren()
183     {
184         if (this.children == null)
185         {
186             List JavaDoc<ChildAssociationRef> childRefs = this.services.getNodeService().getChildAssocs(this.nodeRef);
187             this.children = new ArrayList JavaDoc<TemplateNode>(childRefs.size());
188             for (ChildAssociationRef ref : childRefs)
189             {
190                 // create our Node representation from the NodeRef
191
TemplateNode child = new TemplateNode(ref.getChildRef(), this.services, this.imageResolver);
192                 this.children.add(child);
193             }
194         }
195         
196         return this.children;
197     }
198     
199     /**
200      * @return A map capable of returning the TemplateNode at the specified Path as a child of this node.
201      */

202     public Map JavaDoc getChildByNamePath()
203     {
204         return new NamePathResultsMap(this, this.services);
205     }
206     
207     /**
208      * @return A map capable of returning a List of TemplateNode objects from an XPath query
209      * as children of this node.
210      */

211     public Map JavaDoc getChildrenByXPath()
212     {
213         return new XPathResultsMap(this, this.services);
214     }
215     
216     /**
217      * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Saved Search
218      * object. The Saved Search is executed and the resulting nodes supplied as a sequence.
219      */

220     public Map JavaDoc getChildrenBySavedSearch()
221     {
222         return new SavedSearchResultsMap(this, this.services);
223     }
224     
225     /**
226      * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Lucene search
227      * string. The Saved Search is executed and the resulting nodes supplied as a sequence.
228      */

229     public Map JavaDoc getChildrenByLuceneSearch()
230     {
231         return new LuceneSearchResultsMap(this, this.services);
232     }
233     
234     /**
235      * @return The associations for this Node. As a Map of assoc name to a List of TemplateNodes.
236      */

237     public Map JavaDoc<String JavaDoc, List JavaDoc<TemplateNode>> getAssocs()
238     {
239         if (this.assocs == null)
240         {
241             List JavaDoc<AssociationRef> refs = this.services.getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
242             this.assocs = new QNameMap<String JavaDoc, List JavaDoc<TemplateNode>>(this.services.getNamespaceService());
243             for (AssociationRef ref : refs)
244             {
245                 String JavaDoc qname = ref.getTypeQName().toString();
246                 List JavaDoc<TemplateNode> nodes = assocs.get(qname);
247                 if (nodes == null)
248                 {
249                     // first access for the list for this qname
250
nodes = new ArrayList JavaDoc<TemplateNode>(4);
251                     this.assocs.put(ref.getTypeQName().toString(), nodes);
252                 }
253                 nodes.add( new TemplateNode(ref.getTargetRef(), this.services, this.imageResolver) );
254             }
255         }
256         
257         return this.assocs;
258     }
259     
260     /**
261      * @return All the properties known about this node.
262      */

263     public Map JavaDoc<String JavaDoc, Object JavaDoc> getProperties()
264     {
265         if (this.propsRetrieved == false)
266         {
267             Map JavaDoc<QName, Serializable JavaDoc> props = this.services.getNodeService().getProperties(this.nodeRef);
268             
269             for (QName qname : props.keySet())
270             {
271                 Serializable JavaDoc propValue = props.get(qname);
272                 if (propValue instanceof NodeRef)
273                 {
274                     // NodeRef object properties are converted to new TemplateNode objects
275
// so they can be used as objects within a template
276
propValue = new TemplateNode(((NodeRef)propValue), this.services, this.imageResolver);
277                 }
278                 else if (propValue instanceof ContentData)
279                 {
280                     // ContentData object properties are converted to TemplateContentData objects
281
// so the content and other properties of those objects can be accessed
282
propValue = new TemplateContentData((ContentData)propValue, qname);
283                 }
284                 this.properties.put(qname.toString(), propValue);
285             }
286             
287             this.propsRetrieved = true;
288         }
289         
290         return this.properties;
291     }
292     
293     /**
294      * @return true if this Node is a container (i.e. a folder)
295      */

296     public boolean getIsContainer()
297     {
298         if (isContainer == null)
299         {
300             DictionaryService dd = this.services.getDictionaryService();
301             isContainer = Boolean.valueOf( (dd.isSubClass(getType(), ContentModel.TYPE_FOLDER) == true &&
302                     dd.isSubClass(getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false) );
303         }
304         
305         return isContainer.booleanValue();
306     }
307     
308     /**
309      * @return true if this Node is a Document (i.e. with content)
310      */

311     public boolean getIsDocument()
312     {
313         if (isDocument == null)
314         {
315             DictionaryService dd = this.services.getDictionaryService();
316             isDocument = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CONTENT));
317         }
318         
319         return isDocument.booleanValue();
320     }
321     
322     /**
323      * @return The list of aspects applied to this node
324      */

325     public Set JavaDoc<QName> getAspects()
326     {
327         if (this.aspects == null)
328         {
329             this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
330         }
331         
332         return this.aspects;
333     }
334     
335     /**
336      * @param aspect The aspect name to test for
337      *
338      * @return true if the node has the aspect false otherwise
339      */

340     public boolean hasAspect(String JavaDoc aspect)
341     {
342         if (this.aspects == null)
343         {
344             this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
345         }
346         
347         if (aspect.startsWith(NAMESPACE_BEGIN))
348         {
349             return aspects.contains((QName.createQName(aspect)));
350         }
351         else
352         {
353             boolean found = false;
354             for (QName qname : this.aspects)
355             {
356                 if (qname.toPrefixString(this.services.getNamespaceService()).equals(aspect))
357                 {
358                     found = true;
359                     break;
360                 }
361             }
362             return found;
363         }
364     }
365     
366     /**
367      * @return FreeMarker NodeModel for the XML content of this node, or null if no parsable XML found
368      */

369     public NodeModel getXmlNodeModel()
370     {
371        try
372        {
373           return NodeModel.parse(new InputSource JavaDoc(new StringReader JavaDoc(getContent())));
374        }
375        catch (Throwable JavaDoc err)
376        {
377           if (logger.isDebugEnabled())
378              logger.debug(err.getMessage(), err);
379           
380           return null;
381        }
382     }
383     
384     /**
385      * @return Display path to this node
386      */

387     public String JavaDoc getDisplayPath()
388     {
389         if (displayPath == null)
390         {
391             try
392             {
393                 displayPath = this.services.getNodeService().getPath(this.nodeRef).toDisplayPath(this.services.getNodeService());
394             }
395             catch (AccessDeniedException err)
396             {
397                 displayPath = "";
398             }
399         }
400         
401         return displayPath;
402     }
403     
404     /**
405      * @return the small icon image for this node
406      */

407     public String JavaDoc getIcon16()
408     {
409         if (this.imageResolver != null)
410         {
411             if (getIsDocument())
412             {
413                 return this.imageResolver.resolveImagePathForName(getName(), true);
414             }
415             else
416             {
417                 return "/images/icons/space_small.gif";
418             }
419         }
420         else
421         {
422             return "/images/filetypes/_default.gif";
423         }
424     }
425     
426     /**
427      * @return the large icon image for this node
428      */

429     public String JavaDoc getIcon32()
430     {
431         if (this.imageResolver != null)
432         {
433             if (getIsDocument())
434             {
435                 return this.imageResolver.resolveImagePathForName(getName(), false);
436             }
437             else
438             {
439                 String JavaDoc icon = (String JavaDoc)getProperties().get("app:icon");
440                 if (icon != null)
441                 {
442                     return "/images/icons/" + icon + ".gif";
443                 }
444                 else
445                 {
446                     return "/images/icons/space-icon-default.gif";
447                 }
448             }
449         }
450         else
451         {
452             return "/images/filetypes32/_default.gif";
453         }
454     }
455     
456     /**
457      * @return true if the node is currently locked
458      */

459     public boolean getIsLocked()
460     {
461         boolean locked = false;
462         
463         if (getAspects().contains(ContentModel.ASPECT_LOCKABLE))
464         {
465             LockStatus lockStatus = this.services.getLockService().getLockStatus(this.nodeRef);
466             if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
467             {
468                 locked = true;
469             }
470         }
471         
472         return locked;
473     }
474     
475     /**
476      * @return the parent node
477      */

478     public TemplateNode getParent()
479     {
480         if (parent == null)
481         {
482             NodeRef parentRef = this.services.getNodeService().getPrimaryParent(nodeRef).getParentRef();
483             // handle root node (no parent!)
484
if (parentRef != null)
485             {
486                 parent = new TemplateNode(parentRef, this.services, this.imageResolver);
487             }
488         }
489         
490         return parent;
491     }
492     
493     /**
494      * @return the content String for this node from the default content property
495      * (@see ContentModel.PROP_CONTENT)
496      */

497     public String JavaDoc getContent()
498     {
499         ContentService contentService = this.services.getContentService();
500         ContentReader reader = contentService.getReader(this.nodeRef, ContentModel.PROP_CONTENT);
501         return (reader != null && reader.exists()) ? reader.getContentString() : "";
502     }
503     
504     /**
505      * @return url to the content stream for this node for the default content property
506      * (@see ContentModel.PROP_CONTENT)
507      */

508     public String JavaDoc getUrl()
509     {
510         try
511         {
512             return MessageFormat.format(CONTENT_DEFAULT_URL, new Object JavaDoc[] {
513                     nodeRef.getStoreRef().getProtocol(),
514                     nodeRef.getStoreRef().getIdentifier(),
515                     nodeRef.getId(),
516                     StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } );
517         }
518         catch (UnsupportedEncodingException JavaDoc err)
519         {
520             throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
521         }
522     }
523     
524     /**
525      * @return The mimetype encoding for content attached to the node from the default content property
526      * (@see ContentModel.PROP_CONTENT)
527      */

528     public String JavaDoc getMimetype()
529     {
530         if (mimetype == null)
531         {
532             TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
533             if (content != null)
534             {
535                 mimetype = content.getMimetype();
536             }
537         }
538         
539         return mimetype;
540     }
541     
542     /**
543      * @return The size in bytes of the content attached to the node from the default content property
544      * (@see ContentModel.PROP_CONTENT)
545      */

546     public long getSize()
547     {
548         if (size == null)
549         {
550             TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
551             if (content != null)
552             {
553                 size = content.getSize();
554             }
555         }
556         
557         return size != null ? size.longValue() : 0L;
558     }
559     
560     /**
561      * @return the image resolver instance used by this node
562      */

563     public TemplateImageResolver getImageResolver()
564     {
565         return this.imageResolver;
566     }
567     
568     /**
569      * Override Object.toString() to provide useful debug output
570      */

571     public String JavaDoc toString()
572     {
573         if (this.services.getNodeService().exists(nodeRef))
574         {
575             return "Node Type: " + getType() +
576                    "\nNode Properties: " + this.getProperties().toString() +
577                    "\nNode Aspects: " + this.getAspects().toString();
578         }
579         else
580         {
581             return "Node no longer exists: " + nodeRef;
582         }
583     }
584     
585     
586     /**
587      * Inner class wrapping and providing access to a ContentData property
588      */

589     public class TemplateContentData implements Serializable JavaDoc
590     {
591        /**
592         * Constructor
593         *
594         * @param contentData The ContentData object this object wraps
595         * @param property The property the ContentData is attached too
596         */

597         public TemplateContentData(ContentData contentData, QName property)
598         {
599             this.contentData = contentData;
600             this.property = property;
601         }
602         
603         /**
604          * @return the content stream
605          */

606         public String JavaDoc getContent()
607         {
608             ContentService contentService = services.getContentService();
609             ContentReader reader = contentService.getReader(nodeRef, property);
610             
611             return (reader != null && reader.exists()) ? reader.getContentString() : "";
612         }
613         
614         /**
615          * @return
616          */

617         public String JavaDoc getUrl()
618         {
619             try
620             {
621                 return MessageFormat.format(CONTENT_PROP_URL, new Object JavaDoc[] {
622                        nodeRef.getStoreRef().getProtocol(),
623                        nodeRef.getStoreRef().getIdentifier(),
624                        nodeRef.getId(),
625                        StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20"),
626                        StringUtils.replace(URLEncoder.encode(property.toString(), "UTF-8"), "+", "%20") } );
627             }
628             catch (UnsupportedEncodingException JavaDoc err)
629             {
630                 throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
631             }
632         }
633         
634         public long getSize()
635         {
636             return contentData.getSize();
637         }
638         
639         public String JavaDoc getMimetype()
640         {
641             return contentData.getMimetype();
642         }
643         
644         private ContentData contentData;
645         private QName property;
646     }
647 }
Popular Tags