KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exoplatform > services > jcr > impl > core > NodesModificationManager


1 /**
2  * Copyright 2001-2003 The eXo Platform SARL All rights reserved. *
3  * Please look at license.txt in info directory for more license detail. *
4  */

5
6 package org.exoplatform.services.jcr.impl.core;
7
8
9 import java.util.ArrayList JavaDoc;
10 import java.util.Collections JavaDoc;
11 import java.util.Comparator JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import javax.jcr.DateValue;
20 import javax.jcr.ItemExistsException;
21 import javax.jcr.Node;
22 import javax.jcr.PathNotFoundException;
23 import javax.jcr.Property;
24 import javax.jcr.PropertyType;
25 import javax.jcr.RepositoryException;
26 import javax.jcr.StringValue;
27 import javax.jcr.nodetype.ConstraintViolationException;
28 import javax.jcr.nodetype.NodeDef;
29
30 import org.apache.commons.logging.Log;
31 import org.exoplatform.services.jcr.core.ItemLocation;
32 import org.exoplatform.services.jcr.core.NodeChange;
33 import org.exoplatform.services.jcr.core.NodeData;
34 import org.exoplatform.services.jcr.core.ReferenceableNodeLocation;
35 import org.exoplatform.services.jcr.storage.RepositoryManager;
36 import org.exoplatform.services.jcr.storage.WorkspaceContainer;
37 import org.exoplatform.services.jcr.util.PathUtil;
38 import org.exoplatform.services.log.LogUtil;
39
40
41
42 /**
43  * Created by The eXo Platform SARL .
44  * @author <a HREF="mailto:geaz@users.sourceforge.net">Gennady Azarenkov</a>
45  * @version $Id: NodesModificationManager.java,v 1.48 2004/11/02 18:36:33 geaz Exp $
46  */

47 public class NodesModificationManager {
48
49     NodesStorage nodesStorage;
50     private Map JavaDoc validationErrors;
51     protected Log log;
52     private TicketImpl ticket;
53
54     public NodesModificationManager(TicketImpl ticket) throws RepositoryException {
55         nodesStorage = new NodesStorage(((RepositoryImpl)ticket.getRepository()).getRepositoryManager(),
56             ticket.getContainer());
57         this.ticket = ticket;
58         log = LogUtil.getLog("org.exoplatform.services.jcr");
59         validationErrors = new HashMap JavaDoc();
60     }
61
62     synchronized public void delete(NodeImpl item) {
63         NodeImpl node = (NodeImpl)item;
64         // i.e. not in Changes yet
65
if (getState(node) == NodeChangeState.UNDEFINED) {
66             node = (NodeImpl)nodesStorage.getNodeByPath(item.getPath());
67         }
68         log.debug("NodesModificationManager is marking to DELETE " + node + " with old state " +
69             NodeChangeState.getStateName(getState(node)));
70         nodesStorage.setState(node.getPath(), NodeChangeState.DELETED);
71     }
72
73     synchronized public void add(NodeImpl node) {
74         log.debug("NodesModificationManager is ADDING " + node + " to the change log.");
75         nodesStorage.add(node);
76     }
77
78     synchronized public void addReference(String JavaDoc relatedUUID, String JavaDoc refPath) throws PathNotFoundException, RepositoryException {
79         log.debug("NodesModificationManager is ADDING REFERENCE " + refPath + " to the "+relatedUUID);
80         nodesStorage.addReference(relatedUUID, refPath);
81     }
82
83     synchronized public void update(NodeImpl node) {
84         log.debug("NodesModificationManager is marking to UPDATE " + node + " with old state " +
85             NodeChangeState.getStateName(getState(node)));
86
87         if (getState(node) == NodeChangeState.UNCHANGED) {
88             log.debug("Node modification manager update UNCHANGED node: " + node);
89             nodesStorage.setState(node.getPath(), NodeChangeState.UPDATED);
90         }
91     }
92
93     synchronized public void commit(NodeData node, boolean shallow) throws RepositoryException {
94
95         NodeChange entry = nodesStorage.getNodeChangeByPath(node.getPath());
96
97         log.debug("NodesModificationManager is COMMITTING (shallow = " + shallow + ") " + entry );
98         if (entry != null) {
99             if (entry.getState() == NodeChangeState.DELETED) {
100                 commitDeletedNode(entry);
101             } else if (entry.getState() == NodeChangeState.ADDED) {
102                 commitAddedNode(entry);
103             } else if (entry.getState() == NodeChangeState.UPDATED) {
104                 commitUpdatedNode(entry);
105             } else if (entry.getState() == NodeChangeState.REF_ADDED) {
106                 commitRefAddedNode(entry);
107             }
108         }
109  
110         List JavaDoc children = nodesStorage.getChildrenChanges(node.getPath(), shallow);
111         Collections.sort(children, new PathComparator());
112         if (!shallow) {
113             for (int i = 0; i < children.size(); i++) {
114                 NodeChange childChange = (NodeChange)children.get(i);
115                 Node childNode = childChange.getNode();
116                 log.debug("NodesModificationManager is COMMITTING child " + childNode + " current state " +
117                     NodeChangeState.getStateName(childChange.getState()));
118                 if (childChange.getState() == NodeChangeState.DELETED) {
119                     commitDeletedNode(childChange);
120                 } else if (childChange.getState() == NodeChangeState.ADDED) {
121                     commitAddedNode(childChange);
122                 } else if (childChange.getState() == NodeChangeState.UPDATED) {
123                     commitUpdatedNode(childChange);
124                 } else if (childChange.getState() == NodeChangeState.REF_ADDED) {
125                     commitRefAddedNode(childChange);
126                 }
127             }
128         } else {
129
130             for (int i = 0; i < children.size(); i++) {
131                 NodeChange childChange = (NodeChange)children.get(i);
132                 Node childNode = childChange.getNode();
133                 log.debug("NodesModificationManager is COMMITTING child " + childNode + " current state " +
134                     NodeChangeState.getStateName(childChange.getState()));
135                 if (childChange.getState() == NodeChangeState.DELETED) {
136                     commitDeletedNode(childChange);
137
138             }
139           }
140        }
141     }
142
143     private void commitDeletedNode(NodeChange nodeChange) throws RepositoryException {
144         NodeData node = nodeChange.getNode();
145         List JavaDoc children = new ArrayList JavaDoc();
146         getAllDescendants((NodeImpl)node, children);
147         for (int i = 0; i < children.size(); i++) {
148             NodeData childNode = (NodeData)children.get(i);
149             log.debug("NodesModificationManager is Committing deleted child " + childNode);
150             getWorkspaceContainer().delete(childNode.getPath());
151             getRepositoryManager().deleteLocationByPath(getWorkspaceContainer().getName(), childNode.getPath());
152             nodesStorage.remove(childNode.getPath());
153         }
154
155         log.debug("NodesModificationManager COMMITTED (recursively) deleted " + node + " to persist. ");
156     }
157
158     private void commitAddedNode(NodeChange nodeChange) throws RepositoryException {
159         NodeData node = nodeChange.getNode();
160         addNode(nodeChange);
161         Property uuid = node.getPermanentProperty("jcr:uuid");
162         if (uuid != null) {
163             getRepositoryManager().addLocation(getWorkspaceContainer().getName(), uuid.getString(), node.getPath(), true);
164             // Add this path as referenceable as well
165
ReferenceableNodeLocation loc = getRepositoryManager().getLocationByUUID(getWorkspaceContainer().getName(), uuid.getString());
166             loc.addReferencedPath(node.getPath());
167         }
168         nodesStorage.setState(node.getPath(), NodeChangeState.UNCHANGED);
169         log.debug("NodesModificationManager COMMITTED added " + node + " to persist. ");
170     }
171
172     private void commitRefAddedNode(NodeChange nodeChange) throws RepositoryException {
173
174         NodeData node = nodeChange.getNode();
175
176         try {
177             String JavaDoc uuid = node.getUUID();
178             getRepositoryManager().addLocation(getWorkspaceContainer().getName(), uuid, nodeChange.getPath(), false);
179         } catch (Exception JavaDoc e) {
180             nodesStorage.remove(node.getPath());
181             throw new RepositoryException("NodesModificationManager.commitRefAddedNode failed. Reason: "+e);
182         }
183
184         nodesStorage.setState(node.getPath(), NodeChangeState.UNCHANGED);
185         log.debug("NodesModificationManager COMMITTED reference added " + node + " to persist. ");
186     }
187
188
189     private void commitUpdatedNode(NodeChange nodeChange) throws RepositoryException {
190         NodeData node = nodeChange.getNode();
191         if (node.getPermanentProperty("jcr:lastModified") != null) {
192             updateTime(node, "jcr:lastModified");
193         }
194         log.debug("Commit updated node " + node);
195         getWorkspaceContainer().update(node);
196         nodesStorage.setState(node.getPath(), NodeChangeState.UNCHANGED);
197         log.debug("NodesModificationManager COMMITTED updated " + node + " to persist. ");
198     }
199
200     synchronized public void rollback(NodeImpl node) {
201         validationErrors.clear();
202         NodeChange entry = nodesStorage.getNodeChangeByPath(node.getPath());
203         if (entry == null || entry.getState() == NodeChangeState.UNCHANGED) {
204             List JavaDoc children = nodesStorage.getChildrenChanges(node.getPath(), false);
205             for (int i = 0; i < children.size(); i++) {
206                 NodeChange childChange = (NodeChange)children.get(i);
207                 NodeData childNode = childChange.getNode();
208                 if (childChange.getState() == NodeChangeState.ADDED) {
209                     nodesStorage.remove(childNode.getPath());
210                 } else {
211                     nodesStorage.setState(childNode.getPath(), NodeChangeState.UNCHANGED);
212                 }
213             }
214             log.debug("NodesModificationManager ROLLED BACK children of unchanged " + node + " to persist. ");
215             return;
216         }
217         if (entry.getState() == NodeChangeState.DELETED) {
218             List JavaDoc children = nodesStorage.getChildrenChanges(node.getPath(), false);
219             for (int i = 0; i < children.size(); i++) {
220                 NodeData childNode = ((NodeChange)children.get(i)).getNode();
221                 nodesStorage.remove(childNode.getPath());
222             }
223             nodesStorage.remove(node.getPath());
224             log.debug("NodesModificationManager ROLLED BACK deleted " + node + " to persist. ");
225         } else if (entry.getState() == NodeChangeState.ADDED) {
226             // log.debug("Rollback added node " + node);
227
List JavaDoc children = nodesStorage.getChildrenChanges(node.getPath(), false);
228             Collections.reverse(children);
229             nodesStorage.remove(node.getPath());
230             for (int i = 0; i < children.size(); i++) {
231                 NodeData childNode = ((NodeChange)children.get(i)).getNode();
232                 nodesStorage.remove(childNode.getPath());
233             }
234             log.debug("NodesModificationManager ROLLED BACK added " + node + " to persist. ");
235         } else if (entry.getState() == NodeChangeState.UPDATED) {
236             nodesStorage.setState(node.getPath(), NodeChangeState.UNCHANGED);
237             log.debug("NodesModificationManager ROLLED BACK updated " + node + " to persist. ");
238         }
239
240     }
241
242
243     // for testing only
244
NodeChange getNodeChange(String JavaDoc path) {
245         return nodesStorage.getNodeChangeByPath(path);
246     }
247
248     private int getState(NodeImpl node) {
249         NodeChange entry = nodesStorage.getNodeChangeByPath(node.getPath());
250         if (entry == null)
251             return NodeChangeState.UNDEFINED;
252         else
253             return entry.getState();
254     }
255
256     private void addNode(NodeChange nodeChange) throws RepositoryException, ItemExistsException {
257         try {
258             NodeData node = nodeChange.getNode();
259             ItemLocation loc = null;
260             Property property = null;
261             if (node.getPermanentProperty("jcr:uuid") != null) {
262
263                 updateUUID(node);
264             }
265             if (node.getPermanentProperty("jcr:created") != null) {
266
267                 updateTime(node, "jcr:created");
268             }
269             if (node.getPermanentProperty("jcr:lastModified") != null) {
270
271                 updateTime(node, "jcr:lastModified");
272             }
273             getWorkspaceContainer().add(node);
274         } catch (ItemExistsException e) {
275             log.error("The node already exists ", e);
276             throw e;
277         } catch (Exception JavaDoc e) {
278             e.printStackTrace();
279             log.error(e);
280             throw new RepositoryException("AddNode failed Reason: " + e.getMessage());
281         }
282     }
283
284     // TODO REfactor this method
285
public NodeData getNodeByUUID(String JavaDoc UUID) {
286         return nodesStorage.getNodeByUUID(UUID);
287     }
288
289     // TODO REfactor this method
290
public NodeData getNodeByPath(String JavaDoc absPath) {
291       return nodesStorage.getNodeByPath(absPath);
292     }
293
294     public Set JavaDoc getChildren(String JavaDoc absPath) {
295         return nodesStorage.getChildren(absPath);
296     }
297
298     public Set JavaDoc getPaths(String JavaDoc uuid) {
299
300         Set JavaDoc paths = new HashSet JavaDoc();
301         try {
302
303            paths.addAll(nodesStorage.getChangedReferencedPaths(uuid));
304 // System.out.println("PATHS from changes for "+uuid+"---"+paths);
305
paths.addAll(getRepositoryManager().getLocationByUUID(getWorkspaceContainer().getName(), uuid).getReferencedPaths());
306            System.out.println("ALL PATHS for "+uuid+"---"+paths);
307            return paths;
308
309         } catch (Exception JavaDoc e) {
310             log.debug("getPaths failed "+e);
311             e.printStackTrace();
312             return paths;
313         }
314     }
315
316
317     public void addValidationError(String JavaDoc path, Exception JavaDoc error) {
318         validationErrors.put(path, error);
319     }
320
321     public void validate(Node node, boolean shallow) throws ConstraintViolationException, ItemExistsException {
322         log.debug("NodesModificationManager Validates "+node+" to persist");
323         processErrors(node, validationErrors);
324         processErrors(node, validateMandatory(node));
325         for (Iterator JavaDoc iterator = validationErrors.keySet().iterator(); iterator.hasNext(); ) {
326             String JavaDoc key = (String JavaDoc)iterator.next();
327             if (key.equals(node.getPath()) || PathUtil.isDescendant(key, node.getPath(), false)) {
328                 validationErrors.remove(key);
329             }
330         }
331     }
332
333     private void processErrors(Node node, Map JavaDoc errors) throws ConstraintViolationException, ItemExistsException {
334         if (errors.size() > 0) {
335             StringBuffer JavaDoc sB = new StringBuffer JavaDoc();
336             Set JavaDoc keys = nodesStorage.getKeys();
337             boolean throwException = false;
338             boolean throwItemExistsException = false;
339             for (Iterator JavaDoc iterator = keys.iterator(); iterator.hasNext(); ) {
340                 String JavaDoc key = (String JavaDoc)iterator.next();
341                 if (key.equals(node.getPath()) || PathUtil.isDescendant(key, node.getPath(), false)) {
342                     if (errors.containsKey(key)) {
343                         Exception JavaDoc error = (Exception JavaDoc)errors.get(key);
344                         if (error != null) {
345                             sB.append("Validation error : " + error + "\n");
346                             throwException = true;
347                             if (error instanceof ItemExistsException) {
348                                 throwItemExistsException = true;
349                             }
350                         }
351                     }
352                 }
353             }
354             if (throwException) {
355                 if (throwItemExistsException)
356                     throw new ItemExistsException(sB.toString());
357                 throw new ConstraintViolationException(sB.toString());
358             }
359         }
360     }
361
362     private Map JavaDoc validateMandatory(Node node) {
363         List JavaDoc nodes = new ArrayList JavaDoc();
364         Map JavaDoc errors = new HashMap JavaDoc();
365         // nodes.add(node);
366
getAllDescendants((NodeImpl)node, nodes);
367         for (int j = 0; j < nodes.size(); j++) {
368             NodeImpl curNode = (NodeImpl)nodes.get(j);
369             curNode.setTicket(ticket);
370             NodeDef[] reqChildNodes = curNode.getPrimaryNodeType().getDeclaredChildNodeDefs();
371             if (reqChildNodes != null) {
372                 for (int i = 0; i < reqChildNodes.length; i++) {
373                     try {
374                         // log.debug("validate CHILD Node ---- " + curNode.getPrimaryNodeType() + " " + reqChildNodes[i] + " " +
375
// reqChildNodes[i].getName());
376
if (reqChildNodes[i].getName() != null && reqChildNodes[i].isMandatory() &&
377                             !curNode.hasNode(reqChildNodes[i].getName())) {
378                                 errors.put(curNode.getPath(),
379                                     new ConstraintViolationException("Mandatory node " +
380                                     reqChildNodes[i].getName() + " is required."));
381                         }
382                     } catch (RepositoryException e) {
383                         /// TEMPORARY
384
log.error("ERRORR!!!!" + e);
385                     }
386                 }
387             }
388         }
389         return errors;
390     }
391
392     private void getAllDescendants(NodeImpl node, List JavaDoc items) {
393         log.debug("Recursively (getAllDescendants): " + node);
394         items.add(node);
395         Iterator JavaDoc children = nodesStorage.getChildren(node.getPath()).iterator();
396         while(children.hasNext()) {
397             String JavaDoc path = (String JavaDoc)children.next();
398 // log.debug("Recursively child path " + path);
399
NodeImpl item = (NodeImpl)getNodeByPath(path);
400             log.debug("Recursively child " + item);
401             getAllDescendants(item, items);
402         }
403     }
404
405     public boolean hasPersistedParent(NodeImpl node) throws RepositoryException {
406         NodeData inContainerParent = getWorkspaceContainer().getNodeByPath(node.getParent().getPath());
407         if (inContainerParent != null)
408             return true;
409         else
410             return false;
411     }
412
413     private RepositoryManager getRepositoryManager() {
414         return ((RepositoryImpl)ticket.getRepository()).getRepositoryManager();
415     }
416
417     private WorkspaceContainer getWorkspaceContainer() throws RepositoryException {
418         return ticket.getContainer();
419     }
420
421     private String JavaDoc getWorkspaceName() {
422         return ticket.getWorkspaceName();
423     }
424
425     private void updateUUID(NodeData node) throws PathNotFoundException, RepositoryException {
426
427         ItemLocation loc = new ItemLocation(node.getPath(), "jcr:uuid");
428         String JavaDoc uuidVal = getRepositoryManager().generateUUID(node);
429         Property property = new PropertyImpl(loc.getPath(), new StringValue(uuidVal), PropertyType.STRING);
430         node.addPermanentProperty(property);
431 // addReference(uuidVal, node.getPath());
432

433     }
434
435     private void updateTime(NodeData node, String JavaDoc propertyName) throws PathNotFoundException, RepositoryException {
436
437         ItemLocation loc = new ItemLocation(node.getPath(), propertyName);
438         Property property = new PropertyImpl(loc.getPath(),
439         new DateValue(getRepositoryManager().getCurrentTime()), PropertyType.DATE);
440         node.addPermanentProperty(property);
441     }
442
443
444     private class PathComparator implements Comparator JavaDoc {
445         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
446             NodeChange nc1 = (NodeChange)o1;
447             NodeChange nc2 = (NodeChange)o2;
448             String JavaDoc path1 = nc1.getNode().getPath();
449             String JavaDoc path2 = nc2.getNode().getPath();
450             return path1.compareTo(path2);
451         }
452     }
453 }
454
Popular Tags