KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > core > version > CopyUtil


1 /**
2  *
3  * Magnolia and its source-code is licensed under the LGPL.
4  * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
5  * When copying, adapting, or redistributing this document in keeping with the guidelines above,
6  * you are required to provide proper attribution to obinary.
7  * If you reproduce or distribute the document without making any substantive modifications to its content,
8  * please use the following attribution line:
9  *
10  * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved.
11  *
12  */

13 package info.magnolia.cms.core.version;
14
15 import info.magnolia.cms.core.Content;
16 import info.magnolia.cms.core.HierarchyManager;
17 import info.magnolia.cms.core.Path;
18 import info.magnolia.context.MgnlContext;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.Iterator JavaDoc;
25
26 import javax.jcr.ImportUUIDBehavior;
27 import javax.jcr.ItemNotFoundException;
28 import javax.jcr.Node;
29 import javax.jcr.Property;
30 import javax.jcr.PropertyIterator;
31 import javax.jcr.PropertyType;
32 import javax.jcr.RepositoryException;
33 import javax.jcr.nodetype.ConstraintViolationException;
34
35 import org.apache.commons.io.IOUtils;
36 import org.apache.commons.lang.StringUtils;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41 /**
42  * @author Sameer Charles
43  * $Id: CopyUtil.java 6665 2006-10-10 15:49:46Z scharles $
44  * Utility class to copy nodes using specified Roles to the magnolia specific version store
45  */

46 public final class CopyUtil {
47
48     /**
49      * Logger.
50      */

51     private static Logger log = LoggerFactory.getLogger(CopyUtil.class);
52
53     /**
54      * singleton instance
55      */

56     private static final CopyUtil thisInstance = new CopyUtil();
57
58     /**
59      * private class
60      */

61     private CopyUtil() {
62     }
63
64     /**
65      * get instance
66      */

67     static CopyUtil getInstance() {
68         return thisInstance;
69     }
70
71     /**
72      * copy given node to the version store using specified filter
73      * @param source
74      * @param filter
75      */

76     void copyToversion(Content source, Content.ContentFilter filter) throws RepositoryException {
77         // first check if the node already exist
78
Content root;
79         try {
80             root = this.getHierarchyManager().getContentByUUID(source.getUUID());
81             if (root.getParent().getName().equalsIgnoreCase(VersionManager.TMP_REFERENCED_NODES)) {
82                 root.getJCRNode().getSession().move(root.getHandle(), "/" + root.getName());
83             }
84             this.removeProperties(root);
85             // copy root properties
86
this.updateProperties(source, root);
87             root.save();
88         }
89         catch (ItemNotFoundException e) {
90             // create root for this versionable node
91
try {
92                 this.importNode(this.getHierarchyManager().getRoot(), source);
93             }
94             catch (IOException JavaDoc ioe) {
95                 throw new RepositoryException("Failed to import node in magnolia version store : " + ioe.getMessage());
96             }
97             root = this.getHierarchyManager().getContentByUUID(source.getUUID());
98             // copy root properties
99
// this.updateProperties(source, root);
100
// save parent node since this node is newly created
101
getHierarchyManager().getRoot().save();
102         }
103         // copy all child nodes
104
Iterator JavaDoc children = source.getChildren(filter).iterator();
105         while (children.hasNext()) {
106             Content child = (Content) children.next();
107             this.clone(child, root, filter, true);
108         }
109         this.removeNonExistingChildNodes(source, root, filter);
110     }
111
112     /**
113      * copy source to destination using the provided filter
114      * @param source node in version store
115      * @param destination which needs to be restored
116      * @param filter this must be the same filter as used while creating this version
117      */

118     void copyFromVersion(Content source, Content destination, Content.ContentFilter filter) throws RepositoryException {
119         // merge top node properties
120
this.removeProperties(destination);
121         this.updateProperties(source, destination);
122         // copy all nodes from version store
123
this.copyAllChildNodes(source, destination, filter);
124         // remove all non existing nodes
125
this.removeNonExistingChildNodes(source, destination, filter);
126     }
127
128     /**
129      * recursively removes all child nodes from node using specified filter
130      * @param source
131      * @param destination
132      * @param filter
133      */

134     private void removeNonExistingChildNodes(Content source, Content destination, Content.ContentFilter filter)
135         throws RepositoryException {
136         // collect all uuids from the source node hierarchy using the given filter
137
Iterator JavaDoc children = destination.getChildren(filter).iterator();
138         while (children.hasNext()) {
139             Content child = (Content) children.next();
140             // check if this child exist in source, if not remove it
141
if (child.getJCRNode().getDefinition().isAutoCreated()) {
142                 continue;
143             }
144             try {
145                 source.getJCRNode().getSession().getNodeByUUID(child.getUUID());
146                 // if exist its ok, recursively remove all sub nodes
147
this.removeNonExistingChildNodes(source, child, filter);
148             }
149             catch (ItemNotFoundException e) {
150                 PropertyIterator referencedProperties = child.getJCRNode().getReferences();
151                 if (referencedProperties.getSize() > 0) {
152                     // remove all referenced properties, its safe since source workspace cannot have these
153
// properties if node with this UUID does not exist
154
while (referencedProperties.hasNext()) {
155                         referencedProperties.nextProperty().remove();
156                     }
157                 }
158                 child.delete();
159             }
160         }
161     }
162
163     /**
164      * copy all child nodes from node1 to node2
165      * @param node1
166      * @param node2
167      * @param filter
168      */

169     private void copyAllChildNodes(Content node1, Content node2, Content.ContentFilter filter)
170         throws RepositoryException {
171         Iterator JavaDoc children = node1.getChildren(filter).iterator();
172         while (children.hasNext()) {
173             Content child = (Content) children.next();
174             this.clone(child, node2, filter, false);
175         }
176     }
177
178     /**
179      * clone
180      * @param node
181      * @param parent
182      * @param filter
183      * @param removeExisting
184      */

185     private void clone(Content node, Content parent, Content.ContentFilter filter, boolean removeExisting)
186         throws RepositoryException {
187         try {
188             // it seems to be a bug in jackrabbit - cloning does not work if the node with the same uuid
189
// exist, "removeExisting" has no effect
190
// if node exist with the same UUID, simply update non propected properties
191
Content existingNode = getHierarchyManager(parent.getWorkspace().getName())
192                 .getContentByUUID(node.getUUID());
193             if (removeExisting) {
194                 existingNode.delete();
195                 parent.save();
196                 this.clone(node, parent);
197                 return;
198             }
199             this.removeProperties(existingNode);
200             this.updateProperties(node, existingNode);
201             Iterator JavaDoc children = node.getChildren(filter).iterator();
202             while (children.hasNext()) {
203                 this.clone((Content) children.next(), existingNode, filter, removeExisting);
204             }
205         }
206         catch (ItemNotFoundException e) {
207             // its safe to clone if UUID does not exist in this workspace
208
this.clone(node, parent);
209         }
210     }
211
212     /**
213      * clone
214      * @param node
215      * @param parent
216      */

217     private void clone(Content node, Content parent) throws RepositoryException {
218         if (node.getJCRNode().getDefinition().isAutoCreated()) {
219             Content destination = parent.getContent(node.getName());
220             this.removeProperties(destination);
221             this.updateProperties(node, destination);
222         }
223         else {
224             parent.getWorkspace().clone(
225                 node.getWorkspace().getName(),
226                 node.getHandle(),
227                 parent.getHandle() + "/" + node.getName(),
228                 true);
229         }
230     }
231
232     /**
233      * remove all properties under the given node
234      * @param node
235      */

236     private void removeProperties(Content node) throws RepositoryException {
237         PropertyIterator properties = node.getJCRNode().getProperties();
238         while (properties.hasNext()) {
239             Property property = properties.nextProperty();
240             if (property.getDefinition().isProtected() || property.getDefinition().isMandatory()) {
241                 continue;
242             }
243             try {
244                 property.remove();
245             }
246             catch (ConstraintViolationException e) {
247                 if (log.isDebugEnabled()) {
248                     log.debug("Property " + property.getName() + " is a reserved property");
249                 }
250             }
251         }
252     }
253
254     /**
255      * import while preserving UUID, parameters supplied must be from separate workspaces
256      * @param parent under which the specified node will be imported
257      * @param node
258      * @throws RepositoryException
259      * @throws IOException if failed to import or export
260      */

261     private void importNode(Content parent, Content node) throws RepositoryException, IOException JavaDoc {
262         File JavaDoc file = File.createTempFile("mgnl", null, Path.getTempDirectory());
263         FileOutputStream JavaDoc outStream = new FileOutputStream JavaDoc(file);
264         node.getWorkspace().getSession().exportSystemView(node.getHandle(), outStream, false, true);
265         outStream.flush();
266         IOUtils.closeQuietly(outStream);
267         FileInputStream JavaDoc inStream = new FileInputStream JavaDoc(file);
268         parent.getWorkspace().getSession().importXML(
269             parent.getHandle(),
270             inStream,
271             ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
272         IOUtils.closeQuietly(inStream);
273         file.delete();
274     }
275
276     /**
277      * merge all non reserved properties
278      * @param source
279      * @param destination
280      */

281     private void updateProperties(Content source, Content destination) throws RepositoryException {
282         Node sourceNode = source.getJCRNode();
283         Node destinationNode = destination.getJCRNode();
284         PropertyIterator properties = sourceNode.getProperties();
285         while (properties.hasNext()) {
286             Property property = properties.nextProperty();
287             // exclude system property Rule and Version specific properties which were created on version
288
if (property.getName().equalsIgnoreCase(VersionManager.PROPERTY_RULE)) {
289                 continue;
290             }
291             try {
292                 if (property.getDefinition().isProtected()) {
293                     continue;
294                 }
295                 if (property.getType() == PropertyType.REFERENCE) {
296                     // first check for the referenced node existence
297
try {
298                         getHierarchyManager(destination.getWorkspace().getName())
299                             .getContentByUUID(property.getString());
300                     }
301                     catch (ItemNotFoundException e) {
302                         if (!StringUtils.equalsIgnoreCase(
303                             destination.getWorkspace().getName(),
304                             VersionManager.VERSION_WORKSPACE)) {
305                             throw e;
306                         }
307                         // get referenced node under temporary store
308
// use jcr import, there is no other way to get a node without sub hierarchy
309
Content referencedNode = getHierarchyManager(source.getWorkspace().getName()).getContentByUUID(
310                             property.getString());
311                         try {
312                             this.importNode(getTemporaryPath(), referencedNode);
313                             this.removeProperties(getHierarchyManager().getContentByUUID(property.getString()));
314                             getTemporaryPath().save();
315                         }
316                         catch (IOException JavaDoc ioe) {
317                             log.error("Failed to import referenced node", ioe);
318                         }
319                     }
320                 }
321                 if (property.getDefinition().isMultiple()) {
322                     destinationNode.setProperty(property.getName(), property.getValues());
323                 }
324                 else {
325                     destinationNode.setProperty(property.getName(), property.getValue());
326                 }
327             }
328             catch (ConstraintViolationException e) {
329                 if (log.isDebugEnabled()) {
330                     log.debug("Property " + property.getName() + " is a reserved property");
331                 }
332             }
333         }
334     }
335
336     /**
337      * get version store hierarchy manager
338      */

339     private HierarchyManager getHierarchyManager() {
340         return MgnlContext.getHierarchyManager(VersionManager.VERSION_WORKSPACE);
341     }
342
343     /**
344      * get hierarchy manager of the specified workspace
345      * @param workspaceId
346      */

347     private HierarchyManager getHierarchyManager(String JavaDoc workspaceId) {
348         return MgnlContext.getHierarchyManager(workspaceId);
349     }
350
351     /**
352      * get temporary node
353      */

354     private Content getTemporaryPath() throws RepositoryException {
355         return getHierarchyManager().getContent("/" + VersionManager.TMP_REFERENCED_NODES);
356     }
357 }
358
Popular Tags