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