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.framework.action.service;
35
36 import info.magnolia.cms.core.version.VersionManager;
37 import info.magnolia.event.EventBus;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.objectfactory.Components;
40 import info.magnolia.ui.UIComponent;
41 import info.magnolia.ui.ValueContext;
42 import info.magnolia.ui.api.action.ActionExecutor;
43 import info.magnolia.ui.api.app.SubApp;
44 import info.magnolia.ui.api.app.SubAppContext;
45 import info.magnolia.ui.api.event.AdmincentralEventBus;
46 import info.magnolia.ui.api.event.ContentChangedEvent;
47 import info.magnolia.ui.api.ioc.UiContextScoped;
48 import info.magnolia.ui.contentapp.browser.ActionExecutionService;
49 import info.magnolia.ui.contentapp.detail.ContentDetailSubApp;
50 import info.magnolia.ui.datasource.jcr.JcrDatasourceDefinition;
51 import info.magnolia.ui.dialog.formdialog.FormDialogPresenter;
52 import info.magnolia.ui.editor.EditorView;
53 import info.magnolia.ui.editor.ItemProviderStrategy;
54 import info.magnolia.ui.form.EditorCallback;
55 import info.magnolia.ui.form.EditorValidator;
56 import info.magnolia.ui.framework.message.MessagesManager;
57 import info.magnolia.ui.vaadin.integration.contentconnector.ConfiguredJcrContentConnectorDefinition;
58 import info.magnolia.ui.vaadin.integration.contentconnector.ConfiguredNodeTypeDefinition;
59 import info.magnolia.ui.vaadin.integration.contentconnector.JcrContentConnector;
60 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
61 import info.magnolia.util.OptionalConsumer;
62
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.Collection;
66 import java.util.List;
67 import java.util.Optional;
68 import java.util.Set;
69 import java.util.concurrent.Callable;
70 import java.util.stream.Collectors;
71 import java.util.stream.Stream;
72
73 import javax.inject.Inject;
74 import javax.inject.Named;
75 import javax.inject.Provider;
76 import javax.jcr.Node;
77 import javax.jcr.RepositoryException;
78
79 import com.google.common.collect.Sets;
80 import com.vaadin.data.BinderValidationStatus;
81
82
83
84
85
86
87
88
89
90 @UiContextScoped
91 public class CompatibilityActionExecutionService extends ActionExecutionService {
92
93 private final ComponentProvider componentProvider;
94 private final EventBus eventBus;
95
96 @Inject
97 public CompatibilityActionExecutionService(ActionExecutor actionExecutor,
98 MessagesManager messagesManager,
99 ComponentProvider componentProvider,
100 @Named(AdmincentralEventBus.NAME) EventBus eventBus) {
101 super(actionExecutor, messagesManager);
102 this.componentProvider = componentProvider;
103 this.eventBus = eventBus;
104 }
105
106 @Override
107 public void executeAction(String actionName, Object... parameters) {
108 Collection<Object> compatibilityParameters = new ArrayList<>(Arrays.asList(parameters));
109
110 Optional<ValueContextProvider> valueContextProviderOptional = invokeComponentProviderSafely(() -> componentProvider.newInstance(ValueContextProvider.class));
111
112 Optional<Collection> selectedItems = valueContextProviderOptional
113 .map(InjectedComponentProvider::get)
114 .map(ValueContext::get)
115 .map(nodeStream -> nodeStream.collect(Collectors.toList()));
116
117 OptionalConsumer.of(Stream.of(parameters)
118 .filter(FormDialogPresenter.class::isInstance)
119 .findFirst())
120 .ifNotPresent(() -> invokeComponentProviderSafely(() -> Components.getComponent(FormDialogPresenter.class))
121 .ifPresent(compatibilityParameters::add));
122
123 Optional<SubAppContext> subAppContext = invokeComponentProviderSafely(() -> componentProvider.newInstance((SubAppContext.class)));
124 Optional<EditorView> editorView = subAppContext
125 .map(SubAppContext::getSubApp)
126 .map(SubApp::getView)
127 .filter(UIComponent.class::isInstance)
128 .map(view -> ((UIComponent) view).accessViewBeanStore().get(EditorView.class));
129
130 Set<Node> jcrNodes = findJcrNodes(selectedItems);
131
132 if (jcrNodes.size() > 0) {
133 compatibilityParameters.add(wrapForLegacyActionExecution(jcrNodes.iterator().next(), editorView));
134 compatibilityParameters.add(jcrNodes.stream()
135 .map(node -> wrapForLegacyActionExecution(node, editorView))
136 .collect(Collectors.toList())
137 );
138 mimicContentConnector(compatibilityParameters);
139 mimicEditor(compatibilityParameters, jcrNodes, subAppContext, editorView, invokeComponentProviderSafely(() -> componentProvider.newInstance(ValueContextProvider.class)));
140 } else {
141 selectedItems.ifPresent(o -> o.stream().findFirst().ifPresent(compatibilityParameters::add));
142 }
143 super.executeAction(actionName, compatibilityParameters.toArray(new Object[0]));
144 }
145
146 private void mimicEditor(Collection<Object> compatibilityParameters, Set<Node> jcrNodes, Optional<SubAppContext> subAppContext, Optional<EditorView> editorView, Optional<ValueContextProvider> valueContextProviderOptional) {
147 editorView.ifPresent(nodeEditorView -> compatibilityParameters.add(new EditorValidator() {
148 @Override
149 public void showValidation(boolean visible) {
150
151 }
152
153 @Override
154 public boolean isValid() {
155 List<BinderValidationStatus<?>> validate = nodeEditorView.validate();
156 return validate.stream().allMatch(BinderValidationStatus::isOk);
157 }
158 }));
159
160 compatibilityParameters.add(new EditorCallback() {
161 @Override
162 public void onCancel() {
163 subAppContext.ifPresent(subAppContext -> {
164 if (subAppContext.getSubApp() instanceof ContentDetailSubApp) {
165 subAppContext.close();
166 }
167 });
168 }
169
170 @Override
171 public void onSuccess(String actionName) {
172 onCancel();
173 }
174 });
175
176 valueContextProviderOptional
177 .map(InjectedComponentProvider::get)
178 .ifPresent(context -> eventBus.addHandler(ContentChangedEvent.class, event -> context.set(jcrNodes)));
179 }
180
181 private void mimicContentConnector(Collection<Object> compatibilityParameters) {
182 invokeComponentProviderSafely(() -> componentProvider.newInstance(JcrDatasourceDefinitionProvider.class))
183 .map(InjectedComponentProvider::get)
184 .ifPresent(datasourceDefinition -> {
185 ConfiguredJcrContentConnectorDefinitionnnectorDefinition.html#ConfiguredJcrContentConnectorDefinition">ConfiguredJcrContentConnectorDefinition contentConnectorDefinition = new ConfiguredJcrContentConnectorDefinition();
186 contentConnectorDefinition.setWorkspace(datasourceDefinition.getWorkspace());
187 contentConnectorDefinition.setRootPath(datasourceDefinition.getRootPath());
188 contentConnectorDefinition.setNodeTypes(datasourceDefinition.getAllowedNodeTypes()
189 .stream()
190 .map(nodeType -> {
191 ConfiguredNodeTypeDefinitionfiguredNodeTypeDefinition.html#ConfiguredNodeTypeDefinition">ConfiguredNodeTypeDefinition nodeTypeDefinition = new ConfiguredNodeTypeDefinition();
192 nodeTypeDefinition.setName(nodeType);
193 return nodeTypeDefinition;
194 })
195 .collect(Collectors.toList()));
196 compatibilityParameters.add(new JcrContentConnector(componentProvider.getComponent(VersionManager.class), contentConnectorDefinition));
197 });
198 }
199
200 private Set<Node> findJcrNodes(Optional<Collection> selectedItems) {
201 return (Set<Node>) selectedItems.map(items -> items.stream()
202 .filter(Node.class::isInstance)
203 .map(Node.class::cast)
204 .collect(Collectors.toSet()))
205 .orElse(Sets.newHashSet());
206 }
207
208 private JcrNodeAdapter wrapForLegacyActionExecution(Object potentialJcrItem, Optional<EditorView> editorView) {
209 return new JcrNodeAdapter((Node) potentialJcrItem) {
210 @Override
211 public Node applyChanges() throws RepositoryException {
212 editorView.ifPresent(editorView -> editorView.write(getJcrItem()));
213 return super.applyChanges();
214 }
215 };
216 }
217
218 private <C> Optional<C> invokeComponentProviderSafely(Callable<C> callable) {
219 try {
220 return Optional.of(callable.call());
221 } catch (Exception e) {
222 return Optional.empty();
223 }
224 }
225
226 private static class ItemProviderStrategyProvider extends InjectedComponentProvider<ItemProviderStrategy<Node, ?>> {
227 @Inject
228 private ItemProviderStrategyProvider(ItemProviderStrategy<Node, ?> strategy) {
229 super(strategy);
230 }
231 }
232
233 private static class ValueContextProvider extends InjectedComponentProvider<ValueContext<Node>> {
234 @Inject
235 private ValueContextProvider(ValueContext<Node> valueContext) {
236 super(valueContext);
237 }
238 }
239
240 private static class JcrDatasourceDefinitionProvider extends InjectedComponentProvider<JcrDatasourceDefinition> {
241 @Inject
242 private JcrDatasourceDefinitionProvider(JcrDatasourceDefinition datasourceDefinition) {
243 super(datasourceDefinition);
244 }
245 }
246
247
248
249
250 private static class InjectedComponentProvider<T> implements Provider<T> {
251
252 private final T component;
253
254 private InjectedComponentProvider(T component) {
255 this.component = component;
256 }
257
258 @Override
259 public T get() {
260 return component;
261 }
262 }
263 }