1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.jcr.wrapper;
35
36 import info.magnolia.jcr.iterator.RangeIteratorImpl;
37 import info.magnolia.jcr.util.NodeUtil;
38
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.LinkedHashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.TreeMap;
45
46 import javax.jcr.Node;
47 import javax.jcr.NodeIterator;
48 import javax.jcr.PathNotFoundException;
49 import javax.jcr.Property;
50 import javax.jcr.PropertyIterator;
51 import javax.jcr.RepositoryException;
52
53 import org.apache.commons.lang.StringUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class ExtendingNodeWrapper extends ChildWrappingNodeWrapper {
75
76 protected static final String EXTENDING_NODE_PROPERTY = "extends";
77 protected static final String EXTENDING_NODE_PROPERTY_OVERRIDE = "override";
78
79 private static final Logger log = LoggerFactory.getLogger(ExtendingNodeWrapper.class);
80
81
82
83
84 private boolean extending;
85
86
87
88
89 private Node extendedNode;
90
91
92
93
94
95 public ExtendingNodeWrapper(Node wrappedNode) {
96 this(wrappedNode, false);
97 }
98
99
100
101
102
103
104
105 public ExtendingNodeWrapper(Node wrappedNode, boolean failOnError) {
106 super(wrappedNode);
107
108 try {
109 final boolean hasExtendingProperty = getWrappedNode().hasProperty(EXTENDING_NODE_PROPERTY);
110
111 if (hasExtendingProperty) {
112 extending = true;
113
114 Property extendingNodeProperty = getWrappedNode().getProperty(EXTENDING_NODE_PROPERTY);
115
116 String extendingNodePath = extendingNodeProperty.getString();
117
118 if (StringUtils.isBlank(extendingNodePath) || extendingNodePath.equals(EXTENDING_NODE_PROPERTY_OVERRIDE)) {
119 extending = false;
120 }
121
122 if (extending) {
123 if (isExists(extendingNodePath, getWrappedNode())) {
124
125 if (extendingNodePath.startsWith("/")) {
126 extendedNode = getWrappedNode().getSession().getNode(extendingNodePath);
127 } else {
128 extendedNode = getWrappedNode().getNode(extendingNodePath);
129 }
130 if (!NodeUtil.isSame(getWrappedNode(), extendedNode)) {
131 extendedNode = wrapIfNeeded(extendedNode);
132 } else {
133
134 extendedNode = null;
135 extending = false;
136 log.error("Node can't self-extend: " + getWrappedNode().getPath());
137 }
138 } else {
139 String message = "Can't find referenced node for value: " + wrapped;
140 log.error(message);
141 extending = false;
142 if (failOnError) {
143 throw new RuntimeException(message);
144 }
145 }
146 }
147 }
148
149 } catch (RepositoryException e) {
150 throw new RuntimeException("Can't wrap node [" + wrapped + "]", e);
151 }
152 }
153
154
155
156
157
158
159
160 protected ExtendingNodeWrapper(Node wrappedNode, Node extendedNode) {
161 super(wrapIfNeeded(wrappedNode));
162 extending = true;
163 try {
164 if (getWrappedNode().hasProperty(EXTENDING_NODE_PROPERTY)) {
165 Property extendingNodeProperty = getWrappedNode().getProperty(EXTENDING_NODE_PROPERTY);
166
167
168 extending = !extendingNodeProperty.getString().equals(EXTENDING_NODE_PROPERTY_OVERRIDE);
169 }
170 }
171 catch (RepositoryException e) {
172 throw new RuntimeException("Can't determine extends point for node [" + wrappedNode + "]", e);
173 }
174
175 this.extendedNode = wrapIfNeeded(extendedNode);
176 }
177
178 @Override
179 public boolean hasNode(String relPath) throws RepositoryException {
180 if(getWrappedNode().hasNode(relPath)) {
181 return true;
182 } else if(extending && extendedNode.hasNode(relPath)) {
183 return true;
184 } else {
185 return false;
186 }
187 }
188
189 @Override
190 public Node getNode(String relPath) throws PathNotFoundException, RepositoryException {
191 if (getWrappedNode().hasNode(relPath)) {
192 return wrapNode(getWrappedNode().getNode(relPath));
193 } else if (extending && extendedNode.hasNode(relPath)) {
194 return(extendedNode.getNode(relPath));
195 } else {
196 throw new PathNotFoundException("Node does not exists: [" + relPath + "]");
197 }
198 }
199
200 @Override
201 public NodeIterator getNodes() throws RepositoryException {
202 return this.getNodes("*");
203 }
204
205 @Override
206 public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException {
207 return this.getNodes(StringUtils.join(nameGlobs, " | "));
208 }
209
210 @Override
211 public NodeIterator getNodes(String namePattern) throws RepositoryException {
212 Collection<Node> children = NodeUtil.getSortedCollectionFromNodeIterator(getWrappedNode().getNodes());
213 if (extending) {
214
215 Collection<Node> extendedNodeChildren = NodeUtil.getSortedCollectionFromNodeIterator(extendedNode.getNodes());
216 Map<String, Node> merged = new LinkedHashMap<String, Node>();
217
218 for (Node content : extendedNodeChildren) {
219 merged.put(content.getName(), content);
220 }
221 for (Node content : children) {
222 merged.put(content.getName(), content);
223 }
224 return new NodeIteratorImpl(wrapNodes(merged.values()));
225 }
226 return new NodeIteratorImpl(wrapNodes(children));
227 }
228
229 @Override
230 public boolean hasProperty(String relPath) throws RepositoryException {
231
232 if (relPath.equals(EXTENDING_NODE_PROPERTY)) {
233 return false;
234 } else if (getWrappedNode().hasProperty(relPath)) {
235 return true;
236 } else if (extending && extendedNode.hasProperty(relPath)) {
237 return true;
238 } else {
239 return false;
240 }
241 }
242
243 @Override
244 public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException {
245
246 if (relPath.equals(EXTENDING_NODE_PROPERTY)) {
247 throw new PathNotFoundException("Cannont access property [" + getWrappedNode().getPath() + "." + relPath + "]");
248 } else if (getWrappedNode().hasProperty(relPath)) {
249 return getWrappedNode().getProperty(relPath);
250 } else if (extending && extendedNode.hasProperty(relPath)) {
251 return extendedNode.getProperty(relPath);
252 } else {
253 throw new RepositoryException("Can't read property from extended node [" + extendedNode + "]");
254 }
255 }
256
257 @Override
258 public PropertyIterator getProperties() throws RepositoryException {
259 return this.getProperties("*");
260 }
261
262 @Override
263 public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException {
264 return this.getProperties(StringUtils.join(nameGlobs, " | "));
265 }
266
267 @Override
268 public PropertyIterator getProperties(String namePattern) throws RepositoryException {
269 Collection<Property> properties = getPropertiesAsList(getWrappedNode(), namePattern);
270
271 if (extending) {
272 Collection<Property> inheritedProperties = getPropertiesAsList(extendedNode, namePattern);
273
274 Map<String, Property> merged = new TreeMap<String, Property>();
275
276 for (Property prop : inheritedProperties) {
277 merged.put(prop.getName(), prop);
278 }
279
280 for (Property prop : properties) {
281 merged.put(prop.getName(), prop);
282 }
283 return new PropertyIteratorImpl(merged.values());
284 }
285 return new PropertyIteratorImpl(properties);
286 }
287
288 @Override
289 public Node wrapNode(Node node) {
290
291 try {
292 if (extending && extendedNode.hasNode(node.getName())) {
293 Node extendedSubNode = extendedNode.getNode(node.getName());
294 return new ExtendingNodeWrapper(node, extendedSubNode);
295 }
296 }
297 catch (RepositoryException e) {
298 throw new RuntimeException("Can't wrap " + node, e);
299 }
300 return wrapIfNeeded(node);
301 }
302
303 @Override
304 public Node getWrappedNode() {
305 if (wrapped instanceof ExtendingNodeWrapper) {
306 ExtendingNodeWrapper extendingNodeWrapper = (ExtendingNodeWrapper) wrapped;
307 if (!extendingNodeWrapper.extending) {
308 return extendingNodeWrapper.getWrappedNode();
309 }
310 }
311 return wrapped;
312 }
313
314
315
316
317 public boolean isExtending() {
318 return extending;
319 }
320
321
322
323
324
325
326
327
328 private boolean isExists(String nodePath, Node parent) throws RepositoryException {
329 if (nodePath.startsWith("/")) {
330 return getWrappedNode().getSession().itemExists(nodePath);
331 }
332 return parent.hasNode(nodePath);
333 }
334
335
336
337
338
339
340 private static Node wrapIfNeeded(Node node) {
341 if (node instanceof ExtendingNodeWrapper) {
342 return node;
343 }
344 return new ExtendingNodeWrapper(node);
345 }
346
347
348
349
350
351
352 private Collection<Node> wrapNodes(Collection<Node> collection) {
353 Collection<Node> wrappedNodes = new ArrayList<Node>();
354 for (Node node : collection) {
355 wrappedNodes.add(wrapNode(node));
356 }
357 return wrappedNodes;
358 }
359
360
361
362
363
364
365
366
367
368 private static List<Property> getPropertiesAsList(Node node, String namePattern) throws RepositoryException {
369 List<Property> properties = new ArrayList<Property>();
370 PropertyIterator it = node.getProperties(namePattern);
371
372 while(it.hasNext()) {
373 Property prop = (Property) it.next();
374 if (!prop.getName().equals(EXTENDING_NODE_PROPERTY)) {
375 properties.add(prop);
376 }
377 }
378 return properties;
379 }
380
381 private static class PropertyIteratorImpl extends RangeIteratorImpl<Property> implements PropertyIterator {
382
383 public PropertyIteratorImpl(Collection<Property> properties) {
384 super(properties);
385 }
386
387 @Override
388 public Property nextProperty() {
389 return super.next();
390 }
391 }
392
393 private static class NodeIteratorImpl extends RangeIteratorImpl<Node> implements NodeIterator {
394
395 public NodeIteratorImpl(Collection<Node> nodes) {
396 super(nodes);
397 }
398
399 @Override
400 public Node nextNode() {
401 return super.next();
402 }
403 }
404
405 }