View Javadoc
1   package org.argeo.support.freemarker;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.jcr.Node;
7   import javax.jcr.NodeIterator;
8   import javax.jcr.Property;
9   import javax.jcr.PropertyIterator;
10  import javax.jcr.RepositoryException;
11  import javax.jcr.Value;
12  
13  import freemarker.template.SimpleScalar;
14  import freemarker.template.TemplateCollectionModel;
15  import freemarker.template.TemplateHashModel;
16  import freemarker.template.TemplateHashModelEx2;
17  import freemarker.template.TemplateModel;
18  import freemarker.template.TemplateModelException;
19  import freemarker.template.TemplateModelIterator;
20  import freemarker.template.TemplateNodeModel;
21  import freemarker.template.TemplateSequenceModel;
22  
23  public class JcrModel implements TemplateNodeModel, TemplateHashModel {
24  	private final Node node;
25  
26  	public JcrModel(Node node) {
27  		this.node = node;
28  	}
29  
30  	@Override
31  	public TemplateSequenceModel getChildNodes() throws TemplateModelException {
32  		try {
33  			return new NodeIteratorModel(node.getNodes());
34  		} catch (RepositoryException e) {
35  			throw new TemplateModelException("Cannot list children of " + node, e);
36  		}
37  	}
38  
39  	@Override
40  	public String getNodeName() throws TemplateModelException {
41  		try {
42  			return node.getName();
43  		} catch (RepositoryException e) {
44  			throw new TemplateModelException("Cannot get name of " + node, e);
45  		}
46  	}
47  
48  	@Override
49  	public String getNodeNamespace() throws TemplateModelException {
50  		// TODO find out namespace
51  		return null;
52  	}
53  
54  	@Override
55  	public String getNodeType() throws TemplateModelException {
56  		try {
57  			return node.getPrimaryNodeType().getName();
58  		} catch (RepositoryException e) {
59  			throw new TemplateModelException("Cannot get node type of " + node, e);
60  		}
61  	}
62  
63  	@Override
64  	public TemplateNodeModel getParentNode() throws TemplateModelException {
65  		try {
66  			Node parent = node.getParent();
67  			if (parent == null)
68  				return null;
69  			return new JcrModel(parent);
70  		} catch (RepositoryException e) {
71  			throw new TemplateModelException("Cannot get parent of " + node, e);
72  		}
73  	}
74  
75  	// HASH
76  
77  	@Override
78  	public TemplateModel get(String key) throws TemplateModelException {
79  		try {
80  			if ("jcr:path".equals(key))
81  				return new SimpleScalar(node.getPath());
82  			if ("jcr:name".equals(key))
83  				return new SimpleScalar(node.getName());
84  			if ("jcr:properties".equals(key))
85  				return new PropertiesModel();
86  			if ("jcr:parent".equals(key))
87  				return !"/".equals(node.getPath()) ? new JcrModel(node.getParent()) : null;
88  
89  			Property property = null;
90  			if (!node.hasProperty(key)) {
91  				List<Property> props = new ArrayList<>();
92  				PropertyIterator pit = node.getProperties("*:" + key);
93  				while (pit.hasNext())
94  					props.add(pit.nextProperty());
95  				if (props.size() > 1)
96  					throw new TemplateModelException(
97  							"Too many properties match " + key + " (" + props + "), use prefix with \\: escape");
98  				if (!props.isEmpty())
99  					property = props.get(0);
100 			} else
101 				property = node.getProperty(key);
102 			if (property != null)
103 				return propertyValues(property);
104 
105 			Node child = null;
106 			if (!node.hasNode(key)) {
107 				List<Node> children = new ArrayList<>();
108 				NodeIterator nit = node.getNodes("*:" + key);
109 				while (nit.hasNext())
110 					children.add(nit.nextNode());
111 				if (children.size() > 1)
112 					throw new TemplateModelException(
113 							"Too many properties match " + key + " (" + children + "), use prefix with \\: escape");
114 				if (!children.isEmpty())
115 					child = children.get(0);
116 			} else
117 				child = node.getNode(key);
118 			if (child != null)
119 				return new JcrModel(child);
120 			return null;
121 
122 		} catch (RepositoryException e) {
123 			throw new TemplateModelException("Cannot get property " + key + " of " + node, e);
124 		}
125 	}
126 
127 	@Override
128 	public boolean isEmpty() throws TemplateModelException {
129 		return false;
130 	}
131 
132 	public Node getNode() {
133 		return node;
134 	}
135 
136 	protected TemplateModel propertyValues(Property property) throws RepositoryException {
137 		if (!property.isMultiple())
138 			return new SimpleScalar(property.getString());
139 		Value[] values = property.getValues();
140 		StringBuilder sb = new StringBuilder();
141 		for (Value value : values) {
142 			sb.append(value.getString()).append('\n');
143 		}
144 		return new SimpleScalar(sb.toString());
145 	}
146 
147 	class PropertiesModel implements TemplateHashModelEx2 {
148 		@Override
149 		public TemplateModel get(String key) throws TemplateModelException {
150 			return JcrModel.this.get(key);
151 		}
152 
153 		@Override
154 		public boolean isEmpty() throws TemplateModelException {
155 			return false;
156 		}
157 
158 		@Override
159 		public TemplateCollectionModel keys() throws TemplateModelException {
160 			try {
161 				PropertyIterator pit = node.getProperties();
162 				return new TemplateCollectionModel() {
163 
164 					@Override
165 					public TemplateModelIterator iterator() throws TemplateModelException {
166 						return new TemplateModelIterator() {
167 
168 							@Override
169 							public TemplateModel next() throws TemplateModelException {
170 								try {
171 									return new SimpleScalar(pit.nextProperty().getName());
172 								} catch (RepositoryException e) {
173 									throw new TemplateModelException("Cannot list properties of " + node, e);
174 								}
175 							}
176 
177 							@Override
178 							public boolean hasNext() throws TemplateModelException {
179 								return pit.hasNext();
180 							}
181 						};
182 					}
183 				};
184 			} catch (RepositoryException e) {
185 				throw new TemplateModelException("Cannot list properties of " + node, e);
186 			}
187 		}
188 
189 		@Override
190 		public int size() throws TemplateModelException {
191 			try {
192 				PropertyIterator pit = node.getProperties();
193 				return (int) pit.getSize();
194 			} catch (RepositoryException e) {
195 				throw new TemplateModelException("Cannot list properties of " + node, e);
196 			}
197 		}
198 
199 		@Override
200 		public TemplateCollectionModel values() throws TemplateModelException {
201 			try {
202 				PropertyIterator pit = node.getProperties();
203 				return new TemplateCollectionModel() {
204 
205 					@Override
206 					public TemplateModelIterator iterator() throws TemplateModelException {
207 						return new TemplateModelIterator() {
208 
209 							@Override
210 							public TemplateModel next() throws TemplateModelException {
211 								try {
212 									return propertyValues(pit.nextProperty());
213 								} catch (RepositoryException e) {
214 									throw new TemplateModelException("Cannot list properties of " + node, e);
215 								}
216 							}
217 
218 							@Override
219 							public boolean hasNext() throws TemplateModelException {
220 								return pit.hasNext();
221 							}
222 						};
223 					}
224 				};
225 			} catch (RepositoryException e) {
226 				throw new TemplateModelException("Cannot list properties of " + node, e);
227 			}
228 		}
229 
230 		@Override
231 		public KeyValuePairIterator keyValuePairIterator() throws TemplateModelException {
232 			try {
233 				PropertyIterator pit = node.getProperties();
234 				return new KeyValuePairIterator() {
235 
236 					@Override
237 					public boolean hasNext() throws TemplateModelException {
238 						return pit.hasNext();
239 					}
240 
241 					@Override
242 					public KeyValuePair next() throws TemplateModelException {
243 						Property property = pit.nextProperty();
244 						return new KeyValuePair() {
245 
246 							@Override
247 							public TemplateModel getValue() throws TemplateModelException {
248 								try {
249 									return propertyValues(property);
250 								} catch (RepositoryException e) {
251 									throw new TemplateModelException("Cannot list properties of " + node, e);
252 								}
253 							}
254 
255 							@Override
256 							public TemplateModel getKey() throws TemplateModelException {
257 								try {
258 									return new SimpleScalar(property.getName());
259 								} catch (RepositoryException e) {
260 									throw new TemplateModelException("Cannot list properties of " + node, e);
261 								}
262 							}
263 						};
264 					}
265 				};
266 			} catch (RepositoryException e) {
267 				throw new TemplateModelException("Cannot list properties of " + node, e);
268 			}
269 		}
270 
271 	}
272 }