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.ui.vaadin.integration.jcr;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.jcr.RuntimeRepositoryException;
38 import info.magnolia.jcr.util.NodeUtil;
39 import info.magnolia.jcr.util.PropertyUtil;
40
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.LinkedHashMap;
44 import java.util.LinkedList;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Map.Entry;
48
49 import javax.jcr.Item;
50 import javax.jcr.Node;
51 import javax.jcr.NodeIterator;
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang3.StringUtils;
55 import org.apache.jackrabbit.JcrConstants;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 import com.vaadin.v7.data.Property;
60 import com.vaadin.v7.data.util.ObjectProperty;
61
62
63
64
65
66 @Deprecated
67 public abstract class AbstractJcrNodeAdapter extends AbstractJcrAdapter {
68
69 private static final Logger log = LoggerFactory.getLogger(AbstractJcrNodeAdapter.class);
70
71 private String primaryNodeType;
72
73 private final Map<String, AbstractJcrNodeAdapter> children = new LinkedHashMap<>();
74
75 private final Map<String, AbstractJcrNodeAdapter> removedChildren = new HashMap<>();
76
77 private AbstractJcrNodeAdapter parent;
78
79 private String nodeName;
80
81 private boolean childItemChanges = false;
82
83 public AbstractJcrNodeAdapter(Node jcrNode) {
84 super(jcrNode);
85 }
86
87 @Override
88 public boolean isNode() {
89 return true;
90 }
91
92 @Override
93 protected void initCommonAttributes(Item jcrItem) {
94 super.initCommonAttributes(jcrItem);
95 Node node = (Node) jcrItem;
96 try {
97 if (StringUtils.isBlank(primaryNodeType)) {
98 primaryNodeType = node.getPrimaryNodeType().getName();
99 }
100 } catch (RepositoryException e) {
101 log.error("Could not determine primaryNodeType name of JCR node", e);
102 primaryNodeType = UNIDENTIFIED;
103 }
104 }
105
106 protected void setPrimaryNodeTypeName(String primaryNodeTypeName) {
107 this.primaryNodeType = primaryNodeTypeName;
108 }
109
110
111
112
113
114
115 public String getPrimaryNodeTypeName() {
116 return primaryNodeType;
117 }
118
119 protected Map<String, AbstractJcrNodeAdapter> getRemovedChildren() {
120 return removedChildren;
121 }
122
123
124
125
126
127
128
129 @Override
130 public Node getJcrItem() {
131 return (Node)super.getJcrItem();
132 }
133
134
135
136
137 @Override
138 public boolean addItemProperty(Object id, Property property) {
139
140 log.debug("Add new Property Item name " + id + " with value " + property.getValue());
141 try {
142 Node node = getJcrItem();
143 String propertyName = (String) id;
144 if (!node.hasProperty(propertyName)) {
145
146 node.setProperty(propertyName, (String) property.getValue());
147 getChangedProperties().put((String)id, property);
148 return true;
149 } else {
150 log.warn("Property " + id + " already exist.");
151 return false;
152 }
153 } catch (RepositoryException e) {
154 log.error("Unable to add JCR property", e);
155 return false;
156 }
157 }
158
159
160
161
162
163 @Override
164 public Property getItemProperty(Object id) {
165 Object value;
166 Class type = String.class;
167 try {
168 final Node jcrNode = getJcrItem();
169 if (!jcrNode.hasProperty((String) id)) {
170 if (ModelConstants.JCR_NAME.equals(id)) {
171 value = jcrNode.getName();
172 } else {
173 return null;
174 }
175 } else {
176 value = PropertyUtil.getPropertyValueObject(jcrNode, String.valueOf(id));
177 type = value.getClass();
178 }
179
180
181 boolean readOnly = isNodeProtected(jcrNode) || isPropertyProtected(id);
182 Property property = new ObjectProperty(value, type, readOnly);
183 getChangedProperties().put((String) id, property);
184 return property;
185 } catch (RepositoryException e) {
186 throw new RuntimeRepositoryException(e);
187 }
188 }
189
190 boolean isNodeProtected(Node jcrNode) throws RepositoryException {
191 return jcrNode != null && NodeUtil.isNodeType(jcrNode, JcrConstants.NT_FROZENNODE);
192 }
193
194 boolean isPropertyProtected(Object id) {
195 return JcrConstants.JCR_UUID.equals(id) || JcrConstants.JCR_PRIMARYTYPE.equals(id);
196 }
197
198
199
200
201
202
203 @Override
204 public Node applyChanges() throws RepositoryException {
205
206 Node node = getJcrItem();
207
208
209 updateProperties(node);
210 updateChildren(node);
211
212 return node;
213 }
214
215
216
217
218
219
220 public void updateChildren(Node node) throws RepositoryException {
221 if (!children.isEmpty()) {
222 List<String> sortedChildIdentifiers = new LinkedList<>();
223 for (AbstractJcrNodeAdapter child : children.values()) {
224
225 child.applyChanges();
226 sortedChildIdentifiers.add(child.getJcrItem().getIdentifier());
227 }
228 if (node.getPrimaryNodeType().hasOrderableChildNodes()) {
229 sortChildren(node, sortedChildIdentifiers);
230 }
231 }
232
233
234 if (!removedChildren.isEmpty()) {
235 for (AbstractJcrNodeAdapter removedChild : removedChildren.values()) {
236 if (node.hasNode(removedChild.getNodeName())) {
237 node.getNode(removedChild.getNodeName()).remove();
238 }
239 }
240 }
241 }
242
243
244
245
246 private void sortChildren(Node node, List<String> sortedIdentifiers) throws RepositoryException {
247
248 List<String> unsortedIdentifiers = new ArrayList<>();
249
250 for (NodeIterator it = node.getNodes(); it.hasNext();) {
251 unsortedIdentifiers.add(it.nextNode().getIdentifier());
252 }
253
254 for (int pos = 0; pos < sortedIdentifiers.size(); pos++) {
255 String current = sortedIdentifiers.get(pos);
256 int nodePos = unsortedIdentifiers.indexOf(current);
257
258 if (nodePos != -1 && nodePos != pos) {
259 Node nodeToMove = node.getSession().getNodeByIdentifier(current);
260 Node target = node.getSession().getNodeByIdentifier(unsortedIdentifiers.get(pos));
261
262 NodeUtil.moveNodeBefore(nodeToMove, target);
263 String movedId = unsortedIdentifiers.remove(nodePos);
264 unsortedIdentifiers.add(pos, movedId);
265 }
266 }
267 }
268
269 @Override
270 public void updateProperties(Item item) throws RepositoryException {
271 super.updateProperties(item);
272 if (item instanceof Node) {
273
274 Node node = (Node) item;
275 for (Entry<String, Property> entry : getRemovedProperties().entrySet()) {
276 if (node.hasProperty(entry.getKey())) {
277 node.getProperty(entry.getKey()).remove();
278 }
279 }
280 getRemovedProperties().clear();
281 }
282 }
283
284
285
286
287
288
289
290
291
292
293 @Override
294 protected void updateProperty(Item item, String propertyId, Property property) {
295 if (!(item instanceof Node)) {
296 return;
297 }
298 Node node = (Node) item;
299 if (ModelConstants.JCR_NAME.equals(propertyId)) {
300 String jcrName = (String) property.getValue();
301 try {
302 if (jcrName != null && !jcrName.isEmpty() && !jcrName.equals(node.getName())) {
303
304
305 jcrName = Path.getValidatedLabel(jcrName);
306 jcrName = Path.getUniqueLabel(node.getSession(), node.getParent().getPath(), jcrName);
307
308 NodeUtil.renameNode(node, jcrName);
309
310 setItemId(JcrItemUtil.getItemId(node));
311 }
312 } catch (RepositoryException e) {
313 log.error("Could not rename JCR Node.", e);
314 }
315 } else if (propertyId != null && !propertyId.isEmpty()) {
316 if (property.getValue() != null) {
317 try {
318 PropertyUtil.setProperty(node, propertyId, property.getValue());
319 } catch (RepositoryException e) {
320 log.error("Could not set JCR Property {}", propertyId, e);
321 }
322 } else {
323 try {
324 if (node.hasProperty(propertyId)) {
325 log.debug("Property '{}' has a null value: Will be removed", propertyId);
326
327 markPropertyForDeletion(propertyId);
328 }
329 } catch (RepositoryException e) {
330 log.error("Could not check for existence of JCR Property {}", propertyId, e);
331 }
332 }
333 }
334 }
335
336
337
338
339 protected void markPropertyForDeletion(String propertyId) {
340
341 getRemovedProperties().put(propertyId, null);
342 }
343
344
345
346
347
348 public AbstractJcrNodeAdapter getChild(String nodeName) {
349 return children.get(nodeName);
350 }
351
352 public Map<String, AbstractJcrNodeAdapter> getChildren() {
353 return children;
354 }
355
356
357
358
359
360 public AbstractJcrNodeAdapter addChild(AbstractJcrNodeAdapter child) {
361 childItemChanges = true;
362 if (removedChildren.containsKey(child.getNodeName())) {
363 removedChildren.remove(child.getNodeName());
364 }
365 child.setParent(this);
366 if (children.containsKey(child.getNodeName())) {
367 children.remove(child.getNodeName());
368 }
369 return children.put(child.getNodeName(), child);
370 }
371
372
373
374
375
376
377 public boolean removeChild(AbstractJcrNodeAdapter toRemove) {
378 childItemChanges = true;
379 removedChildren.put(toRemove.getNodeName(), toRemove);
380 return children.remove(toRemove.getNodeName()) != null;
381 }
382
383
384
385
386 public AbstractJcrNodeAdapter getParent() {
387 return parent;
388 }
389
390 public void setParent(AbstractJcrNodeAdapter parent) {
391 this.parent = parent;
392 }
393
394
395
396
397
398 public String getNodeName() {
399 return this.nodeName;
400 }
401
402 public void setNodeName(String nodeName) {
403 this.nodeName = nodeName;
404 }
405
406
407
408
409 public boolean hasChildItemChanges() {
410 return childItemChanges;
411 }
412 }