1 13 package info.magnolia.cms.core.version; 14 15 import org.slf4j.Logger; 16 import org.slf4j.LoggerFactory; 17 import org.apache.commons.codec.binary.Base64; 18 import org.apache.commons.io.IOUtils; 19 20 import javax.jcr.*; 21 import javax.jcr.version.Version; 22 import javax.jcr.version.VersionHistory; 23 import javax.jcr.version.VersionIterator; 24 import javax.jcr.version.VersionException; 25 26 import info.magnolia.cms.core.HierarchyManager; 27 import info.magnolia.cms.core.Content; 28 import info.magnolia.cms.core.ItemType; 29 import info.magnolia.cms.core.NodeData; 30 import info.magnolia.cms.util.Rule; 31 import info.magnolia.cms.util.RuleBasedContentFilter; 32 import info.magnolia.cms.util.ExclusiveWrite; 33 import info.magnolia.context.MgnlContext; 34 35 import java.util.List ; 36 import java.io.*; 37 38 42 public abstract class BaseVersionManager { 43 44 47 public static final String VERSION_WORKSPACE = "mgnlVersion"; 48 49 52 protected static final String TMP_REFERENCED_NODES = "mgnl:tmpReferencedNodes"; 53 54 57 protected static final String SYSTEM_NODE = "mgnl:versionMetaData"; 58 59 62 protected static final String PROPERTY_RULE = "Rule"; 63 64 67 protected static final String ROOT_VERSION = "jcr:rootVersion"; 68 69 72 private static Logger log = LoggerFactory.getLogger(BaseVersionManager.class); 73 74 78 protected void createInitialStructure() throws RepositoryException { 79 HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(VERSION_WORKSPACE); 80 try { 81 Content tmp = hm.getContent("/" + VersionManager.TMP_REFERENCED_NODES); 82 NodeIterator children = tmp.getJCRNode().getNodes(); 84 while (children.hasNext()) { 85 Node child = children.nextNode(); 86 if (child.getReferences().getSize() < 1) { 87 child.remove(); 88 } 89 } 90 } 91 catch (PathNotFoundException e) { 92 hm.createContent("", VersionManager.TMP_REFERENCED_NODES, ItemType.SYSTEM.getSystemName()); 93 } 94 hm.save(); 95 } 96 97 104 public synchronized Version addVersion(Content node) throws UnsupportedRepositoryOperationException, 105 RepositoryException { 106 Rule rule = new Rule(node.getNodeTypeName() + "," + ItemType.SYSTEM.getSystemName(), ","); 108 rule.reverse(); 109 return this.addVersion(node, rule); 110 } 111 112 119 public synchronized Version addVersion(Content node, Rule rule) throws UnsupportedRepositoryOperationException, 120 RepositoryException { 121 List permissions = this.getAccessManagerPermissions(); 122 this.impersonateAccessManager(null); 123 try { 124 return this.createVersion(node, rule); 125 } 126 catch (RepositoryException re) { 127 log.error("failed to copy versionable node to version store, reverting all changes made in this session"); 130 getHierarchyManager().refresh(false); 131 throw re; 132 } 133 finally { 134 this.revertAccessManager(permissions); 135 } 136 } 137 138 146 protected Version createVersion(Content node, Rule rule) throws UnsupportedRepositoryOperationException, 147 RepositoryException { 148 if (isInvalidMaxVersions()) { 149 log.debug("Ignore create version, MaxVersionIndex < 1"); 150 log.debug("Returning root version of the source node"); 151 return node.getJCRNode().getVersionHistory().getRootVersion(); 152 } 153 CopyUtil.getInstance().copyToversion(node, new RuleBasedContentFilter(rule)); 154 Content versionedNode = this.getVersionedNode(node); 155 Content systemInfo = this.getSystemNode(versionedNode); 156 ByteArrayOutputStream out = new ByteArrayOutputStream(); 158 try { 159 ObjectOutput objectOut = new ObjectOutputStream(out); 160 objectOut.writeObject(rule); 161 objectOut.flush(); 162 objectOut.close(); 163 NodeData nodeData; 164 if (!systemInfo.hasNodeData(PROPERTY_RULE)) { 166 nodeData = systemInfo.createNodeData(PROPERTY_RULE); 167 } 168 else { 169 nodeData = systemInfo.getNodeData(PROPERTY_RULE); 170 } 171 nodeData.setValue(new String (Base64.encodeBase64(out.toByteArray()))); 172 } 173 catch (IOException e) { 174 throw new RepositoryException("Unable to add serialized Rule to the versioned content"); 175 } 176 String userName = ""; 178 if (MgnlContext.getUser() != null) { 179 userName = MgnlContext.getUser().getName(); 180 } 181 if (!systemInfo.hasNodeData(ContentVersion.VERSION_USER)) { 183 systemInfo.createNodeData(ContentVersion.VERSION_USER).setValue(userName); 184 } 185 else { 186 systemInfo.getNodeData(ContentVersion.VERSION_USER).setValue(userName); 187 } 188 if (!systemInfo.hasNodeData(ContentVersion.NAME)) { 189 systemInfo.createNodeData(ContentVersion.NAME).setValue(node.getName()); 190 } 191 else { 192 systemInfo.getNodeData(ContentVersion.NAME).setValue(node.getName()); 193 } 194 195 versionedNode.save(); 196 Version newVersion = versionedNode.getJCRNode().checkin(); 198 versionedNode.getJCRNode().checkout(); 199 try { 200 this.setMaxVersionHistory(versionedNode); 201 } 202 catch (RepositoryException re) { 203 log.error("Failed to limit version history to the maximum configured", re); 204 log.error("New version has already been created"); 205 } 206 207 return newVersion; 208 } 209 210 213 public abstract boolean isInvalidMaxVersions(); 214 215 219 public synchronized Content getVersionedNode(Content node) throws RepositoryException { 220 return getVersionedNode(node.getUUID()); 221 } 222 223 227 protected synchronized Content getVersionedNode(String uuid) throws RepositoryException { 228 List permissions = this.getAccessManagerPermissions(); 229 this.impersonateAccessManager(null); 230 try { 231 return getHierarchyManager().getContentByUUID(uuid); 232 } 233 catch (ItemNotFoundException e) { 234 return null; 235 } 236 catch (RepositoryException re) { 237 throw re; 238 } 239 finally { 240 this.revertAccessManager(permissions); 241 } 242 } 243 244 249 public abstract void setMaxVersionHistory(Content node) throws RepositoryException; 250 251 258 public synchronized VersionHistory getVersionHistory(Content node) throws UnsupportedRepositoryOperationException, 259 RepositoryException { 260 Content versionedNode = this.getVersionedNode(node); 261 if (versionedNode == null) { 262 log.info("No VersionHistory found for this node"); 264 return null; 265 } 266 return versionedNode.getJCRNode().getVersionHistory(); 267 } 268 269 277 public synchronized Version getVersion(Content node, String name) throws UnsupportedRepositoryOperationException, 278 RepositoryException { 279 VersionHistory history = this.getVersionHistory(node); 280 if (history != null) { 281 return history.getVersion(name); 282 } 283 log.error("Node " + node.getHandle() + " was never versioned"); 284 return null; 285 } 286 287 292 public Version getBaseVersion(Content node) throws UnsupportedOperationException , RepositoryException { 293 Content versionedNode = this.getVersionedNode(node); 294 if (versionedNode != null) { 295 return versionedNode.getJCRNode().getBaseVersion(); 296 } 297 298 throw new RepositoryException("Node " + node.getHandle() + " was never versioned"); 299 } 300 301 308 public synchronized VersionIterator getAllVersions(Content node) throws UnsupportedRepositoryOperationException, 309 RepositoryException { 310 Content versionedNode = this.getVersionedNode(node); 311 if (versionedNode == null) { 312 return null; 314 } 315 return versionedNode.getJCRNode().getVersionHistory().getAllVersions(); 316 } 317 318 328 public synchronized void restore(Content node, Version version, boolean removeExisting) throws VersionException, 329 UnsupportedRepositoryOperationException, RepositoryException { 330 Content versionedNode = this.getVersionedNode(node); 332 versionedNode.getJCRNode().restore(version, removeExisting); 333 versionedNode.getJCRNode().checkout(); 334 List permissions = this.getAccessManagerPermissions(); 335 this.impersonateAccessManager(null); 336 try { 337 Rule rule = this.getUsedFilter(versionedNode); 339 try { 340 synchronized (ExclusiveWrite.getInstance()) { 341 CopyUtil.getInstance().copyFromVersion(versionedNode, node, new RuleBasedContentFilter(rule)); 342 node.save(); 343 } 344 } 345 catch (RepositoryException re) { 346 log.error("failed to restore versioned node, reverting all changes make to this node"); 347 node.refresh(false); 348 throw re; 349 } 350 } 351 catch (IOException e) { 352 throw new RepositoryException(e); 353 } 354 catch (ClassNotFoundException e) { 355 throw new RepositoryException(e); 356 } 357 catch (RepositoryException e) { 358 throw e; 359 } 360 finally { 361 this.revertAccessManager(permissions); 362 } 363 } 364 365 370 public synchronized void removeVersionHistory(String uuid) throws RepositoryException { 371 List permissions = this.getAccessManagerPermissions(); 372 this.impersonateAccessManager(null); 373 try { 374 Content node = this.getVersionedNode(uuid); 375 if (node != null) { 376 if (node.getJCRNode().getReferences().getSize() < 1) { 377 node.delete(); 379 } else { VersionHistory history = node.getVersionHistory(); 381 VersionIterator versions = node.getAllVersions(); 382 if (versions != null) { 383 versions.nextVersion(); 385 while (versions.hasNext()) { 386 history.removeVersion(versions.nextVersion().getName()); 387 } 388 } 389 } 390 } 391 } 392 catch (RepositoryException re) { 393 throw re; 394 } 395 finally { 396 this.revertAccessManager(permissions); 397 } 398 getHierarchyManager().save(); 399 } 400 401 408 protected Rule getUsedFilter(Content versionedNode) throws IOException, ClassNotFoundException , RepositoryException { 409 ByteArrayInputStream inStream = null; 411 try { 412 String ruleString = this.getSystemNode(versionedNode).getNodeData(PROPERTY_RULE).getString(); 413 inStream = new ByteArrayInputStream(Base64.decodeBase64(ruleString.getBytes())); 414 ObjectInput objectInput = new ObjectInputStream(inStream); 415 return (Rule) objectInput.readObject(); 416 } 417 catch (IOException e) { 418 throw e; 419 } 420 catch (ClassNotFoundException e) { 421 throw e; 422 } 423 finally { 424 IOUtils.closeQuietly(inStream); 425 } 426 } 427 428 433 protected synchronized Content getSystemNode(Content node) throws RepositoryException { 434 try { 435 return node.getContent(SYSTEM_NODE); 436 } 437 catch (PathNotFoundException e) { 438 return node.createContent(SYSTEM_NODE, ItemType.SYSTEM); 439 } 440 } 441 442 446 protected void impersonateAccessManager(List permissions) { 447 this.getHierarchyManager().getAccessManager().setPermissionList(permissions); 448 } 449 450 454 protected void revertAccessManager(List permissions) { 455 this.getHierarchyManager().getAccessManager().setPermissionList(permissions); 456 } 457 458 461 protected List getAccessManagerPermissions() { 462 return this.getHierarchyManager().getAccessManager().getPermissionList(); 463 } 464 465 468 protected HierarchyManager getHierarchyManager() { 469 return MgnlContext.getHierarchyManager(VersionManager.VERSION_WORKSPACE); 470 } 471 472 473 } 474 | Popular Tags |