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