1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.onehippo.forge.utilities.commons.jcrmockup;
18
19 import java.util.ArrayList;
20 import java.util.Calendar;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.jcr.Node;
29 import javax.jcr.NodeIterator;
30 import javax.jcr.RepositoryException;
31 import javax.jcr.Session;
32 import javax.jcr.Value;
33 import javax.jcr.Workspace;
34 import javax.jcr.nodetype.NodeType;
35 import javax.jcr.version.VersionManager;
36 import jakarta.xml.bind.annotation.XmlAttribute;
37 import jakarta.xml.bind.annotation.XmlElement;
38 import jakarta.xml.bind.annotation.XmlRootElement;
39 import jakarta.xml.bind.annotation.XmlTransient;
40
41 import org.mockito.Matchers;
42 import org.mockito.Mockito;
43 import org.mockito.invocation.InvocationOnMock;
44 import org.mockito.stubbing.Answer;
45
46
47
48
49 @XmlRootElement(name = "node", namespace = MockNode.HTTP_WWW_JCP_ORG_JCR_SV_1_0)
50 public class MockNode {
51
52 public static final String HTTP_WWW_JCP_ORG_JCR_SV_1_0 = "http://www.jcp.org/jcr/sv/1.0";
53
54
55 private static MockNode rootMockNode;
56 private static Session session = Mockito.mock(Session.class);
57
58 @XmlTransient
59 private boolean removed = false;
60
61 @XmlTransient
62 private MockNode parent;
63
64 @XmlElement(name = "node", namespace = MockNode.HTTP_WWW_JCP_ORG_JCR_SV_1_0)
65 private List<MockNode> childNodes;
66
67 @XmlElement(name = "property", namespace = MockNode.HTTP_WWW_JCP_ORG_JCR_SV_1_0)
68 private List<MockProperty> properties;
69
70 @XmlTransient
71 private boolean propertiesMapInitialized = false;
72
73 @XmlTransient
74 private Map<String, MockProperty> propertiesMap = new HashMap<String, MockProperty>();
75
76 @XmlAttribute(name = "name", namespace = MockNode.HTTP_WWW_JCP_ORG_JCR_SV_1_0)
77 private String name;
78
79 public List<MockNode> getMockChildNodes() {
80 if (childNodes == null) {
81 return Collections.emptyList();
82 }
83 List<MockNode> notRemovedChildNodes = new ArrayList<MockNode>();
84 Iterator<MockNode> childIterator = childNodes.iterator();
85 while (childIterator.hasNext()) {
86 MockNode child = childIterator.next();
87 if (child.isRemoved()) {
88 childIterator.remove();
89 } else {
90 notRemovedChildNodes.add(child);
91 }
92 }
93 return notRemovedChildNodes;
94 }
95
96 public void addMockChildNode(MockNode childNode) {
97 if (this.childNodes == null) {
98 this.childNodes = new ArrayList<MockNode>();
99 }
100 childNode.setParent(this);
101 this.childNodes.add(childNode);
102 }
103
104
105
106
107
108 private void initializePropertiesMap() {
109 if (!propertiesMapInitialized && this.properties != null) {
110 final Iterator<MockProperty> propertyIterator = this.properties.iterator();
111 while (propertyIterator.hasNext()) {
112 final MockProperty mockProperty = propertyIterator.next();
113 if (mockProperty.isRemoved()) {
114 propertyIterator.remove();
115 } else {
116 this.propertiesMap.put(mockProperty.getMockPropertyName(), mockProperty);
117 }
118 }
119 propertiesMapInitialized = true;
120 }
121 }
122
123 public MockProperty getMockProperty(String name) {
124 initializePropertiesMap();
125 if (!this.propertiesMap.containsKey(name)) {
126 return null;
127 }
128 final MockProperty mockProperty = this.propertiesMap.get(name);
129 if (mockProperty.isRemoved()) {
130 this.propertiesMap.remove(name);
131 return null;
132 }
133 return mockProperty;
134 }
135
136 public Collection<MockProperty> getMockProperties() {
137 initializePropertiesMap();
138 final List<MockProperty> result = new ArrayList<MockProperty>();
139 final Iterator<MockProperty> mockPropertyIterator = this.propertiesMap.values().iterator();
140 while (mockPropertyIterator.hasNext()) {
141 final MockProperty mockProperty = mockPropertyIterator.next();
142 if (mockProperty.isRemoved()) {
143 mockPropertyIterator.remove();
144 } else {
145 result.add(mockProperty);
146 }
147 }
148 return result;
149 }
150
151 public MockNode getMockChildNode(String name) {
152 if (childNodes == null) {
153 return null;
154 }
155 Iterator<MockNode> childIterator = childNodes.iterator();
156 while (childIterator.hasNext()) {
157 MockNode child = childIterator.next();
158 if (child.isRemoved()) {
159 childIterator.remove();
160 } else if (name.equals(child.getMockNodeName())) {
161 return child;
162 }
163 }
164 return null;
165 }
166
167 public List<MockNode> getMockChildNodesByName(String name) {
168 if (childNodes == null) {
169 return Collections.emptyList();
170 }
171 List<MockNode> foundNodes = new ArrayList<MockNode>();
172 Iterator<MockNode> childIterator = childNodes.iterator();
173 while (childIterator.hasNext()) {
174 MockNode child = childIterator.next();
175 if (child.isRemoved()) {
176 childIterator.remove();
177 } else if (name.equals(child.getMockNodeName())) {
178 foundNodes.add(child);
179 }
180 }
181 return foundNodes;
182 }
183
184 public void setMockProperty(MockProperty property) {
185 initializePropertiesMap();
186 property.setParent(this);
187 this.propertiesMap.put(property.getMockPropertyName(), property);
188 }
189
190 public String getMockNodeName() {
191 return name;
192 }
193
194 public void setMockNodeName(String name) {
195 this.name = name;
196 }
197
198 public boolean isRemoved() {
199 return removed;
200 }
201
202 public void setRemoved(final boolean removed) {
203 this.removed = removed;
204 }
205
206 public MockNode getParent() {
207 return parent;
208 }
209
210 public void setParent(MockNode parent) {
211 this.parent = parent;
212 }
213
214 public String getPath() {
215 if (MockNode.getRooMockNode() == this) {
216 return "/";
217 }
218 int index = getIndex();
219 if (this.parent == rootMockNode) {
220 if (index > 1) {
221 return "/"+this.name+"["+index+"]";
222 }
223 return "/" + this.name;
224 } else {
225 if (index > 1) {
226 return this.parent.getPath() + "/" + this.name+"["+index+"]";
227 }
228 return this.parent.getPath() + "/" + this.name;
229 }
230 }
231
232 public void buildTree(final MockNode parent) {
233 this.parent = parent;
234 if (this.properties != null) {
235 for (MockProperty property : this.properties) {
236 property.setParent(this);
237 }
238 }
239 if (childNodes != null) {
240 for (MockNode childNode : childNodes) {
241 childNode.buildTree(this);
242 }
243 }
244 }
245
246 public int getIndex() {
247 if (this.parent == null) {
248 return 0;
249 }
250 int index = 1;
251 for (MockNode sibling : this.parent.childNodes) {
252 if (this.name.equals(sibling.name)) {
253 if (this.equals(sibling)) {
254 return index;
255 }
256 index++;
257 }
258 }
259 return 0;
260 }
261
262 public Node getJcrMock() throws RepositoryException {
263 return mockJcrNode(this);
264 }
265
266
267
268
269
270
271
272
273 public static Node mockJcrNode(final MockNode mockNode) throws RepositoryException {
274 Node jcrNode = Mockito.mock(Node.class);
275 Mockito.when(jcrNode.getName()).thenReturn(mockNode.getMockNodeName());
276
277 mockUuid(mockNode, jcrNode);
278
279 mockMixins(mockNode, jcrNode);
280
281 final Answer<NodeIterator> nodeIteratorAnswer = new NodeIteratorAnswer(mockNode);
282 Mockito.when(jcrNode.getNodes(Matchers.anyString())).thenAnswer(nodeIteratorAnswer);
283 Mockito.when(jcrNode.getNodes()).thenAnswer(nodeIteratorAnswer);
284
285 Mockito.when(jcrNode.getProperties()).thenAnswer(new PropertyIteratorAnswer(mockNode));
286
287 final ItemAnswer itemAnswer = new ItemAnswer(mockNode);
288 Mockito.when(jcrNode.getNode(Matchers.anyString())).thenAnswer(itemAnswer);
289 Mockito.when(jcrNode.getProperty(Matchers.anyString())).thenAnswer(itemAnswer);
290 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.anyLong())).thenAnswer(itemAnswer);
291 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.anyDouble())).thenAnswer(itemAnswer);
292 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.anyString())).thenAnswer(itemAnswer);
293 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.anyBoolean())).thenAnswer(itemAnswer);
294 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.any(String[].class))).thenAnswer(itemAnswer);
295 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.any(Calendar.class))).thenAnswer(itemAnswer);
296 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.any(Value.class))).thenAnswer(itemAnswer);
297 Mockito.when(jcrNode.setProperty(Matchers.anyString(), Matchers.any(Value[].class))).thenAnswer(itemAnswer);
298 Mockito.when(jcrNode.addNode(Matchers.anyString())).thenAnswer(itemAnswer);
299 Mockito.when(jcrNode.addNode(Matchers.anyString(), Matchers.anyString())).thenAnswer(itemAnswer);
300 Mockito.when(jcrNode.getParent()).thenAnswer(itemAnswer);
301 Mockito.doAnswer(new Answer() {
302 public Object answer(final InvocationOnMock invocationOnMock) {
303 mockNode.setRemoved(true);
304 return null;
305 }
306 }).when(jcrNode).remove();
307
308 Mockito.when(jcrNode.getPath()).thenAnswer(new Answer<String>() {
309 public String answer(final InvocationOnMock invocationOnMock) {
310 return mockNode.getPath();
311 }
312 });
313
314 final UnsupportedOperationException unsupportedOperation = new UnsupportedOperationException("The method getProperties(pattern) is not supported yet.");
315 Mockito.doThrow(unsupportedOperation).when(jcrNode).getProperties(Matchers.anyString());
316
317 final MockProperty primaryTypeProperty = mockNode.getMockProperty("jcr:primaryType");
318 Mockito.when(jcrNode.isNodeType(Matchers.anyString())).thenAnswer(new Answer<Boolean>() {
319 public Boolean answer(InvocationOnMock invocationOnMock) {
320 final Object args[] = invocationOnMock.getArguments();
321 return primaryTypeProperty != null && args[0] instanceof String && (args[0]).equals(primaryTypeProperty.getMockValues().get(0));
322 }
323 });
324
325 final NodeType primaryNodeType = Mockito.mock(NodeType.class);
326 Mockito.when(primaryNodeType.getName()).thenReturn(primaryTypeProperty.getMockValues().get(0));
327 Mockito.when(jcrNode.getPrimaryNodeType()).thenReturn(primaryNodeType);
328
329 Mockito.when(jcrNode.hasProperty(Matchers.anyString())).thenAnswer(new Answer<Boolean>() {
330 public Boolean answer(InvocationOnMock invocationOnMock) {
331 final Object args[] = invocationOnMock.getArguments();
332 return mockNode.getMockProperty((String) args[0]) != null;
333 }
334 });
335 Mockito.when(jcrNode.hasNode(Matchers.anyString())).thenAnswer(new Answer<Boolean>() {
336 public Boolean answer(InvocationOnMock invocationOnMock) {
337 final Object args[] = invocationOnMock.getArguments();
338 return mockNode.getMockChildNode((String) args[0]) != null;
339 }
340 });
341 Mockito.when(jcrNode.getIndex()).thenAnswer(new Answer<Integer>() {
342 public Integer answer(final InvocationOnMock invocationOnMock) {
343 return mockNode.getIndex();
344 }
345 });
346
347 if (rootMockNode == null) {
348
349 rootMockNode = mockNode;
350 session = Mockito.mock(Session.class);
351 Mockito.when(session.getItem(Matchers.anyString())).thenAnswer(itemAnswer);
352 Mockito.when(session.getRootNode()).thenAnswer(itemAnswer);
353 final Workspace mockWorkspace = Mockito.mock(Workspace.class);
354 final VersionManager versionManager = Mockito.mock(VersionManager.class);
355 Mockito.when(session.getWorkspace()).thenReturn(mockWorkspace);
356 Mockito.when(mockWorkspace.getVersionManager()).thenReturn(versionManager);
357 Mockito.when(session.itemExists(Matchers.anyString())).thenAnswer(new Answer<Boolean>() {
358 public Boolean answer(final InvocationOnMock invocationOnMock) throws RepositoryException {
359 return itemAnswer.getItem(invocationOnMock.getArguments()) != null;
360 }
361 });
362 }
363
364 Mockito.when(jcrNode.getSession()).thenReturn(session);
365
366 return jcrNode;
367 }
368
369 private static void mockMixins(MockNode mockNode, Node jcrNode) throws RepositoryException {
370 final MockProperty mixinProperty = mockNode.getMockProperty("jcr:mixinTypes");
371 if (mixinProperty != null) {
372 final List<String> values = mixinProperty.getMockValues();
373 final List<NodeType> nodeTypes = new ArrayList<NodeType>();
374 for (String value : values) {
375 final NodeType nodeType = Mockito.mock(NodeType.class);
376 Mockito.when(nodeType.getName()).thenReturn(value);
377 nodeTypes.add(nodeType);
378 }
379 Mockito.when(jcrNode.getMixinNodeTypes()).thenReturn(nodeTypes.toArray(new NodeType[nodeTypes.size()]));
380 }
381 }
382
383 private static void mockUuid(MockNode mockNode, Node jcrNode) throws RepositoryException {
384 final MockProperty uuidProperty = mockNode.getMockProperty("jcr:uuid");
385 if (uuidProperty != null) {
386 final List<String> values = uuidProperty.getMockValues();
387 if (values.size() == 1) {
388 Mockito.when(jcrNode.getIdentifier()).thenReturn(values.get(0));
389 }
390 }
391 }
392
393
394
395
396 public static void invalidateSession() {
397 rootMockNode = null;
398 session = Mockito.mock(Session.class);
399 }
400
401 public static MockNode getRooMockNode() {
402 return rootMockNode;
403 }
404 }