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 info.magnolia.jcr.util.NodeUtil.getName;
37 import static java.util.stream.Collectors.toList;
38
39 import info.magnolia.config.NamedDefinition;
40 import info.magnolia.jcr.predicate.AbstractPredicate;
41 import info.magnolia.jcr.util.NodeUtil;
42 import info.magnolia.objectfactory.ComponentProvider;
43 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
44 import info.magnolia.ui.field.ConfiguredComplexPropertyDefinition;
45 import info.magnolia.ui.field.NoopNameDecorator;
46 import info.magnolia.ui.field.WithPropertyNameDecorator;
47
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Optional;
51 import java.util.concurrent.CompletableFuture;
52 import java.util.stream.Stream;
53 import java.util.stream.StreamSupport;
54
55 import javax.inject.Inject;
56 import javax.jcr.Node;
57
58 import com.machinezoo.noexception.Exceptions;
59
60 import lombok.AllArgsConstructor;
61 import lombok.EqualsAndHashCode;
62 import lombok.Getter;
63 import lombok.Setter;
64
65
66
67
68 public abstract class ByIndexedChildNodes implements MultiFormView.EntryResolution<Node> {
69
70 private static final String INCREMENT_REGEX = "(\\d{1,3})";
71
72 private final I18NAuthoringSupport<Node> i18NAuthoringSupport;
73
74 private final Locale locale;
75
76 protected final info.magnolia.ui.editor.ByIndexedChildNodes.Definition definition;
77
78 protected final NamedDefinition propertyDefinition;
79
80 private final WithPropertyNameDecorator.PropertyNameDecorator propertyNameDecorator;
81
82 @Inject
83 public ByIndexedChildNodes(info.magnolia.ui.editor.ByIndexedChildNodes.Definition definition, NamedDefinition relatedPropertyDefinition, I18NAuthoringSupport<Node> i18NAuthoringSupport, ComponentProvider componentProvider, Locale locale) {
84 this.definition = definition;
85 this.propertyDefinition = relatedPropertyDefinition;
86 this.i18NAuthoringSupport = i18NAuthoringSupport;
87 this.locale = locale;
88 this.propertyNameDecorator = componentProvider.newInstance(definition.propertyNameDecorator);
89 }
90
91
92
93
94 @Deprecated
95 public ByIndexedChildNodes(NamedDefinition relatedPropertyDefinition, I18NAuthoringSupport<Node> i18NAuthoringSupport, ComponentProvider componentProvider, Locale locale) {
96 this(new info.magnolia.ui.editor.ByIndexedChildNodes.Definition(), relatedPropertyDefinition, i18NAuthoringSupport, componentProvider, locale);
97 }
98
99 @Override
100 public Stream<ComplexPropertyDefinition<Node>> resolveForRoot(Node rootNode) {
101 List<Node> childItems = getChildNodes(rootNode, getEntryPropertyNameBase()).collect(toList());
102 Stream.Builder<ComplexPropertyDefinition<Node>> collector = Stream.builder();
103 for (int idx = 0; idx < childItems.size(); ++idx) {
104 resolvePropertyDefinition(childItems.get(idx), idx).ifPresent(collector::add);
105 }
106 return collector.build();
107 }
108
109 protected String getEntryPropertyNameBase() {
110 return this.propertyNameDecorator.apply(propertyDefinition.getName());
111 }
112
113 @Override
114 public CompletableFuture<ComplexPropertyDefinition<Node>> pick() {
115 return CompletableFuture.completedFuture(resolvePropertyDefinition(null, -1).orElse(null));
116 }
117
118 protected abstract Optional<EditorDefinition<Node>> resolveEntryEditorDefinition(Node item, int index);
119
120 protected Optional<ConfiguredComplexPropertyDefinition<Node>> resolvePropertyDefinition(Node item, int index) {
121 return resolveEntryEditorDefinition(item, index)
122 .map(entryEditorDefinition -> {
123 ConfiguredComplexPropertyDefinition<Node> property = new ConfiguredComplexPropertyDefinition.Wrapper<>(entryEditorDefinition);
124 ItemProviderDefinition<Node, Node> indexedItemProvider = resolveItemProvider(item, index);
125 property.setItemProvider(indexedItemProvider);
126 return property;
127 });
128 }
129
130
131
132
133 @Deprecated
134 protected JcrIndexedChildNodeProvider.Definition resolveItemProvider(Node node, int index) {
135 JcrIndexedChildNodeProvider.Definition indexedItemProvider = new JcrIndexedChildNodeProvider.Definition();
136
137 indexedItemProvider.setIndex(index);
138 indexedItemProvider.setNodeName(getEntryPropertyNameBase());
139
140 return indexedItemProvider;
141 }
142
143 protected Stream<Node> getChildNodes(Node node, String name) {
144 Iterable<Node> nodes = Exceptions.wrap().get(() ->
145 NodeUtil.getNodes(node, new info.magnolia.ui.editor.ByIndexedChildNodes.IndexedChildNodeNameRegexPredicate(name)));
146
147 return StreamSupport.stream(nodes.spliterator(), false);
148 }
149
150 private String deriveLocaleAwareName(String name, Locale locale) {
151 return i18NAuthoringSupport.deriveLocalisedPropertyName(name, locale);
152 }
153
154 @AllArgsConstructor
155 private class IndexedChildNodeNameRegexPredicate extends AbstractPredicate<Node> {
156
157 private final String baseName;
158
159 private String getIndexedChildNodeRegexp(String name) {
160 return name + INCREMENT_REGEX;
161 }
162
163 @Override
164 public boolean evaluateTyped(Node node) {
165 String childNodeNameRegex = getIndexedChildNodeRegexp(baseName);
166 return getName(node).matches(localiseChildName(childNodeNameRegex, node));
167 }
168
169 private String localiseChildName(String targetChildNodeName, Node node) {
170 if (locale != null &&
171 i18NAuthoringSupport.getDefaultLocale(node) != null &&
172 !i18NAuthoringSupport.isDefaultLocale(locale, node)) {
173 targetChildNodeName = deriveLocaleAwareName(targetChildNodeName, locale);
174 }
175 return targetChildNodeName;
176 }
177 }
178
179
180
181
182 @Getter
183 @Setter
184 @EqualsAndHashCode(callSuper = true)
185 public static class Definition extends MultiFormView.EntryResolution.Definition<Node> implements WithPropertyNameDecorator {
186
187 private Class<? extends PropertyNameDecorator> propertyNameDecorator = NoopNameDecorator.class;
188
189 public Definition() {
190 setImplementationClass(ByIndexedChildNodes.class);
191 }
192
193 @Override
194 public Class<? extends PropertyNameDecorator> getPropertyNameDecorator() {
195 return propertyNameDecorator;
196 }
197
198 public void setPropertyNameDecorator(Class<? extends PropertyNameDecorator> propertyNameDecoratorClass) {
199 this.propertyNameDecorator = propertyNameDecoratorClass;
200 }
201 }
202 }