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.cms.core.version;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.Path;
38 import info.magnolia.cms.beans.config.ContentRepository;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.cms.core.HierarchyManager;
41
42 import java.io.File;
43 import java.io.FileInputStream;
44 import java.io.FileOutputStream;
45 import java.io.IOException;
46 import java.util.Iterator;
47
48 import javax.jcr.ImportUUIDBehavior;
49 import javax.jcr.ItemNotFoundException;
50 import javax.jcr.Node;
51 import javax.jcr.Property;
52 import javax.jcr.PropertyIterator;
53 import javax.jcr.PropertyType;
54 import javax.jcr.RepositoryException;
55 import javax.jcr.nodetype.ConstraintViolationException;
56
57 import org.apache.commons.io.IOUtils;
58 import org.apache.commons.lang.StringUtils;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65
66
67
68 public final class CopyUtil {
69
70
71
72
73 private static Logger log = LoggerFactory.getLogger(CopyUtil.class);
74
75
76
77
78 private static final CopyUtil thisInstance = new CopyUtil();
79
80
81
82
83 private CopyUtil() {
84 }
85
86
87
88
89 public static CopyUtil getInstance() {
90 return thisInstance;
91 }
92
93
94
95
96
97
98 void copyToversion(Content source, Content.ContentFilter filter) throws RepositoryException {
99
100 Content root;
101 try {
102 root = this.getHierarchyManager().getContentByUUID(source.getUUID());
103 if (root.getParent().getName().equalsIgnoreCase(VersionManager.TMP_REFERENCED_NODES)) {
104 root.getJCRNode().getSession().move(root.getHandle(), "/" + root.getName());
105 }
106 this.removeProperties(root);
107
108 this.updateProperties(source, root);
109 root.save();
110 }
111 catch (ItemNotFoundException e) {
112
113 try {
114 this.importNode(this.getHierarchyManager().getRoot(), source);
115 }
116 catch (IOException ioe) {
117 throw new RepositoryException("Failed to import node in magnolia version store : " + ioe.getMessage());
118 }
119 root = this.getHierarchyManager().getContentByUUID(source.getUUID());
120
121
122
123 getHierarchyManager().getRoot().save();
124 }
125
126 Iterator children = source.getChildren(filter).iterator();
127 while (children.hasNext()) {
128 Content child = (Content) children.next();
129 this.clone(child, root, filter, true);
130 }
131 this.removeNonExistingChildNodes(source, root, filter);
132 }
133
134
135
136
137
138
139
140 void copyFromVersion(Content source, Content destination, Content.ContentFilter filter) throws RepositoryException {
141
142 this.removeProperties(destination);
143 this.updateProperties(source, destination);
144
145 this.copyAllChildNodes(source, destination, filter);
146
147 this.removeNonExistingChildNodes(source, destination, filter);
148 }
149
150
151
152
153
154
155
156 private void removeNonExistingChildNodes(Content source, Content destination, Content.ContentFilter filter)
157 throws RepositoryException {
158
159 Iterator children = destination.getChildren(filter).iterator();
160 while (children.hasNext()) {
161 Content child = (Content) children.next();
162
163 if (child.getJCRNode().getDefinition().isAutoCreated()) {
164 continue;
165 }
166 try {
167 source.getJCRNode().getSession().getNodeByUUID(child.getUUID());
168
169 this.removeNonExistingChildNodes(source, child, filter);
170 }
171 catch (ItemNotFoundException e) {
172 PropertyIterator referencedProperties = child.getJCRNode().getReferences();
173 if (referencedProperties.getSize() > 0) {
174
175
176 while (referencedProperties.hasNext()) {
177 referencedProperties.nextProperty().remove();
178 }
179 }
180 child.delete();
181 }
182 }
183 }
184
185
186
187
188
189
190
191 private void copyAllChildNodes(Content node1, Content node2, Content.ContentFilter filter)
192 throws RepositoryException {
193 Iterator children = node1.getChildren(filter).iterator();
194 while (children.hasNext()) {
195 Content child = (Content) children.next();
196 this.clone(child, node2, filter, false);
197 }
198 }
199
200
201
202
203
204
205
206
207 public void clone(Content node, Content parent, Content.ContentFilter filter, boolean removeExisting)
208 throws RepositoryException {
209 try {
210
211
212
213 String workspaceName = ContentRepository.getInternalWorkspaceName(parent.getWorkspace().getName());
214 Content existingNode = getHierarchyManager(workspaceName)
215 .getContentByUUID(node.getUUID());
216 if (removeExisting) {
217 existingNode.delete();
218 parent.save();
219 this.clone(node, parent);
220 return;
221 }
222 this.removeProperties(existingNode);
223 this.updateProperties(node, existingNode);
224 Iterator children = node.getChildren(filter).iterator();
225 while (children.hasNext()) {
226 this.clone((Content) children.next(), existingNode, filter, removeExisting);
227 }
228 }
229 catch (ItemNotFoundException e) {
230
231 this.clone(node, parent);
232 }
233 }
234
235
236
237
238
239
240 private void clone(Content node, Content parent) throws RepositoryException {
241 if (node.getJCRNode().getDefinition().isAutoCreated()) {
242 Content destination = parent.getContent(node.getName());
243 this.removeProperties(destination);
244 this.updateProperties(node, destination);
245 }
246 else {
247 String parH = parent.getHandle();
248 parent.getWorkspace().clone(
249 node.getWorkspace().getName(),
250 node.getHandle(),
251 parH + (parH != null && parH.endsWith("/") ? "" :"/") + node.getName(),
252 true);
253 }
254 }
255
256
257
258
259
260 private void removeProperties(Content node) throws RepositoryException {
261 PropertyIterator properties = node.getJCRNode().getProperties();
262 while (properties.hasNext()) {
263 Property property = properties.nextProperty();
264 if (property.getDefinition().isProtected() || property.getDefinition().isMandatory()) {
265 continue;
266 }
267 try {
268 property.remove();
269 }
270 catch (ConstraintViolationException e) {
271 if (log.isDebugEnabled()) {
272 log.debug("Property " + property.getName() + " is a reserved property");
273 }
274 }
275 }
276 }
277
278
279
280
281
282
283
284
285 private void importNode(Content parent, Content node) throws RepositoryException, IOException {
286 File file = File.createTempFile("mgnl", null, Path.getTempDirectory());
287 FileOutputStream outStream = new FileOutputStream(file);
288 node.getWorkspace().getSession().exportSystemView(node.getHandle(), outStream, false, true);
289 outStream.flush();
290 IOUtils.closeQuietly(outStream);
291 FileInputStream inStream = new FileInputStream(file);
292 parent.getWorkspace().getSession().importXML(
293 parent.getHandle(),
294 inStream,
295 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
296 IOUtils.closeQuietly(inStream);
297 file.delete();
298 }
299
300
301
302
303
304
305 private void updateProperties(Content source, Content destination) throws RepositoryException {
306 Node sourceNode = source.getJCRNode();
307 Node destinationNode = destination.getJCRNode();
308 PropertyIterator properties = sourceNode.getProperties();
309 while (properties.hasNext()) {
310 Property property = properties.nextProperty();
311
312 if (property.getName().equalsIgnoreCase(VersionManager.PROPERTY_RULE)) {
313 continue;
314 }
315 try {
316 if (property.getDefinition().isProtected()) {
317 continue;
318 }
319 if ("jcr:isCheckedOut".equals(property.getName())) {
320
321
322
323
324 continue;
325 }
326 if (property.getType() == PropertyType.REFERENCE) {
327
328 try {
329 getHierarchyManager(destination.getWorkspace().getName())
330 .getContentByUUID(property.getString());
331 }
332 catch (ItemNotFoundException e) {
333 if (!StringUtils.equalsIgnoreCase(
334 destination.getWorkspace().getName(),
335 VersionManager.VERSION_WORKSPACE)) {
336 throw e;
337 }
338
339
340 Content referencedNode = getHierarchyManager(source.getWorkspace().getName()).getContentByUUID(
341 property.getString());
342 try {
343 this.importNode(getTemporaryPath(), referencedNode);
344 this.removeProperties(getHierarchyManager().getContentByUUID(property.getString()));
345 getTemporaryPath().save();
346 }
347 catch (IOException ioe) {
348 log.error("Failed to import referenced node", ioe);
349 }
350 }
351 }
352 if (property.getDefinition().isMultiple()) {
353 destinationNode.setProperty(property.getName(), property.getValues());
354 }
355 else {
356 destinationNode.setProperty(property.getName(), property.getValue());
357 }
358 }
359 catch (ConstraintViolationException e) {
360 if (log.isDebugEnabled()) {
361 log.debug("Property " + property.getName() + " is a reserved property");
362 }
363 }
364 }
365 }
366
367
368
369
370 private HierarchyManager getHierarchyManager() {
371 return MgnlContext.getHierarchyManager(VersionManager.VERSION_WORKSPACE);
372 }
373
374
375
376
377
378 private HierarchyManager getHierarchyManager(String workspaceId) {
379 return MgnlContext.getHierarchyManager(workspaceId);
380 }
381
382
383
384
385 private Content getTemporaryPath() throws RepositoryException {
386 return getHierarchyManager().getContent("/" + VersionManager.TMP_REFERENCED_NODES);
387 }
388 }