/*
* Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.registry.jcr.version;
import org.wso2.carbon.registry.core.CollectionImpl;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.jcr.RegistryNode;
import org.wso2.carbon.registry.jcr.RegistrySession;
import org.wso2.carbon.registry.jcr.util.RegistryJCRItemOperationUtil;
import org.wso2.carbon.registry.jcr.util.RegistryJCRSpecificStandardLoderUtil;
import javax.jcr.*;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//TODO persist version history with versions inside them in repo tree
public class RegistryVersionManager implements VersionManager {
private static long versionCounter = 0;
private Session session;
private Map<String, VersionHistory> versionHistories = new HashMap<String, VersionHistory>();
private String currentActivityNodePath = "";
private int configNodeCount = 0;
public RegistryVersionManager(Session session) {
this.session = session;
// loadActivityNodes();
}
// private void loadActivityNodes() {
// try {
//
// if ((!(((RegistrySession) session).itemExists("/jcr:system")) && ((RegistrySession) session).itemExists("/jcr:system/jcr:activities"))) {
// ((RegistrySession) session).getRootNode().addNode("jcr:system").addNode("jcr:activities");
// }
// } catch (RepositoryException e) {
// e.printStackTrace();
// }
//
// }
private Version createVersionOnNode(String nodePath) throws RegistryException {
String latestVersionPath = "";
Version version = null;
((RegistrySession) session).getUserRegistry().createVersion(nodePath);
String[] regVerPaths = ((RegistrySession) session).getUserRegistry().getVersions(nodePath);
//NOTE: Here the latest version path is given by the last element of tye version array
latestVersionPath = regVerPaths[0];
addVersionToHistory(nodePath, latestVersionPath);
version = new RegistryVersion(latestVersionPath, System.currentTimeMillis(), nodePath, session);
if (versionHistories.get(nodePath) != null) {
((RegistryVersionHistory) versionHistories.
get(nodePath)).getVersionList().add(version);
((RegistryVersion) version).setVersionHistory(
(RegistryVersionHistory) versionHistories.get(nodePath));
} else {
RegistryVersionHistory vh = new RegistryVersionHistory(session,nodePath);
vh.getVersionList().add(version);
((RegistryVersion) version).setVersionHistory(vh);
versionHistories.put(nodePath, vh);
}
return version;
}
public Version checkin(String s) throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException {
Version version = null;
String latestVersionPath = "";
if (!isNodeTypeVersionable(s)) {
throw new UnsupportedRepositoryOperationException("Cannot apply checkin for non versionalbe nodes .!!!");
}
try {
RegistryJCRItemOperationUtil.validateSessionSaved((RegistrySession) session);
Value propVal = ((Node) session.getItem(s)).getProperty("jcr:checkedOut").getValue();
if ((propVal != null) && (propVal.getString().equals("true"))) {
CollectionImpl vnode = ((CollectionImpl) ((RegistrySession) session).getUserRegistry().get(s));
vnode.setProperty("jcr:checkedOut", "false");
vnode.setProperty("jcr:isCheckedOut", "false");
((RegistrySession)session).getUserRegistry().put(s, vnode);
version = createVersionOnNode(s);
// latestVersionPath = createVersionOnNodeAndGetVersionPath(s);
// if (((RegistrySession) session).getUserRegistry().get(s) instanceof CollectionImpl) {
// addVersionToHistory(s,latestVersionPath);
// }
// version = new RegistryVersion(latestVersionPath, System.currentTimeMillis(), s, session);
//
// if (versionHistories.get(s) != null) {
//
// ((RegistryVersionHistory) versionHistories.get(s)).getVersionList().add(version);
// ((RegistryVersion) version).setVersionHistory((RegistryVersionHistory) versionHistories.get(s));
//
// } else {
//
// RegistryVersionHistory vh = new RegistryVersionHistory(session);
// vh.getVersionList().add(version);
// ((RegistryVersion) version).setVersionHistory(vh);
// versionHistories.put(s, vh);
// }
} else {
// node already checked in
List<String> list = getVersionList(s);
version = new RegistryVersion(list.get(list.size() - 1), System.currentTimeMillis(), s, session);
}
} catch (PathNotFoundException e) {
version = getBaseVersion(s);
} catch (RegistryException e) {
throw new RepositoryException("Exception occurred at registry level..!!" + e.getMessage());
} catch (InvalidItemStateException e) {
throw new InvalidItemStateException("Cannot do checkin to unsaved nodes..!!!");
}
return version;
}
private void addVersionToHistory(String nodePath, String nodeVersion) {
try {
String confPath = RegistryJCRSpecificStandardLoderUtil.
getSystemConfigVersionPath((RegistrySession) session);
Resource resource = ((RegistrySession) session).getUserRegistry().get(confPath);
if (resource.getProperty(nodePath) != null) {
resource.getPropertyValues(nodePath).add(nodeVersion);
} else {
List<String> list = new ArrayList<String>();
list.add(nodeVersion);
resource.setProperty(nodePath, list);
}
((RegistrySession) session).getUserRegistry().put(confPath, resource);
} catch (RegistryException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
private List<String> getVersionList(String nodePath) throws RegistryException {
String confPath = RegistryJCRSpecificStandardLoderUtil.
getSystemConfigVersionPath((RegistrySession) session);
return ((RegistrySession) session).getUserRegistry().get(confPath).getPropertyValues(nodePath);
}
private boolean isNodeTypeVersionable(String s) throws RepositoryException {
if (session.getNode(s).isNodeType("mix:versionable") ||
session.getNode(s).isNodeType("mix:simpleVersionable")) {
return true;
} else {
return false;
}
}
public void checkout(String s) throws UnsupportedRepositoryOperationException, LockException, RepositoryException {
if (!isNodeTypeVersionable(s)) {
throw new UnsupportedRepositoryOperationException("Cannot apply checkout for non versionalbe nodes .!!!");
}
try {
Resource resource = ((RegistrySession) session).getUserRegistry().get(s);
resource.setProperty("jcr:checkedOut", "true"); // no need both.But as in JCR spec there are two properties to set
resource.setProperty("jcr:isCheckedOut", "true");
((RegistrySession) session).getUserRegistry().put(s, resource);
} catch (RegistryException e) {
throw new RepositoryException("Exception occurred at Registry level");
}
}
public Version checkpoint(String s) throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException {
checkout(s);
return checkin(s);
}
public boolean isCheckedOut(String s) throws RepositoryException {
try {
String propVal1 = ((RegistrySession) session).getUserRegistry().get(s).getProperty("jcr:checkedOut");
String propVal2 = ((RegistrySession) session).getUserRegistry().get(s).getProperty("jcr:isCheckedOut");
if (propVal1.equals("true")
|| (propVal2.equals("true"))) {
return true;
}
if (propVal1.equals("false")
|| (propVal2.equals("false"))) {
return false;
}
} catch (NullPointerException e) {
// isCheckout is false
} catch (RegistryException e) {
throw new RepositoryException(e.getMessage());
}
return nonVersionableNodeChckoutCheck(s);
}
private boolean nonVersionableNodeChckoutCheck(String s) throws RepositoryException {
Node vParent = null;
try {
vParent = session.getNode(s).getParent();
while (!vParent.isNodeType("mix:simpleVersionable")) {
vParent = vParent.getParent();
}
} catch (ItemNotFoundException e) {
// root reached.
} catch (AccessDeniedException e) {
throw new AccessDeniedException("Access denied on node " + s);
} catch (PathNotFoundException e) {
throw new PathNotFoundException("No such path exists " + s);
}
try {
if (vParent != null && vParent.isNodeType("mix:simpleVersionable")) {
if (vParent.isCheckedOut()) {
return true;
} else {
return false;
}
} else {
return true;
}
} catch (RepositoryException e) {
throw new RepositoryException(e.getMessage());
}
}
public VersionHistory getVersionHistory(String s) throws UnsupportedRepositoryOperationException, RepositoryException {
if (versionHistories.get(s) == null) {
versionHistories.put(s, new RegistryVersionHistory(session,s));
}
return versionHistories.get(s);
}
public Version getBaseVersion(String s) throws UnsupportedRepositoryOperationException, RepositoryException {
if (((RegistryVersionHistory) versionHistories.get(s) != null) &&
(((RegistryVersionHistory) versionHistories.get(s)).getVersionList().size() > 0)) {
List<Version> list = ((RegistryVersionHistory) versionHistories.get(s)).getVersionList();
return list.get(list.size() - 1);
} else {
return null;
}
}
public void restore(Version[] versions, boolean b) throws ItemExistsException, UnsupportedRepositoryOperationException, VersionException, LockException, InvalidItemStateException, RepositoryException {
//TODO
for (Version version : versions) {
restore(version, b);
}
}
private boolean isVersionInNodeVersionHistory(String nodePth, String vPath) throws RegistryException, VersionException {
if (((getVersionList(nodePth).contains(vPath)))) {
return true;
} else {
throw new VersionException("No such version in node's version history" + nodePth);
}
}
private boolean isValidVersionName(String nodePath) throws UnsupportedRepositoryOperationException {
try {
session.getItem(nodePath);
} catch (PathNotFoundException e) {
throw new UnsupportedRepositoryOperationException("Unsupported : non versionable node " + nodePath);
} catch (RepositoryException e) {
throw new UnsupportedRepositoryOperationException("Unsupported : non versionable node " + nodePath);
}
return true;
}
public void restore(String s, String s1, boolean b) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
//s1 =null when it is root version
if (s1 == null) {
throw new VersionException("Cannot do restore opeartion on jcr:rootVersion ..!!!");
}
// Check node is versionable
if (!isNodeTypeVersionable(s)) {
throw new UnsupportedRepositoryOperationException("Cannot do restore on non versionable nodes");
}
try {
RegistryJCRItemOperationUtil.validateSessionSaved((RegistrySession) session);
if (isNodeTypeVersionable(s)
&& isValidVersionName(s)
&& isVersionInNodeVersionHistory(s, s1)
) {
((RegistrySession) session).getUserRegistry().restoreVersion(s1);
Resource resource = ((RegistrySession) session).getUserRegistry().get(s);
resource.setProperty("jcr:isCheckedOut", "false");
resource.setProperty("jcr:checkedOut", "false");
((RegistrySession) session).getUserRegistry().put(s, resource);
createVersionOnNode(s);
}
} catch (VersionException e) {
throw new VersionException("No such version in node's version history" + s);
} catch (UnsupportedRepositoryOperationException e) {
throw new UnsupportedRepositoryOperationException("Node type not Versionable : " + s);
} catch (InvalidItemStateException e) {
throw new InvalidItemStateException("Invalid Item state: operations are still unsaved");
} catch (RegistryException e) {
throw new RepositoryException("Excepion occurred in registry level while restoring");
}
}
// private String getNodePathFromVersionName(String s) {
// if (!s.contains("/")) {
// return s;
// }
// return s.substring(0, s.lastIndexOf("/"))
// + "/"
// + s.split("/")[s.split("/").length - 1].split(";")[0];
//
// }
public void restore(Version version, boolean b) throws VersionException, ItemExistsException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException {
if (version != null && version.getName() == null) {
throw new VersionException("Cannot do restore opeartion on jcr:rootVersion ..!!!");
}
// Check node is versionable
if (!isNodeTypeVersionable(RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()))) {
throw new UnsupportedRepositoryOperationException("Cannot do restore on non versionable nodes");
}
try {
RegistryJCRItemOperationUtil.validateSessionSaved((RegistrySession) session);
if ((version != null)
&& isValidVersionName(
RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()))
&& (isVersionInNodeVersionHistory(
RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()), version.getName()))
) {
((RegistrySession) session).getUserRegistry().restoreVersion(version.getName());
// version.getFrozenNode().setProperty("jcr:isCheckedOut", "false");
Resource resource = ((RegistrySession) session).getUserRegistry().
get(RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()));
resource.setProperty("jcr:isCheckedOut", "false");
resource.setProperty("jcr:checkedOut", "false");
((RegistrySession) session).getUserRegistry().put(
RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()), resource);
//create a new version at restore in simple versioning
createVersionOnNode(RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()));
}
} catch (VersionException e) {
throw new VersionException("No such version in node's version history" +
RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()));
} catch (InvalidItemStateException e) {
throw new InvalidItemStateException("Invalid Item state: operations are still unsaved");
} catch (RegistryException e) {
throw new RepositoryException("Excepion occurred in registry level while restoring");
}
}
public void restore(String s, Version version, boolean b) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
if (version != null && version.getName() == null) {
throw new VersionException("Cannot do restore opeartion on jcr:rootVersion ..!!!");
}
// Check node is versionable
if (!isNodeTypeVersionable(s)) {
throw new UnsupportedRepositoryOperationException("Cannot do restore on non versionable nodes");
}
try {
RegistryJCRItemOperationUtil.validateSessionSaved((RegistrySession) session);
Item i = session.getItem(s);
throw new VersionException("There must be no existing node at absPath " + s);
} catch (InvalidItemStateException e) {
throw new InvalidItemStateException("Invalid Item state: operations are still unsaved");
} catch (PathNotFoundException e) {
//success
}
try {
if ((version != null)
&& isNodeTypeVersionable(s)
&& isValidVersionName(s)
&& (isVersionInNodeVersionHistory(s, version.getName()))
) {
((RegistrySession) session).getUserRegistry().restoreVersion(version.getName());
Resource resource = ((RegistrySession) session).getUserRegistry().
get(RegistryJCRItemOperationUtil.getNodePathFromVersionName(version.getName()));
resource.setProperty("jcr:isCheckedOut", "false");
resource.setProperty("jcr:checkedOut", "false");
((RegistrySession) session).getUserRegistry().put(
RegistryJCRItemOperationUtil.
getNodePathFromVersionName(version.getName()), resource);
createVersionOnNode(RegistryJCRItemOperationUtil.
getNodePathFromVersionName(version.getName()));
}
} catch (VersionException e) {
throw new VersionException("No such version in node's version history" + s);
} catch (RegistryException e) {
throw new RepositoryException("Excepion occurred in registry level while restoring");
}
}
public void restoreByLabel(String s, String s1, boolean b) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
try {
String verPath = ((RegistrySession) session).getUserRegistry().get(
RegistryJCRSpecificStandardLoderUtil.
getSystemConfigVersionLabelPath((RegistrySession) session)).
getProperty(s1);
((RegistrySession) session).getUserRegistry().restoreVersion(verPath);
} catch (RegistryException e) {
throw new RepositoryException(
"Excepion occurred in registry level while restoring by label on : " + s);
}
}
// TODO :All merging stuff
public NodeIterator merge(String s, String s1, boolean b) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
return null;
}
public NodeIterator merge(String s, String s1, boolean b, boolean b1) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
return null;
}
public void doneMerge(String s, Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException {
}
public void cancelMerge(String s, Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException {
}
public Node createConfiguration(String s) throws UnsupportedRepositoryOperationException, RepositoryException {
/*
Calling createConfiguration on the node N at absPath creates, in the configuration storage, a new
nt:configuration node whose root is N. A reference to N is recorded in the jcr:root
property of the new configuration, and a reference to the new configuration
is recorded in the jcr:configuration property of N
*/
String configNodeName = "jcr:configNode" + configNodeCount++;
((RegistryNode) session.getItem(s)).addNode(configNodeName, "nt:configuration").setProperty("jcr:root", s);
((RegistryNode) session.getItem(s)).setProperty("jcr:configuration", s + "/" + configNodeName);
return (RegistryNode) session.getItem(s + "/" + configNodeName);
}
public Node setActivity(Node node) throws UnsupportedRepositoryOperationException, RepositoryException {
RegistryNode acNode = null;
if (node == null) {
currentActivityNodePath = "";
if (((RegistryNode) session.getItem("/jcr:system/jcr:activities")).getNodes().hasNext()) {
acNode = (RegistryNode) ((RegistryNode) session.getItem("/jcr:system/jcr:activities")).getNodes().next();
}
} else {
currentActivityNodePath = node.getPath();
acNode = (RegistryNode) createActivity(node.getPath());
}
return acNode;
}
public Node getActivity() throws UnsupportedRepositoryOperationException, RepositoryException {
return (Node) ((RegistrySession) session).getItem(currentActivityNodePath);
}
public Node createActivity(String s) throws UnsupportedRepositoryOperationException, RepositoryException {
currentActivityNodePath = "/jcr:system/jcr:activities" + s;
return ((RegistryNode) ((RegistrySession) session).getItem("/jcr:system/jcr:activities")).addNode(s, "nt:activity");
}
public void removeActivity(Node node) throws UnsupportedRepositoryOperationException, VersionException, RepositoryException {
((RegistrySession) session).removeItem(node.getPath());
}
public NodeIterator merge(Node node) throws VersionException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
return null;
}
}