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.contentapp.setup;
35
36 import info.magnolia.importexport.postprocessors.MetaDataAsMixinConversionHelper;
37 import info.magnolia.jcr.util.NodeTypes;
38 import info.magnolia.jcr.util.NodeUtil;
39 import info.magnolia.jcr.util.NodeVisitor;
40 import info.magnolia.module.InstallContext;
41 import info.magnolia.module.delta.AbstractTask;
42 import info.magnolia.module.delta.TaskExecutionException;
43
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.Map.Entry;
47
48 import javax.jcr.Node;
49 import javax.jcr.NodeIterator;
50 import javax.jcr.RepositoryException;
51 import javax.jcr.Session;
52 import javax.jcr.Workspace;
53
54 import org.apache.commons.lang3.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public abstract class AbstractDataTypeMigrationTask extends AbstractTask {
71 private static final Logger log = LoggerFactory.getLogger(AbstractDataTypeMigrationTask.class);
72
73
74 private String dataRootPath;
75 private String newRootPath;
76 private HashMap<String, String> oldToNewNodeTypeMapping;
77 private String newWorkspaceName;
78 private Session dataSession;
79 private Session newSession;
80 private boolean isTargetRoot;
81
82
83
84
85
86
87 public AbstractDataTypeMigrationTask(String taskName, String taskDescription, String dataPath, String newPath, String newWorkspaceName) {
88 super(taskName, taskDescription);
89 this.dataRootPath = dataPath;
90 this.isTargetRoot = (StringUtils.isBlank(newPath) || "/".equals(newPath));
91 this.newRootPath = (StringUtils.isNotBlank(newPath) && !"/".equals(newPath)) ? newPath : dataPath;
92 this.newWorkspaceName = newWorkspaceName;
93 this.oldToNewNodeTypeMapping = new HashMap<String, String>();
94 }
95
96 @Override
97 public void execute(InstallContext installContext) throws TaskExecutionException {
98 try {
99
100 dataSession = installContext.getJCRSession("data");
101 newSession = installContext.getJCRSession(newWorkspaceName);
102
103
104 initOldToNewNodeTypeMappingElement(oldToNewNodeTypeMapping);
105
106
107 if (dataSession.nodeExists(dataRootPath)) {
108 migrateData();
109 } else {
110 installContext.warn("Data migration task cancelled. The following data type do not exist in the data workspace: " + dataRootPath);
111 }
112
113 } catch (Exception e) {
114 installContext.error("Unable to perform Migration task " + getName(), e);
115 TaskExecutionException taskExecutionException = (e instanceof TaskExecutionException) ? (TaskExecutionException) e : new TaskExecutionException(e.getMessage());
116 throw taskExecutionException;
117 }
118
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133 protected abstract void initOldToNewNodeTypeMappingElement(HashMap<String, String> oldToNewNodeTypeMapping);
134
135 private void migrateData() throws TaskExecutionException {
136 try {
137 copyDataWorkspaceToNewWorkspace();
138 for (Entry<String, String> entry : oldToNewNodeTypeMapping.entrySet()) {
139 convertPrimaryNodeType(entry.getKey(), entry.getValue());
140 }
141 removeMetaDataNodes();
142 } catch (RepositoryException re) {
143 throw new TaskExecutionException("Could not migrate Data folders to the new workspace :" + newWorkspaceName, re);
144 }
145 }
146
147
148
149
150 private void copyDataWorkspaceToNewWorkspace() throws TaskExecutionException, RepositoryException {
151
152 final Node rootData = dataSession.getNode(dataRootPath);
153 Workspace newWorkspace = newSession.getWorkspace();
154
155 if (rootData.getDepth() == 0) {
156 throw new TaskExecutionException("Can not migrate the root of Data workspace. You have to choose a specific data type to migrate like 'data/category'");
157 }
158 if (!newSession.nodeExists(newRootPath) && !"/".equals(getParentPath(newRootPath)) && !newSession.nodeExists(getParentPath(newRootPath))) {
159 NodeUtil.createPath(newSession.getRootNode(), getParentPath(newRootPath), NodeTypes.Folder.NAME).getSession().save();
160 }
161 newWorkspace.clone("data", dataRootPath, newRootPath, true);
162 log.info("Following data workspace part {}: is now moved to the following workspace '{}' location '{}'", Arrays.asList(dataRootPath, newWorkspace.getName(), newRootPath).toArray());
163
164 if (this.isTargetRoot) {
165
166 NodeIterator nodeIterator = newSession.getNode(newRootPath).getNodes();
167 while (nodeIterator.hasNext()) {
168 Node node = nodeIterator.nextNode();
169 newSession.getWorkspace().move(node.getPath(), "/" + node.getName());
170 }
171 newSession.removeItem(newRootPath);
172 newRootPath = "/";
173 }
174
175 newSession.save();
176 }
177
178 private void convertPrimaryNodeType(String oldNodeType, String newNodetype) throws RepositoryException {
179 final Node root = newSession.getNode(newRootPath);
180 NodeUtil.visit(root, createTypeVisitor(oldNodeType, newNodetype));
181 newSession.save();
182 }
183
184
185 private NodeVisitor createTypeVisitor(final String oldNodeType, final String newNodetype) {
186 NodeVisitor folderVisitor = new NodeVisitor() {
187 @Override
188 public void visit(Node node) throws RepositoryException {
189 if (NodeUtil.isNodeType(node, oldNodeType)) {
190 node.setPrimaryType(newNodetype);
191 log.debug("Node primary Type changed from '{}' to '{}' for '{}' ", Arrays.asList(oldNodeType, newNodetype, node.getPath()).toArray());
192 }
193 }
194 };
195 return folderVisitor;
196 }
197
198
199
200
201
202 private void removeMetaDataNodes() throws RepositoryException {
203 MetaDataAsMixinConversionHelper conversionHelper = new MetaDataAsMixinConversionHelper();
204 conversionHelper.setDeleteMetaDataIfEmptied(true);
205 conversionHelper.setPeriodicSaves(true);
206
207 NodeIterator childRootNodes = newSession.getRootNode().getNodes();
208 while (childRootNodes.hasNext()) {
209 Node child = childRootNodes.nextNode();
210 if (!child.getName().startsWith(NodeTypes.JCR_PREFIX) && !child.getName().startsWith(NodeTypes.REP_PREFIX)) {
211 conversionHelper.convertNodeAndChildren(child);
212 } else {
213 log.debug("Node '{}' are not handled by this task", child.getName());
214 }
215 }
216 log.info("Converted MetaData in workspace '{}'", newSession.getWorkspace().getName());
217 }
218
219 private String getParentPath(String path) {
220 int lastIndexOfSlash = path.lastIndexOf("/");
221 if (lastIndexOfSlash > 0) {
222 return StringUtils.substringBeforeLast(path, "/");
223 }
224 return "/";
225 }
226
227 }
228
229