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.form.field.transformer.multi;
35
36 import info.magnolia.jcr.util.NodeTypes;
37 import info.magnolia.jcr.util.NodeUtil;
38 import info.magnolia.jcr.util.PropertyUtil;
39 import info.magnolia.ui.form.field.definition.ConfiguredFieldDefinition;
40 import info.magnolia.ui.form.field.transformer.basic.BasicTransformer;
41 import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty;
42 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
43 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
44
45 import java.text.DecimalFormat;
46 import java.util.ArrayList;
47 import java.util.HashSet;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Set;
51
52 import javax.jcr.Node;
53 import javax.jcr.PathNotFoundException;
54 import javax.jcr.RepositoryException;
55
56 import org.apache.jackrabbit.commons.predicate.Predicate;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import com.vaadin.data.Item;
61 import com.vaadin.data.Property;
62 import com.vaadin.data.util.PropertysetItem;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public class MultiValueChildrenNodeTransformer extends BasicTransformer<PropertysetItem> {
80
81 private static final Logger log = LoggerFactory.getLogger(MultiValueChildrenNodeTransformer.class);
82
83 protected String childNodeType = NodeTypes.ContentNode.NAME;
84 private String childValuePropertyName;
85
86 public MultiValueChildrenNodeTransformer(Item relatedFormItem, ConfiguredFieldDefinition definition, Class<PropertysetItem> type) {
87 super(relatedFormItem, definition, type);
88 this.childValuePropertyName = definition.getName();
89 }
90
91
92
93
94 @Override
95 public boolean hasI18NSupport() {
96 return false;
97 }
98
99
100
101
102
103
104
105 @Override
106 public PropertysetItem readFromItem() {
107 PropertysetItem newValues = new PropertysetItem();
108 JcrNodeAdapter rootItem = getRootItem();
109
110 List<Node> childNodes = getStoredChildNodes(rootItem);
111 int position = 0;
112 for (Node child : childNodes) {
113 Object value = getValueFromChildNode(child);
114 if (value != null) {
115 newValues.addItemProperty(position, new DefaultProperty(value));
116 position += 1;
117 }
118 }
119 return newValues;
120 }
121
122
123
124
125
126
127
128 @Override
129 public void writeToItem(PropertysetItem newValue) {
130
131 JcrNodeAdapter rootItem = getRootItem();
132 rootItem.getChildren().clear();
133
134 setNewChildItem(rootItem, newValue);
135
136 detachNoMoreExistingChildren(rootItem);
137
138 handleRootitemAndParent(rootItem);
139 }
140
141
142
143
144 protected JcrNodeAdapter getRootItem() {
145 return (JcrNodeAdapter) relatedFormItem;
146 }
147
148
149
150
151
152 protected List<Node> getStoredChildNodes(JcrNodeAdapter parent) {
153 List<Node> res = new ArrayList<Node>();
154 try {
155 if (!(parent instanceof JcrNewNodeAdapter) && parent.getJcrItem().hasNodes()) {
156 Predicate predicate = createPredicateToEvaluateChildNode();
157 if (predicate != null) {
158 res = NodeUtil.asList(NodeUtil.getNodes(parent.getJcrItem(), predicate));
159 } else {
160 res = NodeUtil.asList(NodeUtil.getNodes(parent.getJcrItem(), childNodeType));
161 }
162 }
163 } catch (RepositoryException re) {
164 log.warn("Not able to access the Child Nodes of the following Node Identifier {}", parent.getItemId(), re);
165 }
166 return res;
167 }
168
169
170
171
172
173 protected Predicate createPredicateToEvaluateChildNode() {
174
175 return new Predicate() {
176 @Override
177 public boolean evaluate(Object node) {
178 if (node instanceof Node) {
179 try {
180 return ((Node) node).getName().matches("[0-9]+");
181 } catch (RepositoryException e) {
182 return false;
183 }
184 }
185 return false;
186 }
187 };
188 }
189
190
191
192
193 protected Object getValueFromChildNode(Node child) {
194 try {
195 if (child.hasProperty(childValuePropertyName)) {
196 return PropertyUtil.getPropertyValueObject(child, childValuePropertyName);
197 }
198 } catch (RepositoryException re) {
199 log.warn("Not able to access the Child Nodes property of the following Child Node Name {}", NodeUtil.getName(child), re);
200 }
201 return null;
202 }
203
204
205 protected void setNewChildItem(JcrNodeAdapter rootItem, PropertysetItem newValue) {
206
207 Set<String> childNames = new HashSet<String>();
208 Node rootNode = rootItem.getJcrItem();
209 try {
210 Iterator<?> it = newValue.getItemPropertyIds().iterator();
211 while (it.hasNext()) {
212 Property<?> p = newValue.getItemProperty(it.next());
213
214 if (p == null || p.getValue() == null) {
215 continue;
216 }
217 Object value = p.getValue();
218
219 String childName = createChildItemName(childNames, value, rootItem);
220
221 JcrNodeAdapter childItem = initializeChildItem(rootItem, rootNode, childName);
222
223 setChildItemValue(childItem, value);
224 }
225 } catch (Exception e) {
226 log.warn("Not able to create a Child Item for {} ", rootItem.getItemId(), e);
227 }
228 }
229
230
231
232
233 protected void setChildItemValue(JcrNodeAdapter childItem, Object value) {
234 childItem.addItemProperty(childValuePropertyName, new DefaultProperty(value));
235 }
236
237
238
239
240
241
242 protected JcrNodeAdapter initializeChildItem(JcrNodeAdapter rootItem, Node rootNode, String childName) throws PathNotFoundException, RepositoryException {
243 JcrNodeAdapter childItem = null;
244 if (!(rootItem instanceof JcrNewNodeAdapter) && rootNode.hasNode(childName)) {
245 childItem = new JcrNodeAdapter(rootNode.getNode(childName));
246 } else {
247 childItem = new JcrNewNodeAdapter(rootNode, childNodeType, childName);
248 }
249 rootItem.addChild(childItem);
250 return childItem;
251 }
252
253
254
255
256 private void detachNoMoreExistingChildren(JcrNodeAdapter rootItem) {
257 try {
258 List<Node> children = getStoredChildNodes(rootItem);
259 for (Node child : children) {
260 if (rootItem.getChild(child.getName()) == null) {
261 JcrNodeAdapter toRemove = new JcrNodeAdapter(child);
262 rootItem.removeChild(toRemove);
263 }
264 }
265 } catch (RepositoryException e) {
266 log.error("Could remove children", e);
267 }
268 }
269
270
271
272
273
274
275
276
277 protected void handleRootitemAndParent(JcrNodeAdapter rootItem) {
278
279 }
280
281
282
283
284 protected String createChildItemName(Set<String> childNames, Object value, JcrNodeAdapter rootItem) {
285 int nb = 0;
286 String name = "00";
287 DecimalFormat df = new DecimalFormat("00");
288 while (childNames.contains(name)) {
289 nb += 1;
290 name = df.format(nb);
291 }
292 childNames.add(name);
293 return name;
294 }
295
296 public void setChildValuePropertyName(String newName) {
297 this.childValuePropertyName = newName;
298 }
299
300
301
302
303 protected JcrNodeAdapter getOrCreateChildNode(String childNodeName, String childNodeType) throws RepositoryException {
304 JcrNodeAdapter child = null;
305 if (!(relatedFormItem instanceof JcrNodeAdapter)) {
306 log.warn("Try to retrieve a Jcr Item from a Non Jcr Item Adapter. Will retrun null");
307 return null;
308 }
309 Node node = ((JcrNodeAdapter) relatedFormItem).getJcrItem();
310 if (node.hasNode(childNodeName) && !(relatedFormItem instanceof JcrNewNodeAdapter)) {
311 child = new JcrNodeAdapter(node.getNode(childNodeName));
312 child.setParent(((JcrNodeAdapter) relatedFormItem));
313 } else {
314 child = new JcrNewNodeAdapter(node, childNodeType, childNodeName);
315 child.setParent(((JcrNodeAdapter) relatedFormItem));
316 }
317 return child;
318 }
319
320 }