1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
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;
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 }