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.inheritance;
35
36 import info.magnolia.jcr.RuntimeRepositoryException;
37 import info.magnolia.jcr.decoration.AbstractContentDecorator;
38 import info.magnolia.jcr.decoration.ContentDecoratorNodeWrapper;
39 import info.magnolia.jcr.iterator.ChainedNodeIterator;
40 import info.magnolia.jcr.iterator.FilteringNodeIterator;
41 import info.magnolia.jcr.iterator.RangeIteratorImpl;
42 import info.magnolia.jcr.predicate.AbstractPredicate;
43 import info.magnolia.jcr.util.NodeUtil;
44
45 import javax.jcr.Node;
46 import javax.jcr.NodeIterator;
47 import javax.jcr.PathNotFoundException;
48 import javax.jcr.Property;
49 import javax.jcr.PropertyIterator;
50 import javax.jcr.RepositoryException;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.List;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public class InheritanceContentDecorator extends AbstractContentDecorator {
73
74
75 private final Node destination;
76
77
78 private List<Node> sources = new ArrayList<Node>();
79
80 private AbstractPredicate<Node> childInheritancePredicate = new AbstractPredicate<Node>() {
81 @Override
82 public boolean evaluateTyped(Node node) {
83 try {
84 return isSourceChildInherited(node);
85 } catch (RepositoryException e) {
86 throw new RuntimeRepositoryException(e);
87 }
88 }
89 };
90
91 public InheritanceContentDecorator(Node destination) throws RepositoryException {
92 this.destination = destination;
93 }
94
95 @Override
96 public Node wrapNode(Node node) {
97 try {
98 if (NodeUtil.isSame(destination, node)) {
99 return new DestinationNodeInheritanceNodeWrapper(node);
100 } else {
101 return new OtherNodeInheritanceNodeWrapper(node);
102 }
103 } catch (RepositoryException e) {
104 throw new RuntimeRepositoryException(e);
105 }
106 }
107
108 public Node getDestination() {
109 return destination;
110 }
111
112
113
114
115 private AbstractPredicate<Node> getChildInheritancePredicate() {
116
117 if (childInheritancePredicate != null) {
118 return childInheritancePredicate;
119 }
120
121 childInheritancePredicate = new AbstractPredicate<Node>() {
122 @Override
123 public boolean evaluateTyped(Node node) {
124 try {
125 return isSourceChildInherited(node);
126 } catch (RepositoryException e) {
127 throw new RuntimeRepositoryException(e);
128 }
129 }
130 };
131
132 return childInheritancePredicate;
133 }
134
135 public void addSource(Node source) {
136 this.sources.add(source);
137 }
138
139
140
141
142
143
144
145
146 protected boolean inheritsNodes(Node node) throws RepositoryException {
147 return true;
148 }
149
150
151
152
153
154
155
156
157 protected boolean inheritsProperties(Node node) throws RepositoryException {
158 return true;
159 }
160
161
162
163
164
165
166
167
168 protected boolean isSourceChildInherited(Node node) throws RepositoryException {
169 return true;
170 }
171
172
173
174
175
176
177
178
179
180
181 protected NodeIterator sortInheritedNodes(NodeIterator destinationChildren, List<NodeIterator> sourceChildren) throws RepositoryException {
182 Collections.reverse(sourceChildren);
183 sourceChildren.add(destinationChildren);
184 return new FilteringNodeIterator(new ChainedNodeIterator(sourceChildren), getChildInheritancePredicate());
185 }
186
187
188
189
190
191
192
193
194
195
196
197 protected PropertyIterator combinePropertyIterators(PropertyIterator destinationProperties, List<PropertyIterator> sourceProperties) throws RepositoryException {
198 HashSet<String> names = new HashSet<String>();
199 ArrayList<Property> properties = new ArrayList<Property>();
200 while (destinationProperties.hasNext()) {
201 Property property = destinationProperties.nextProperty();
202 names.add(property.getName());
203 properties.add(property);
204 }
205 for (PropertyIterator propertyIterator : sourceProperties) {
206 while (propertyIterator.hasNext()) {
207 Property property = (Property) propertyIterator.next();
208 if (!names.contains(property.getName())) {
209 names.add(property.getName());
210 properties.add(property);
211 }
212 }
213 }
214 return new PropertyIteratorImpl(properties);
215 }
216
217
218
219
220
221
222 private class OtherNodeInheritanceNodeWrapper extends ContentDecoratorNodeWrapper implements InheritanceNodeWrapper {
223
224 public OtherNodeInheritanceNodeWrapper(Node node) {
225 super(node, InheritanceContentDecorator.this);
226 }
227
228 @Override
229 public boolean isInherited() {
230 try {
231
232 Node wrappedNode = getWrappedNode();
233
234 if (isChildOf(wrappedNode, destination)) {
235 return false;
236 }
237
238 Node n = destination;
239 Iterator<Node> iterator = sources.iterator();
240 while (iterator.hasNext() && inheritsNodes(n)) {
241 n = iterator.next();
242 if (isChildOf(wrappedNode, n) && isSourceChildInherited(wrappedNode)) {
243 return true;
244 }
245 }
246
247 return false;
248 } catch (RepositoryException e) {
249 throw new RuntimeRepositoryException(e);
250 }
251 }
252
253 private boolean isChildOf(Node child, Node parent) {
254 try {
255 return parent.getDepth() == 0 || child.getPath().startsWith(parent.getPath() + "/");
256 } catch (RepositoryException e) {
257 throw new RuntimeRepositoryException(e);
258 }
259 }
260 }
261
262
263
264
265
266
267 public class DestinationNodeInheritanceNodeWrapper extends ContentDecoratorNodeWrapper implements InheritanceNodeWrapper {
268
269 public DestinationNodeInheritanceNodeWrapper(Node node) {
270 super(node, InheritanceContentDecorator.this);
271 }
272
273 @Override
274 public boolean hasNode(String relPath) throws RepositoryException {
275 if (super.hasNode(relPath)) {
276 return true;
277 }
278 Node current = getWrappedNode();
279 Iterator<Node> iterator = sources.iterator();
280 while (iterator.hasNext() && inheritsNodes(current)) {
281 current = iterator.next();
282 if (current.hasNode(relPath) && isSourceChildInherited(current.getNode(relPath))) {
283 return true;
284 }
285 }
286 return false;
287 }
288
289 @Override
290 public Node getNode(String relPath) throws PathNotFoundException, RepositoryException {
291 if (super.hasNode(relPath)) {
292 return super.getNode(relPath);
293 }
294 Node current = getWrappedNode();
295 Iterator<Node> iterator = sources.iterator();
296 while (iterator.hasNext() && inheritsNodes(current)) {
297 current = iterator.next();
298 if (current.hasNode(relPath)) {
299 Node node = current.getNode(relPath);
300 if (isSourceChildInherited(node)) {
301 return wrapNode(node);
302 }
303 }
304 }
305 throw new PathNotFoundException(relPath);
306 }
307
308 @Override
309 public NodeIterator getNodes() throws RepositoryException {
310 List<NodeIterator> nodes = new ArrayList<NodeIterator>();
311 Node current = getWrappedNode();
312 Iterator<Node> iterator = sources.iterator();
313 while (iterator.hasNext() && inheritsNodes(current)) {
314 current = iterator.next();
315 nodes.add(current.getNodes());
316 }
317 return super.wrapNodeIterator(sortInheritedNodes(getWrappedNode().getNodes(), nodes));
318 }
319
320 @Override
321 public NodeIterator getNodes(String namePattern) throws RepositoryException {
322 List<NodeIterator> nodes = new ArrayList<NodeIterator>();
323 Node current = getWrappedNode();
324 Iterator<Node> iterator = sources.iterator();
325 while (iterator.hasNext() && inheritsNodes(current)) {
326 current = iterator.next();
327 nodes.add(current.getNodes(namePattern));
328 }
329 return super.wrapNodeIterator(sortInheritedNodes(getWrappedNode().getNodes(namePattern), nodes));
330 }
331
332 @Override
333 public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException {
334 List<NodeIterator> nodes = new ArrayList<NodeIterator>();
335 Node current = getWrappedNode();
336 Iterator<Node> iterator = sources.iterator();
337 while (iterator.hasNext() && inheritsNodes(current)) {
338 current = iterator.next();
339 nodes.add(current.getNodes(nameGlobs));
340 }
341 return super.wrapNodeIterator(sortInheritedNodes(getWrappedNode().getNodes(nameGlobs), nodes));
342 }
343
344 @Override
345 public boolean hasProperty(String relPath) throws RepositoryException {
346 if (super.hasProperty(relPath)) {
347 return true;
348 }
349 Node current = getWrappedNode();
350 Iterator<Node> iterator = sources.iterator();
351 while (iterator.hasNext() && inheritsProperties(current)) {
352 current = iterator.next();
353 if (current.hasProperty(relPath)) {
354 return true;
355 }
356 }
357 return false;
358 }
359
360 @Override
361 public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException {
362 if (super.hasProperty(relPath)) {
363 return super.getProperty(relPath);
364 }
365 Node current = getWrappedNode();
366 Iterator<Node> iterator = sources.iterator();
367 while (iterator.hasNext() && inheritsProperties(current)) {
368 current = iterator.next();
369 if (current.hasProperty(relPath)) {
370 return wrapProperty(current.getProperty(relPath));
371 }
372 }
373 throw new PathNotFoundException(relPath);
374 }
375
376 @Override
377 public PropertyIterator getProperties() throws RepositoryException {
378 ArrayList<PropertyIterator> properties = new ArrayList<PropertyIterator>();
379 Node current = getWrappedNode();
380 Iterator<Node> iterator = sources.iterator();
381 while (iterator.hasNext() && inheritsProperties(current)) {
382 current = iterator.next();
383 properties.add(current.getProperties());
384 }
385 return super.wrapPropertyIterator(combinePropertyIterators(super.getProperties(), properties));
386 }
387
388 @Override
389 public PropertyIterator getProperties(String namePattern) throws RepositoryException {
390 ArrayList<PropertyIterator> properties = new ArrayList<PropertyIterator>();
391 Node current = getWrappedNode();
392 Iterator<Node> iterator = sources.iterator();
393 while (iterator.hasNext() && inheritsProperties(current)) {
394 current = iterator.next();
395 properties.add(current.getProperties(namePattern));
396 }
397 return super.wrapPropertyIterator(combinePropertyIterators(super.getProperties(namePattern), properties));
398 }
399
400 @Override
401 public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException {
402 ArrayList<PropertyIterator> properties = new ArrayList<PropertyIterator>();
403 Node current = getWrappedNode();
404 Iterator<Node> iterator = sources.iterator();
405 while (iterator.hasNext() && inheritsProperties(current)) {
406 current = iterator.next();
407 properties.add(current.getProperties(nameGlobs));
408 }
409 return super.wrapPropertyIterator(combinePropertyIterators(super.getProperties(nameGlobs), properties));
410 }
411
412 @Override
413 public boolean isInherited() {
414 return false;
415 }
416 }
417
418 private static class PropertyIteratorImpl extends RangeIteratorImpl implements PropertyIterator {
419
420 public PropertyIteratorImpl(Collection<Property> collection) {
421 super(collection);
422 }
423
424 @Override
425 public Property nextProperty() {
426 return (Property) super.next();
427 }
428 }
429 }