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.rest.delivery.jcr.decorator;
35
36 import info.magnolia.jcr.decoration.ContentDecoratorNodeWrapper;
37 import info.magnolia.jcr.util.NodeUtil;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.objectfactory.Components;
40 import info.magnolia.rest.delivery.jcr.filter.FilteringContentDecoratorBuilder;
41 import info.magnolia.rest.reference.ReferenceDefinition;
42 import info.magnolia.rest.reference.ReferenceResolver;
43
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.HashMap;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Optional;
51 import java.util.stream.Collectors;
52
53 import javax.jcr.Item;
54 import javax.jcr.Node;
55 import javax.jcr.NodeIterator;
56 import javax.jcr.Property;
57 import javax.jcr.PropertyIterator;
58 import javax.jcr.RepositoryException;
59
60 import org.apache.jackrabbit.commons.ItemNameMatcher;
61 import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
62 import org.apache.jackrabbit.commons.iterator.PropertyIteratorAdapter;
63 import org.apache.jackrabbit.spi.commons.iterator.Iterators;
64
65 import com.google.common.collect.Lists;
66
67
68
69
70 public class ReferenceExpandWrapper extends ContentDecoratorNodeWrapper {
71
72 private final Map<String, Item> resolvedItems = new HashMap<>();
73 private final ComponentProvider componentProvider = Components.getComponentProvider();
74
75 public ReferenceExpandWrapper(Node wrapped, List<ReferenceDefinition> references, FilteringContentDecoratorBuilder expandDecorators) {
76 super(wrapped, new ReferenceExpandDecorator(references, expandDecorators));
77 try {
78 PropertyIterator properties = wrapped.getProperties();
79 while (properties.hasNext()) {
80 Property property = properties.nextProperty();
81
82 Optional<Node> resolvedItem = resolveProperty(property, references);
83
84 if (resolvedItem.isPresent()) {
85 resolvedItems.put(property.getName(), resolvedItem.get());
86 }
87 }
88 } catch (RepositoryException e) {
89 throw new RuntimeException("Can't wrap node [" + wrapped + "]", e);
90 }
91 }
92
93 private Optional<Node> resolveProperty(Property property, List<ReferenceDefinition> references) throws RepositoryException {
94 for (ReferenceDefinition definition : references) {
95 boolean matchNodeType = definition.getNodeType() == null || definition.getNodeType() != null && NodeUtil.isNodeType(wrapped, definition.getNodeType());
96 boolean matchItemName = definition.getPropertyName() == null || property.getName().matches(definition.getPropertyName());
97 boolean hasDefinition = definition.getReferenceResolver() != null && definition.getReferenceResolver().getImplementationClass() != null;
98 if (matchNodeType && matchItemName && hasDefinition) {
99 ReferenceResolver referenceResolver = componentProvider.newInstance(definition.getReferenceResolver().getImplementationClass(), definition.getReferenceResolver());
100 Optional itemOptional = referenceResolver.resolve(property);
101 if (itemOptional.isPresent() && itemOptional.get() instanceof Node) {
102 Node resolvedNode = (Node) itemOptional.get();
103 return Optional.of(new AdditionNodeWrapper(resolvedNode, property.getName()));
104 }
105 }
106 }
107
108 return Optional.empty();
109 }
110
111 @Override
112 public boolean hasProperties() throws RepositoryException {
113 boolean hasProperties = resolvedItems.values().stream()
114 .anyMatch(item -> !item.isNode());
115 return hasProperties || super.hasProperties();
116 }
117
118 @Override
119 public boolean hasProperty(String relPath) throws RepositoryException {
120 boolean hasProperties = resolvedItems.entrySet().stream()
121 .anyMatch(entry -> !entry.getValue().isNode() && entry.getKey().equals(relPath));
122 return hasProperties || super.hasProperty(relPath);
123 }
124
125 @Override
126 public PropertyIterator getProperties() throws RepositoryException {
127 return getProperties("*");
128 }
129
130 @Override
131 public PropertyIterator getProperties(String namePattern) throws RepositoryException {
132 return getProperties(new String[] {namePattern});
133 }
134
135 @Override
136 public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException {
137 Iterator properties = Iterators.filterIterator(Iterators.properties(super.getProperties(nameGlobs)), property -> {
138 try {
139 return !resolvedItems.containsKey(property.getName());
140 } catch (RepositoryException e) {
141 return false;
142 }
143 });
144
145 List<Property> merged = Lists.newArrayList(properties);
146 List<Property> resolvedProperties = resolvedItems.entrySet().stream()
147 .filter(entry -> !entry.getValue().isNode() && ItemNameMatcher.matches(entry.getKey(), nameGlobs))
148 .map(entry -> (Property) entry.getValue())
149 .collect(Collectors.toList());
150 merged.addAll(resolvedProperties);
151
152 return new PropertyIteratorAdapter(merged);
153 }
154
155 @Override
156 public boolean hasNodes() throws RepositoryException {
157 boolean hasNodes = resolvedItems.values().stream()
158 .anyMatch(Item::isNode);
159 return hasNodes || super.hasNodes();
160 }
161
162 @Override
163 public boolean hasNode(String relPath) throws RepositoryException {
164 boolean hasNodes = resolvedItems.entrySet().stream()
165 .anyMatch(entry ->entry.getValue().isNode() && entry.getKey().equals(relPath) );
166 return hasNodes || super.hasNode(relPath);
167 }
168
169 @Override
170 public Node getNode(String relPath) throws RepositoryException {
171 Optional<Item> itemOptional = resolvedItems.entrySet().stream()
172 .filter(entry -> entry.getValue().isNode() && entry.getKey().equals(relPath))
173 .findFirst()
174 .map(Map.Entry::getValue);
175
176 if (itemOptional.isPresent()) {
177 return (Node) itemOptional.get();
178 }
179
180 return super.getNode(relPath);
181 }
182
183 @Override
184 public NodeIterator getNodes() throws RepositoryException {
185 return getNodes("*");
186 }
187
188 @Override
189 public NodeIterator getNodes(String namePattern) throws RepositoryException {
190 return getNodes(new String[] {namePattern});
191 }
192
193 @Override
194 public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException {
195 Collection<Node> children = NodeUtil.getCollectionFromNodeIterator(getWrappedNode().getNodes(nameGlobs));
196
197 List<Node> merged = new ArrayList<>(children);
198 List<Node> resolvedNodes = resolvedItems.entrySet().stream()
199 .filter(entry -> ItemNameMatcher.matches(entry.getKey(), nameGlobs) && entry.getValue().isNode())
200 .map(entry -> (Node) entry.getValue())
201 .collect(Collectors.toList());
202 merged.addAll(resolvedNodes);
203
204 return wrapNodeIterator(new NodeIteratorAdapter(merged));
205 }
206 }