1 5 6 package org.exoplatform.services.jcr.impl.core; 7 8 9 import java.util.ArrayList ; 10 import java.util.Collections ; 11 import java.util.Comparator ; 12 import java.util.HashMap ; 13 import java.util.HashSet ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 import java.util.Map ; 17 import java.util.Set ; 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 47 public class NodesModificationManager { 48 49 NodesStorage nodesStorage; 50 private Map 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 (); 60 } 61 62 synchronized public void delete(NodeImpl item) { 63 NodeImpl node = (NodeImpl)item; 64 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 relatedUUID, String 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 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 children = new ArrayList (); 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 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 uuid = node.getUUID(); 178 getRepositoryManager().addLocation(getWorkspaceContainer().getName(), uuid, nodeChange.getPath(), false); 179 } catch (Exception 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 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 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 List 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 NodeChange getNodeChange(String 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 e) { 278 e.printStackTrace(); 279 log.error(e); 280 throw new RepositoryException("AddNode failed Reason: " + e.getMessage()); 281 } 282 } 283 284 public NodeData getNodeByUUID(String UUID) { 286 return nodesStorage.getNodeByUUID(UUID); 287 } 288 289 public NodeData getNodeByPath(String absPath) { 291 return nodesStorage.getNodeByPath(absPath); 292 } 293 294 public Set getChildren(String absPath) { 295 return nodesStorage.getChildren(absPath); 296 } 297 298 public Set getPaths(String uuid) { 299 300 Set paths = new HashSet (); 301 try { 302 303 paths.addAll(nodesStorage.getChangedReferencedPaths(uuid)); 304 paths.addAll(getRepositoryManager().getLocationByUUID(getWorkspaceContainer().getName(), uuid).getReferencedPaths()); 306 System.out.println("ALL PATHS for "+uuid+"---"+paths); 307 return paths; 308 309 } catch (Exception e) { 310 log.debug("getPaths failed "+e); 311 e.printStackTrace(); 312 return paths; 313 } 314 } 315 316 317 public void addValidationError(String path, Exception 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 iterator = validationErrors.keySet().iterator(); iterator.hasNext(); ) { 326 String key = (String )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 errors) throws ConstraintViolationException, ItemExistsException { 334 if (errors.size() > 0) { 335 StringBuffer sB = new StringBuffer (); 336 Set keys = nodesStorage.getKeys(); 337 boolean throwException = false; 338 boolean throwItemExistsException = false; 339 for (Iterator iterator = keys.iterator(); iterator.hasNext(); ) { 340 String key = (String )iterator.next(); 341 if (key.equals(node.getPath()) || PathUtil.isDescendant(key, node.getPath(), false)) { 342 if (errors.containsKey(key)) { 343 Exception error = (Exception )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 validateMandatory(Node node) { 363 List nodes = new ArrayList (); 364 Map errors = new HashMap (); 365 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 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 log.error("ERRORR!!!!" + e); 385 } 386 } 387 } 388 } 389 return errors; 390 } 391 392 private void getAllDescendants(NodeImpl node, List items) { 393 log.debug("Recursively (getAllDescendants): " + node); 394 items.add(node); 395 Iterator children = nodesStorage.getChildren(node.getPath()).iterator(); 396 while(children.hasNext()) { 397 String path = (String )children.next(); 398 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 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 uuidVal = getRepositoryManager().generateUUID(node); 429 Property property = new PropertyImpl(loc.getPath(), new StringValue(uuidVal), PropertyType.STRING); 430 node.addPermanentProperty(property); 431 433 } 434 435 private void updateTime(NodeData node, String 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 { 445 public int compare(Object o1, Object o2) { 446 NodeChange nc1 = (NodeChange)o1; 447 NodeChange nc2 = (NodeChange)o2; 448 String path1 = nc1.getNode().getPath(); 449 String path2 = nc2.getNode().getPath(); 450 return path1.compareTo(path2); 451 } 452 } 453 } 454 | Popular Tags |