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.dialog.setup;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.jcr.predicate.AbstractPredicate;
38 import info.magnolia.jcr.predicate.NodeTypePredicate;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.jcr.util.NodeUtil;
41 import info.magnolia.jcr.util.NodeVisitor;
42 import info.magnolia.module.InstallContext;
43 import info.magnolia.module.delta.AbstractTask;
44 import info.magnolia.module.delta.TaskExecutionException;
45 import info.magnolia.repository.RepositoryConstants;
46 import info.magnolia.ui.dialog.setup.migration.CheckBoxRadioControlMigration;
47 import info.magnolia.ui.dialog.setup.migration.CheckBoxSwitchControlMigration;
48 import info.magnolia.ui.dialog.setup.migration.ControlMigration;
49 import info.magnolia.ui.dialog.setup.migration.DamControlMigration;
50 import info.magnolia.ui.dialog.setup.migration.DateControlMigration;
51 import info.magnolia.ui.dialog.setup.migration.EditControlMigration;
52 import info.magnolia.ui.dialog.setup.migration.FckEditControlMigration;
53 import info.magnolia.ui.dialog.setup.migration.FileControlMigration;
54 import info.magnolia.ui.dialog.setup.migration.HiddenControlMigration;
55 import info.magnolia.ui.dialog.setup.migration.LinkControlMigration;
56 import info.magnolia.ui.dialog.setup.migration.MultiSelectControlMigration;
57 import info.magnolia.ui.dialog.setup.migration.SelectControlMigration;
58 import info.magnolia.ui.dialog.setup.migration.StaticControlMigration;
59
60 import java.io.File;
61 import java.io.FileInputStream;
62 import java.io.FileOutputStream;
63 import java.io.IOException;
64 import java.util.HashMap;
65 import java.util.HashSet;
66 import java.util.Iterator;
67
68 import javax.jcr.ImportUUIDBehavior;
69 import javax.jcr.Node;
70 import javax.jcr.Property;
71 import javax.jcr.RepositoryException;
72 import javax.jcr.Session;
73
74 import org.apache.commons.io.IOUtils;
75 import org.apache.commons.lang.StringUtils;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79
80
81
82
83 public class DialogMigrationTask extends AbstractTask {
84
85 private static final Logger log = LoggerFactory.getLogger(DialogMigrationTask.class);
86 private final String moduleName;
87 private final HashSet<Property> extendsAndReferenceProperty = new HashSet<Property>();
88 private HashMap<String, ControlMigration> controlMigrationMap;
89
90 public DialogMigrationTask(String moduleName) {
91 super("Dialog Migration for 5.x", "Migrate dialog for the following module: " + moduleName);
92 this.moduleName = moduleName;
93 this.controlMigrationMap = new HashMap<String, ControlMigration>();
94 }
95
96
97
98
99 @Override
100 public void execute(InstallContext installContext) throws TaskExecutionException {
101 try {
102 this.controlMigrationMap = getCustomMigrationTask();
103 String dialogNodeName = "dialogs";
104 String dialogPath = "/modules/" + moduleName + "/" + dialogNodeName;
105
106 Session session = installContext.getJCRSession(RepositoryConstants.CONFIG);
107 Node dialog = session.getNode(dialogPath);
108
109 String newDialogPath = dialog.getPath() + "50";
110 copyInSession(dialog, newDialogPath);
111 NodeUtil.visit(dialog, new NodeVisitor() {
112 @Override
113 public void visit(Node current) throws RepositoryException {
114 for (Node dialogNode : NodeUtil.getNodes(current, NodeTypes.ContentNode.NAME)) {
115 performDialogMigration(dialogNode);
116 }
117 }
118 }, new NodeTypePredicate(NodeTypes.Content.NAME));
119 session.removeItem(dialogPath);
120 session.move(newDialogPath, dialogPath);
121
122
123 postProcessForExtendsAndReference();
124
125 } catch (Exception e) {
126 log.error("", e);
127 installContext.warn("Could not Migrate Dialog for the following module " + moduleName);
128 }
129 }
130
131
132
133
134
135
136 protected HashMap<String, ControlMigration> getCustomMigrationTask() {
137 HashMap<String, ControlMigration> customMigrationTask = new HashMap<String, ControlMigration>();
138 customMigrationTask.put("edit", new EditControlMigration());
139 customMigrationTask.put("fckEdit", new FckEditControlMigration());
140 customMigrationTask.put("date", new DateControlMigration());
141 customMigrationTask.put("select", new SelectControlMigration());
142 customMigrationTask.put("checkbox", new CheckBoxRadioControlMigration(true));
143 customMigrationTask.put("checkboxSwitch", new CheckBoxSwitchControlMigration());
144 customMigrationTask.put("radio", new CheckBoxRadioControlMigration(false));
145 customMigrationTask.put("dam", new DamControlMigration());
146 customMigrationTask.put("uuidLink", new LinkControlMigration());
147 customMigrationTask.put("link", new LinkControlMigration());
148 customMigrationTask.put("categorizationUUIDMultiSelect", new MultiSelectControlMigration(true));
149 customMigrationTask.put("multiselect", new MultiSelectControlMigration(false));
150 customMigrationTask.put("file", new FileControlMigration());
151 customMigrationTask.put("static", new StaticControlMigration());
152 customMigrationTask.put("hidden", new HiddenControlMigration());
153
154 return customMigrationTask;
155 }
156
157
158
159
160 private void performDialogMigration(Node dialog) throws RepositoryException {
161
162 Iterable<Node> tabNodes = NodeUtil.getNodes(dialog, DIALOG_FILTER);
163 if (tabNodes.iterator().hasNext()) {
164
165 if (dialog.hasProperty("controlType") && dialog.getProperty("controlType").getString().equals("tab")) {
166 handleTab(dialog);
167 } else {
168
169 if (!dialog.hasProperty("controlType") && !dialog.hasProperty("extends") && !dialog.hasProperty("reference")) {
170 handleAction(dialog);
171 }
172
173 handleTabs(dialog, tabNodes.iterator());
174 }
175
176 if (dialog.hasProperty("class")) {
177 dialog.getProperty("class").remove();
178 }
179 } else {
180
181 handleField(dialog);
182 }
183
184 handleExtendsAndReference(dialog);
185 }
186
187
188
189
190 private void handleAction(Node dialog) throws RepositoryException {
191 dialog.addNode("actions", NodeTypes.ContentNode.NAME);
192
193 Node node = dialog.getNode("actions");
194
195 node.addNode("commit", NodeTypes.ContentNode.NAME).setProperty("label", "save changes");
196 node.addNode("cancel", NodeTypes.ContentNode.NAME).setProperty("label", "cancel");
197 node.getNode("commit").setProperty("class", "info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition");
198 node.getNode("cancel").setProperty("class", "info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition");
199
200 }
201
202
203
204
205 private void handleTabs(Node dialog, Iterator<Node> tabNodes) throws RepositoryException {
206 Node form = dialog.addNode("form", NodeTypes.ContentNode.NAME);
207 handleFormLabels(dialog, form);
208 Node dialogTabs = form.addNode("tabs", NodeTypes.ContentNode.NAME);
209 while (tabNodes.hasNext()) {
210 Node tab = tabNodes.next();
211
212 handleTab(tab);
213
214 NodeUtil.moveNode(tab, dialogTabs);
215 }
216 }
217
218
219
220
221 private void handleFormLabels(Node dialog, Node form) throws RepositoryException {
222 moveAndRenameLabelProperty(dialog, form, "label");
223 moveAndRenameLabelProperty(dialog, form, "i18nBasename");
224 moveAndRenameLabelProperty(dialog, form, "description");
225 }
226
227
228
229
230 private void moveAndRenameLabelProperty(Node source, Node target, String propertyName) throws RepositoryException {
231 if (source.hasProperty(propertyName)) {
232 Property dialogProperty = source.getProperty(propertyName);
233 target.setProperty(propertyName, dialogProperty.getString());
234 dialogProperty.remove();
235 }
236 }
237
238
239
240
241 private void handleTab(Node tab) throws RepositoryException {
242 if ((tab.hasProperty("controlType") && StringUtils.equals(tab.getProperty("controlType").getString(), "tab")) || (tab.getParent().hasProperty("extends"))) {
243 if (tab.hasProperty("controlType") && StringUtils.equals(tab.getProperty("controlType").getString(), "tab")) {
244
245 tab.getProperty("controlType").remove();
246 }
247
248 Iterator<Node> controls = NodeUtil.getNodes(tab, NodeTypes.ContentNode.NAME).iterator();
249
250 Node fields = tab.addNode("fields", NodeTypes.ContentNode.NAME);
251
252 while (controls.hasNext()) {
253 Node control = controls.next();
254
255 handleField(control);
256
257 NodeUtil.moveNode(control, fields);
258 }
259 } else if (tab.hasNode("inheritable")) {
260
261 Node inheritable = tab.getNode("inheritable");
262 handleExtendsAndReference(inheritable);
263 } else {
264 handleExtendsAndReference(tab);
265 }
266 }
267
268
269
270
271
272 private void handleField(Node fieldNode) throws RepositoryException {
273 if (fieldNode.hasProperty("controlType")) {
274 String controlTypeName = fieldNode.getProperty("controlType").getString();
275
276 if (controlMigrationMap.containsKey(controlTypeName)) {
277 ControlMigration controlMigration = controlMigrationMap.get(controlTypeName);
278 controlMigration.migrate(fieldNode);
279 } else {
280 fieldNode.setProperty("class", "info.magnolia.ui.form.field.definition.StaticFieldDefinition");
281 if (!fieldNode.hasProperty("value")) {
282 fieldNode.setProperty("value", "Field not yet supported");
283 }
284 log.warn("No dialog define for control '{}' for node '{}'", controlTypeName, fieldNode.getPath());
285 }
286 } else {
287
288 handleExtendsAndReference(fieldNode);
289 }
290 }
291
292
293 private void handleExtendsAndReference(Node node) throws RepositoryException {
294 if (node.hasProperty("extends")) {
295
296 extendsAndReferenceProperty.add(node.getProperty("extends"));
297 } else if (node.hasProperty("reference")) {
298
299 extendsAndReferenceProperty.add(node.getProperty("reference"));
300 }
301 }
302
303
304
305
306 private static AbstractPredicate<Node> DIALOG_FILTER = new AbstractPredicate<Node>() {
307 @Override
308 public boolean evaluateTyped(Node node) {
309 try {
310 return !node.getName().startsWith(NodeTypes.JCR_PREFIX)
311 && !NodeUtil.isNodeType(node, NodeTypes.MetaData.NAME) &&
312 NodeUtil.isNodeType(node, NodeTypes.ContentNode.NAME);
313 } catch (RepositoryException e) {
314 return false;
315 }
316 }
317 };
318
319
320
321
322
323 private void postProcessForExtendsAndReference() throws RepositoryException {
324 for (Property p : extendsAndReferenceProperty) {
325 String path = p.getString();
326 if (path.equals("override")) {
327 continue;
328 }
329 if (!p.getSession().nodeExists(path)) {
330
331 String newPath = insertBeforeLastSlashAndTest(p.getSession(), path, "/tabs", "/fields", "/tabs/fields", "/form/tabs");
332 if (newPath != null) {
333 p.setValue(newPath);
334 continue;
335 }
336
337
338 String beging = path.substring(0, path.lastIndexOf("/"));
339 String end = path.substring(beging.lastIndexOf("/"));
340 beging = beging.substring(0, beging.lastIndexOf("/"));
341 newPath = beging + "/form/tabs" + end;
342 if (p.getSession().nodeExists(newPath)) {
343 p.setValue(newPath);
344 continue;
345 }
346
347 newPath = insertBeforeLastSlash(newPath, "/fields");
348 if (p.getSession().nodeExists(newPath)) {
349 p.setValue(newPath);
350 } else {
351 log.warn("reference to " + path + " not found");
352 }
353 }
354 }
355 }
356
357
358
359
360
361 private String insertBeforeLastSlashAndTest(Session session, String reference, String... toInserts) throws RepositoryException {
362 String res = null;
363 for (String toInsert : toInserts) {
364 String newPath = insertBeforeLastSlash(reference, toInsert);
365 if (session.nodeExists(newPath)) {
366 return newPath;
367 }
368 }
369 return res;
370 }
371
372
373
374
375 private String insertBeforeLastSlash(String reference, String toInsert) {
376 String beging = reference.substring(0, reference.lastIndexOf("/"));
377 String end = reference.substring(reference.lastIndexOf("/"));
378 return beging + toInsert + end;
379 }
380
381
382
383
384
385 private void copyInSession(Node src, String dest) throws RepositoryException {
386 final String destParentPath = StringUtils.defaultIfEmpty(StringUtils.substringBeforeLast(dest, "/"), "/");
387 final String destNodeName = StringUtils.substringAfterLast(dest, "/");
388 final Session session = src.getSession();
389 try {
390 final File file = File.createTempFile("mgnl", null, Path.getTempDirectory());
391 final FileOutputStream outStream = new FileOutputStream(file);
392 session.exportSystemView(src.getPath(), outStream, false, false);
393 outStream.flush();
394 IOUtils.closeQuietly(outStream);
395 FileInputStream inStream = new FileInputStream(file);
396 session.importXML(
397 destParentPath,
398 inStream,
399 ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
400 IOUtils.closeQuietly(inStream);
401 file.delete();
402 if (!StringUtils.equals(src.getName(), destNodeName)) {
403 String currentPath;
404 if (destParentPath.equals("/")) {
405 currentPath = "/" + src.getName();
406 } else {
407 currentPath = destParentPath + "/" + src.getName();
408 }
409 session.move(currentPath, dest);
410 }
411 } catch (IOException e) {
412 throw new RepositoryException("Can't copy node " + src + " to " + dest, e);
413 }
414 }
415 }