View Javadoc

1   /*
2    * Copyright 2007 Hippo
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" 
12   * BASIS, 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 nl.hippo.portal.cms.site;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.TreeSet;
24  
25  import javax.xml.parsers.ParserConfigurationException;
26  
27  import nl.hippo.client.api.content.DocumentMetadata;
28  import nl.hippo.client.api.content.Property;
29  import nl.hippo.portal.cms.repository.DocumentTreeBuilder;
30  import nl.hippo.portal.cms.repository.WebdavCollection;
31  import nl.hippo.portal.cms.repository.WebdavResource;
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl;
35  import org.w3c.dom.Document;
36  import org.w3c.dom.Node;
37  import org.w3c.dom.traversal.DocumentTraversal;
38  import org.w3c.dom.traversal.NodeFilter;
39  import org.w3c.dom.traversal.TreeWalker;
40  import org.xml.sax.SAXException;
41  
42  public final class SiteMapLoader implements DocumentTransformer {
43  
44      private static final String ATTR_TYPE = "type";
45      private static final String ATTR_DATASOURCE = "datasource";
46      private static final String ATTR_TITLE = "title";
47      private static final String ATTR_REPOSITORY_BASED = "repository-based";
48      static final String ATTR_ID = "id";
49      private static final String ATTR_NAME = "name";
50      private static final String ATTR_HIDDEN = "hidden";
51      private static final String ATTR_LINKABLE = "linkable";
52      private static final String ELEMENT_FIXED = "fixed-item";
53      private static final String ELEMENT_ITEM = "menu-item";
54  
55      private DocumentTreeBuilder treeBuilder;
56      private int repoNavMaxDepth;
57      
58      public SiteMapLoader(DocumentTreeBuilder treeBuilder, int repoNavMaxDepth) {
59          this.treeBuilder=treeBuilder;
60          this.repoNavMaxDepth=repoNavMaxDepth;
61          treeBuilder.setMaxNavDepth(repoNavMaxDepth);
62      }
63  
64      public Object transform(String name, InputStream documentStream, List documentPaths) throws SAXException, ParserConfigurationException,
65              IOException {
66          return getSiteMap(name, documentStream, documentPaths);
67      }
68  
69      public SiteMap getSiteMap(String name, InputStream metaDataStream, List documentPaths) throws SAXException,
70              ParserConfigurationException, IOException {
71          SiteMapImpl result = new SiteMapImpl(name);
72          Document doc = DocumentBuilderFactoryImpl.newInstance().newDocumentBuilder().parse(metaDataStream);
73          Node root = doc.getDocumentElement();
74          DocumentTraversal traversal = (DocumentTraversal) doc;
75          TreeWalker walker = traversal.createTreeWalker(root, NodeFilter.SHOW_ALL, null, false);
76          Node node = walker.nextNode();
77          traverse(node, result, "", documentPaths);
78          return result;
79      }
80  
81      private void traverse(Node node, SiteMapImpl parent, String path, List documentPaths) {
82          while (node != null) {
83              String nodeName = node.getNodeName();
84              if (ELEMENT_ITEM.equals(nodeName)) {
85                  String newPath = parseItem(node, parent, true, path, documentPaths);
86                  if (node.hasChildNodes()) {
87                      traverse(node.getFirstChild(), parent, newPath, documentPaths);
88                  }
89              } else if (ELEMENT_FIXED.equals(nodeName)) {
90                  String newPath = parseItem(node, parent, false, path, documentPaths);
91                  if (node.hasChildNodes()) {
92                      traverse(node.getFirstChild(), parent, newPath, documentPaths);
93                  }
94              }
95              node = node.getNextSibling();
96          }
97      }
98  
99      private boolean isWebdavCollection(WebdavResource resource){
100         return (resource instanceof WebdavCollection);
101     }
102     
103     private WebdavResource findAndRemoveIndexDocument(WebdavCollection collection){
104         for (Iterator iter = collection.getChildren().iterator(); iter.hasNext();) {
105             WebdavResource childResource = (WebdavResource) iter.next();
106             if (childResource!=null && !(childResource instanceof WebdavCollection)){
107                 String value = childResource.getDocument().getMetadata().getPropertyValue("isIndexDocument", Property.HIPPO_NAMESPACE);
108                 if (value!=null && "true".equalsIgnoreCase(value)){
109                     iter.remove();
110                     return childResource; // index document found
111                 }                                    
112             }            
113         }
114         return null;
115     }
116     
117     private String getTitle(WebdavResource resource){
118         DocumentMetadata metadata = resource.getDocument().getMetadata();
119         String caption = metadata.getCaption();
120         if (caption!=null && caption.length()>0){
121             return caption;
122         }
123         String displayName = metadata.getDisplayname();
124         return displayName.replaceAll(".xml", "");
125     }
126     
127     private void addRepositoryBasedItem(WebdavResource resource, SiteMapImpl siteMap, String path, String rootType, int level){
128         DocumentMetadata metadata = resource.getDocument().getMetadata();
129         String displayName = metadata.getDisplayname();
130         String newPath = path+displayName.replaceAll(".xml", ".html");
131         String caption = getTitle(resource);
132         String datasource=null;
133         String template=null;
134         boolean linkable=true;
135         if (isWebdavCollection(resource)){
136           WebdavCollection collection = (WebdavCollection) resource;  
137           WebdavResource indexDocument = findAndRemoveIndexDocument(collection); 
138           if (indexDocument!=null){
139               DocumentMetadata indexMetadata = indexDocument.getDocument().getMetadata(); 
140               datasource = indexMetadata.getDocumentPath().getRelativePath();
141               template = rootType;
142           } else {
143               linkable=false; // no index document found
144           }
145         } else {
146             datasource = metadata.getDocumentPath().getRelativePath();
147             template=rootType+"-detail";
148         }
149         siteMap.addSiteMapItem(null, newPath, caption, datasource,template, 
150                 false, true, linkable);        
151         if (isWebdavCollection(resource) && level < repoNavMaxDepth){            
152             WebdavCollection collection = (WebdavCollection) resource;
153             for (Iterator iter = collection.getChildren().iterator(); iter.hasNext();) {
154                 WebdavResource child = (WebdavResource) iter.next();
155                 addRepositoryBasedItem(child, siteMap, newPath+"/",rootType, level+1);                
156             }
157         }
158     }
159     
160     private String parseItem(Node node, SiteMapImpl siteMap, boolean isMenuItem, String path, List documentPaths) {
161         Map attributes = XMLLoaderUtils.getAttributes(node);
162         String newPath = path + getPath(attributes);
163         if (getRepositoryBased(attributes)){
164             String rootType = getTemplate(attributes);
165             String datasource = getSrc(attributes);
166             WebdavResource rootFolder = treeBuilder.build(datasource);
167             if (rootFolder!=null && rootFolder instanceof WebdavCollection){
168                 documentPaths.add(datasource); 
169                 TreeSet items = ((WebdavCollection)rootFolder).getChildren();
170                 for (Iterator iter = items.iterator(); iter.hasNext();) {
171                     WebdavResource resource = (WebdavResource) iter.next();
172                     addRepositoryBasedItem(resource,siteMap,path,rootType,1);                    
173                 }
174             }
175             
176         } else {
177             SiteMapItemImpl item = siteMap.addSiteMapItem(getId(attributes), newPath, getTitle(attributes), getSrc(attributes),
178                     getTemplate(attributes), getHidden(attributes), isMenuItem, getLinkable(attributes));
179             if (item != null) {
180             	item.setAttributes(attributes);
181             }	
182         }
183         return newPath + "/";
184     }
185 
186     private String getPath(Map attributes) {
187         String result = (String) attributes.get(ATTR_NAME);
188         return result;
189     }
190 
191     private String getId(Map attributes) {
192         String result = (String) attributes.get(ATTR_ID);
193         return StringUtils.defaultIfEmpty(result, null);
194     }
195 
196     private String getTitle(Map attributes) {
197         String result = (String) attributes.get(ATTR_TITLE);
198         return result;
199     }
200 
201     private boolean getHidden(Map attributes) {
202         String result = (String) attributes.get(ATTR_HIDDEN);
203         return result != null ? Boolean.valueOf(result).booleanValue() : false;
204     }
205 
206     private boolean getLinkable(Map attributes) {
207         String result = (String) attributes.get(ATTR_LINKABLE);
208         return result != null ? Boolean.valueOf(result).booleanValue() : true;
209     }
210 
211     private String getSrc(Map attributes) {
212         String result = (String) attributes.get(ATTR_DATASOURCE);
213         return result;
214     }
215 
216     private String getTemplate(Map attributes) {
217         String result = (String) attributes.get(ATTR_TYPE);
218         if (result == null || result.length() == 0) {
219             result = (String) attributes.get(ATTR_ID);
220         }
221         return result;
222     }
223     
224     private boolean getRepositoryBased(Map attributes) {
225         String result = (String) attributes.get(ATTR_REPOSITORY_BASED);        
226         return result == null ? false : "true".equalsIgnoreCase(result);
227     }
228 
229 }