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.editor;
35
36 import static java.util.stream.Collectors.*;
37
38 import info.magnolia.objectfactory.Components;
39 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
40 import info.magnolia.ui.contentapp.configuration.column.ColumnDefinition;
41 import info.magnolia.ui.field.FieldDefinition;
42 import info.magnolia.ui.field.NoopNameDecorator;
43 import info.magnolia.ui.field.WithPropertyNameDecorator.PropertyNameDecorator;
44
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.List;
48 import java.util.Locale;
49 import java.util.Map;
50 import java.util.Optional;
51 import java.util.stream.Stream;
52
53 import javax.jcr.Item;
54 import javax.jcr.Node;
55
56 import com.machinezoo.noexception.Exceptions;
57 import com.vaadin.data.PropertyDefinition;
58 import com.vaadin.data.PropertySet;
59 import com.vaadin.data.ValueProvider;
60 import com.vaadin.server.Setter;
61
62 import lombok.Data;
63 import lombok.extern.slf4j.Slf4j;
64
65
66
67
68
69
70
71
72
73
74 @Slf4j
75 public class JcrItemPropertySet implements PropertySet<Item> {
76
77
78
79
80
81
82
83
84 @Deprecated
85 public static JcrItemPropertySet withProperties(Map<String, Class> properties) {
86 List<JcrItemPropertySet.JcrPropertyDescriptor> propertyDescriptors = properties.entrySet().stream()
87 .map(entry -> JcrPropertyDescriptor.builder()
88 .type(entry.getValue())
89 .name(entry.getKey())
90 .build())
91 .collect(toList());
92
93 return new JcrItemPropertySet(propertyDescriptors, Components.getComponent(I18NAuthoringSupport.class));
94 }
95
96
97
98
99
100
101
102
103 @Deprecated
104 public static <T> PropertySet<Item> fromColumns(List<ColumnDefinition<T>> columnDefinitions) {
105 return withProperties(columnDefinitions.stream().collect(toMap(ColumnDefinition::getName, ColumnDefinition::getType)));
106 }
107
108
109
110
111
112
113
114 public static PropertySet<Item> fromFieldDefinitions(Collection<FieldDefinition> fieldDefinitions, Locale locale) {
115
116 return new JcrItemPropertySet(fieldDefinitions.stream()
117 .map(fieldDefinition -> JcrPropertyDescriptor
118 .builder()
119 .name(fieldDefinition.getName())
120 .isReadonly(fieldDefinition.isReadOnly())
121 .type(fieldDefinition.getType())
122 .build())
123 .collect(toList()), locale, Components.getComponent(I18NAuthoringSupport.class), null);
124 }
125
126 private final List<PropertyDefinition<Item, ?>> knownProperties = new ArrayList<>();
127 private final Locale locale;
128 private final I18NAuthoringSupport<Item> genericLocalisationSupport;
129 private final PropertyNameDecorator propertyNameDecorator;
130
131 public JcrItemPropertySet(List<JcrPropertyDescriptor> knownProperties, I18NAuthoringSupport<Item> genericLocalisationSupport) {
132 this(knownProperties, null, genericLocalisationSupport, new NoopNameDecorator());
133 }
134
135 public JcrItemPropertySet(List<JcrPropertyDescriptor> knownProperties, Locale locale, I18NAuthoringSupport<Item> genericLocalisationSupport) {
136 this(knownProperties, locale, genericLocalisationSupport, new NoopNameDecorator());
137 }
138
139 public JcrItemPropertySet(List<JcrPropertyDescriptor> knownProperties, Locale locale, I18NAuthoringSupport<Item> genericLocalisationSupport, PropertyNameDecorator propertyNameDecorator) {
140 this.locale = locale;
141 this.genericLocalisationSupport = genericLocalisationSupport;
142 this.propertyNameDecorator = propertyNameDecorator;
143
144 knownProperties.forEach(property -> this.knownProperties.add(new JcrItemPropertyDefinition<>(this, property)));
145 }
146
147 @Override
148 public Stream<PropertyDefinition<Item, ?>> getProperties() {
149 return knownProperties.stream();
150 }
151
152 @Override
153 public Optional<PropertyDefinition<Item, ?>> getProperty(String name) {
154 return Optional.of(knownProperties.stream()
155 .filter(def -> def.getName().equals(name))
156 .findFirst()
157 .orElse(getDecoratedProperty(name)));
158 }
159
160 private PropertyDefinition<Item, ?> getDecoratedProperty(String name) {
161 return Optional.of(knownProperties.stream()
162 .filter(def -> def.getName().equals(propertyNameDecorator.apply(name)))
163 .findFirst()
164 .orElse(new JcrItemPropertyDefinition<>(this, JcrItemPropertySet.JcrPropertyDescriptor.builder()
165 .type(Object.class)
166 .name(name)
167 .build()))).get();
168 }
169
170
171
172
173
174
175 @Data
176 public static class JcrPropertyDescriptor<T> {
177 private Class<T> type;
178 private String name;
179 private String nodeNameProperty;
180 private boolean isReadonly;
181 private boolean isI18n;
182 private Locale locale;
183 private PropertyNameDecorator propertyNameDecorator = new NoopNameDecorator();
184
185 public JcrPropertyDescriptor() {
186 }
187
188 JcrPropertyDescriptor(Class<T> type, String name, boolean isReadonly, boolean isI18n, Locale locale, PropertyNameDecorator propertyNameDecorator, String nodeNameProperty) {
189 this.type = type;
190 this.name = name;
191 this.isReadonly = isReadonly;
192 this.isI18n = isI18n;
193 this.locale = locale;
194 this.nodeNameProperty = nodeNameProperty;
195 if (propertyNameDecorator != null) {
196 this.propertyNameDecorator = propertyNameDecorator;
197 }
198 }
199
200 public static <T> JcrPropertyDescriptorBuilder<T> builder() {
201 return new JcrPropertyDescriptorBuilder<T>();
202 }
203
204 public String getName() {
205 return this.propertyNameDecorator.apply(this.name);
206 }
207
208
209
210
211 @Deprecated
212 public void setDefaultValue(T defaultValue) {
213 log.warn("JcrPropertyDescriptor#setDefaultValue is deprecated since 6.2.4, doesn't keep the default value");
214 }
215
216
217
218
219 @Deprecated
220 public T getDefaultValue() {
221 log.warn("JcrPropertyDescriptor#getDefaultValue is deprecated since 6.2.4, doesn't keep the default value configuration and returns null");
222 return null;
223 }
224
225
226
227
228
229
230
231 public static class JcrPropertyDescriptorBuilder<T> {
232 private Class<T> type;
233 private String name;
234 private boolean isReadonly;
235 private boolean isI18n;
236 private Locale locale;
237 private PropertyNameDecorator propertyNameDecorator;
238 private String nodeNameProperty;
239
240 JcrPropertyDescriptorBuilder() {
241 }
242
243 public JcrPropertyDescriptorBuilder<T> type(Class<T> type) {
244 this.type = type;
245 return this;
246 }
247
248 public JcrPropertyDescriptorBuilder<T> name(String name) {
249 this.name = name;
250 return this;
251 }
252
253 public JcrPropertyDescriptorBuilder<T> isReadonly(boolean isReadonly) {
254 this.isReadonly = isReadonly;
255 return this;
256 }
257
258 public JcrPropertyDescriptorBuilder<T> isI18n(boolean isI18n) {
259 this.isI18n = isI18n;
260 return this;
261 }
262
263 public JcrPropertyDescriptorBuilder<T> locale(Locale locale) {
264 this.locale = locale;
265 return this;
266 }
267
268 public JcrPropertyDescriptorBuilder<T> propertyNameDecorator(PropertyNameDecorator propertyNameDecorator) {
269 this.propertyNameDecorator = propertyNameDecorator;
270 return this;
271 }
272
273 public JcrPropertyDescriptorBuilder<T> nodeNameProperty(String nodeNameProperty) {
274 this.nodeNameProperty = nodeNameProperty;
275 return this;
276 }
277
278
279
280
281 @Deprecated
282 public JcrPropertyDescriptorBuilder<T> defaultValue(String ignoredDefaultValue) {
283 return this;
284 }
285
286 public JcrPropertyDescriptor<T> build() {
287 return new JcrPropertyDescriptor<T>(type, name, isReadonly, isI18n, locale, propertyNameDecorator, nodeNameProperty);
288 }
289
290 public String toString() {
291 return "JcrItemPropertySet.JcrPropertyDescriptor.JcrPropertyDescriptorBuilder(type=" + this.type + ", name=" + this.name + ", isReadonly=" + this.isReadonly + ", isI18n=" + this.isI18n + ", locale=" + this.locale + ", propertyNameDecorator=" + this.propertyNameDecorator + ", nodeNameProperty=" + this.nodeNameProperty + ")";
292 }
293 }
294 }
295
296
297
298
299
300
301
302
303 class JcrPropertyDescriptorWrapper<T> extends JcrPropertyDescriptor<T> {
304
305 private JcrPropertyDescriptor<T> delegate;
306
307 public JcrPropertyDescriptorWrapper(JcrPropertyDescriptor<T> delegate) {
308 this.delegate = delegate;
309 }
310
311 @Override
312 public Class<T> getType() {
313 return delegate.getType();
314 }
315
316 @Override
317 public void setType(Class<T> type) {
318 delegate.setType(type);
319 }
320
321 @Override
322 public String getName() {
323 return delegate.getName();
324 }
325
326 @Override
327 public void setName(String name) {
328 delegate.setName(name);
329 }
330
331 @Override
332 public boolean isReadonly() {
333 return delegate.isReadonly();
334 }
335
336 @Override
337 public void setReadonly(boolean isReadonly) {
338 delegate.setReadonly(isReadonly);
339 }
340
341 @Override
342 public boolean isI18n() {
343 return delegate.isI18n();
344 }
345
346 @Override
347 public void setI18n(boolean isI18n) {
348 delegate.setI18n(isI18n);
349 }
350
351 @Override
352 public Locale getLocale() {
353 return delegate.getLocale();
354 }
355
356 @Override
357 public void setLocale(Locale locale) {
358 delegate.setLocale(locale);
359 }
360
361 @Override
362 public PropertyNameDecorator getPropertyNameDecorator() {
363 return delegate.getPropertyNameDecorator();
364 }
365
366 @Override
367 public void setPropertyNameDecorator(PropertyNameDecorator propertyNameDecorator) {
368 delegate.setPropertyNameDecorator(propertyNameDecorator);
369 }
370
371 @Override
372 public String getNodeNameProperty() {
373 return delegate.getNodeNameProperty();
374 }
375
376 @Override
377 public void setNodeNameProperty(String nodeNameProperty) {
378 delegate.setNodeNameProperty(nodeNameProperty);
379 }
380 }
381
382
383
384
385
386
387
388
389
390 class LocalisedJcrPropertyDescriptor<T> extends JcrPropertyDescriptorWrapper<T> {
391
392 private final Node relatedNode;
393
394 LocalisedJcrPropertyDescriptor(JcrPropertyDescriptor<T> delegate, Node relatedNode) {
395 super(delegate);
396 this.relatedNode = relatedNode;
397 }
398
399 @Override
400 public String getName() {
401 return getName(relatedNode);
402 }
403
404 public String getName(Node node) {
405 if (locale != null &&
406 isI18n() &&
407 !genericLocalisationSupport.isDefaultLocale(locale, node)) {
408 return genericLocalisationSupport.deriveLocalisedPropertyName(super.getName(), locale);
409 }
410 return super.getName();
411 }
412 }
413
414
415
416
417
418
419
420
421 private class JcrItemPropertyDefinition<V> implements PropertyDefinition<Item, V> {
422
423 private final PropertySet<Item> propertySet;
424 private final JcrItemPropertySet.JcrPropertyDescriptor<V> descriptor;
425
426 private JcrItemPropertyDefinition(PropertySet<Item> propertySet, JcrPropertyDescriptor<V> descriptor) {
427 this.propertySet = propertySet;
428 this.descriptor = descriptor;
429 }
430
431 @Override
432 public ValueProvider<Item, V> getGetter() {
433 return item -> {
434 JcrPropertyDescriptor<V> descriptor = this.descriptor;
435 if (item.isNode()) {
436 descriptor = new LocalisedJcrPropertyDescriptor<>(descriptor, (Node) item);
437 }
438 return JcrItemInteractionStrategy.get(item).get(item, descriptor);
439 };
440 }
441
442 @Override
443 public Optional<Setter<Item, V>> getSetter() {
444 return Optional.of((Setter<Item, V>) (Item item, V value) -> {
445 JcrPropertyDescriptor<V> descriptor = this.descriptor;
446 if (item.isNode()) {
447 descriptor = new LocalisedJcrPropertyDescriptor<>(descriptor, (Node) item);
448 }
449
450 boolean isPropertyUpdatePermitted = !descriptor.isReadonly;
451
452 if (!isPropertyUpdatePermitted && item.isNode()) {
453 Node asNode = (Node) item;
454 String propertyName = descriptor.getName();
455
456 isPropertyUpdatePermitted = !Exceptions.wrap().get(() -> asNode.hasProperty(propertyName));
457 }
458
459 if (isPropertyUpdatePermitted) {
460 JcrItemInteractionStrategy.get(item).set(item, value, descriptor);
461 }
462 });
463 }
464
465 @Override
466 public Class<V> getType() {
467 return descriptor.getType();
468 }
469
470 @Override
471 public Class<?> getPropertyHolderType() {
472 return Node.class;
473 }
474
475 @Override
476 public String getName() {
477 return descriptor.getName();
478 }
479
480 @Override
481 public String getCaption() {
482 return descriptor.getName();
483 }
484
485 @Override
486 public PropertySet<Item> getPropertySet() {
487 return propertySet;
488 }
489 }
490 }