/*
* $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/VersioningHelper.java,v 1.95.2.2 2004/02/05 16:11:25 mholz Exp $
* $Revision: 1.95.2.2 $
* $Date: 2004/02/05 16:11:25 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* 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.apache.slide.webdav.util;
import org.apache.slide.util.*;
import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenWrapper;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.lock.Lock;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.macro.ConflictException;
import org.apache.slide.macro.Macro;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.Search;
import org.apache.slide.search.SearchQuery;
import org.apache.slide.search.SearchQueryResult;
import org.apache.slide.search.SlideUri;
import org.apache.slide.search.basic.Literals;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.ActionNode;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.util.Configuration;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.method.MethodNotAllowedException;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.PropertyHelper;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlledImpl;
import org.apache.slide.webdav.util.resourcekind.CheckedOut;
import org.apache.slide.webdav.util.resourcekind.CheckedOutVersionControlled;
import org.apache.slide.webdav.util.resourcekind.DeltavCompliantUnmappedUrl;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.apache.slide.webdav.util.resourcekind.Version;
import org.apache.slide.webdav.util.resourcekind.VersionControlled;
import org.apache.slide.webdav.util.resourcekind.VersionControlledImpl;
import org.apache.slide.webdav.util.resourcekind.VersionHistoryImpl;
import org.apache.slide.webdav.util.resourcekind.VersionImpl;
import org.apache.slide.webdav.util.resourcekind.Working;
import org.apache.slide.webdav.util.resourcekind.WorkingImpl;
import org.apache.slide.webdav.util.resourcekind.WorkspaceImpl;
import org.apache.util.WebdavStatus;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
/**
* Helper class for versioning operations. Allows to execute the operation from
* within multiple methods.
*
* @author <a href="mailto:peter.nevermann@softwareag.com">Peter Nevermann</a>
*/
public class VersioningHelper extends AbstractWebdavHelper {
/**
* Factory method.
*/
public static VersioningHelper
getVersioningHelper( SlideToken sToken, NamespaceAccessToken nsaToken,
HttpServletRequest req, HttpServletResponse resp, WebdavServletConfig sConf ) {
return new VersioningHelper( sToken, nsaToken, req, resp, sConf );
}
/**
** The SAXBuilder used to create JDOM Documents.
**/
protected static SAXBuilder saxBuilder = null;
private Content content = null;
private Structure structure = null;
private Macro macro = null;
private Lock lock = null;
private HttpServletRequest req = null;
private HttpServletResponse resp = null;
private WebdavServletConfig sConf = null;
private PropertyHelper pHelp = null;
private String serverURL = null;
/**
* The URI of the <code>modifyRevisionMetadataAction</code>.
*/
protected final String modifyMetadataUri;
/**
* The URI of the <code>modifyRevisionContentAction</code>.
*/
protected final String modifyContentUri;
/**
* Protected contructor
*/
protected VersioningHelper( SlideToken sToken, NamespaceAccessToken nsaToken,
HttpServletRequest req, HttpServletResponse resp, WebdavServletConfig sConf ) {
super( sToken, nsaToken );
this.req = req;
this.resp = resp;
this.sConf = sConf;
this.content = nsaToken.getContentHelper();
this.structure = nsaToken.getStructureHelper();
this.macro = nsaToken.getMacroHelper();
this.lock = nsaToken.getLockHelper();
this.pHelp = PropertyHelper.getPropertyHelper( sToken, nsaToken, sConf );
ActionNode actionNode = nsaToken.getNamespaceConfig().getModifyRevisionMetadataAction();
if (actionNode != null) {
modifyMetadataUri = actionNode.getUri();
}
else {
modifyMetadataUri = "";
}
actionNode = nsaToken.getNamespaceConfig().getModifyRevisionContentAction();
if (actionNode != null) {
modifyContentUri = actionNode.getUri();
}
else {
modifyContentUri = "";
}
serverURL = "http://" + req.getServerName()+ ":" + req.getServerPort();
}
/**
* Returns slide Uri determinating the NodeRevisionDescriptors and
* NodeRevisionDescriptor associated with the given <code>resourcePath</code>.
* If the given <code>label</code> is not <code>null</code>, and the
* <code>resourcePath</code> identifies a VCR, the revision with that label
* of the associated history is returned.
*
* @param resourcePath the path of the resource for which to retrieve
* the SlideResource.
* @param label the label of the revision to return. May be
* <code>null</code>.
*
* @return slide Uri determinating the NodeRevisionDescriptors and
* NodeRevisionDescriptor associated with the given
* <code>resourcePath</code>.
*
* @throws SlideException
* @throws LabeledRevisionNotFoundException if no revision with the specified
* label was found.
*/
public String getLabeledResourceUri(String resourcePath, String label) throws SlideException, LabeledRevisionNotFoundException {
if (label == null) {
return resourcePath;
}
else {
SlideToken lightSToken = sToken;
if (sToken.isForceStoreEnlistment() || sToken.isForceLock()) {
lightSToken = new SlideTokenWrapper(sToken, false);
lightSToken.setForceLock(false);
}
return getLabeledResourceUri(nsaToken, lightSToken, content, resourcePath, label);
}
}
/**
* If the <code>resourcePath</code> identifies a VHR, the associated revision
* with the given <code>label</code> is returned. If the <code>resourcePath</code>
* does not identify a VHR , <code>null</code> is returned.
*
* @param resourcePath the path of the resource for which to retrieve
* the NRD.
* @param label the label of the revision to return.
*
* @return the associated revision with the given <code>label</code>.
*
* @throws SlideException
* @throws LabeledRevisionNotFoundException if no revision with the specified
* label was found.
*/
public NodeRevisionDescriptor retrieveLabeledRevision(String resourcePath, String label) throws SlideException, LabeledRevisionNotFoundException {
return retrieveLabeledRevision(nsaToken, sToken, content, resourcePath, label);
}
/**
* Set the specified resource under version control
*
* @param resourcePath the URI of the resource to version-control
* @throws SlideException
*/
public void versionControl( String resourcePath ) throws SlideException {
UriHandler rUh = UriHandler.getUriHandler( resourcePath );
Iterator i;
Enumeration j;
NodeRevisionDescriptors rNrds = content.retrieve( sToken, resourcePath );
NodeRevisionDescriptor rNrd = content.retrieve( sToken, rNrds );
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, resourcePath, rNrd );
if( !rRk.isSupportedMethod(req.getMethod()) ) {
throw new MethodNotAllowedException( rRk );
}
// Check for rRk = K_VERSION_CONTROLLED*
if( rRk instanceof VersionControlled ) {
// nothing to do
return;
}
// Set initial VR properties
NodeRevisionDescriptor vrNrd =
new NodeRevisionDescriptor(req.getContentLength());
i = pHelp.createInitialProperties(VersionImpl.getInstance()).iterator();
while( i.hasNext() )
vrNrd.setProperty( (NodeProperty)i.next() );
// Copy dead properties VCR -> VR
j = rNrd.enumerateProperties();
while( j.hasMoreElements() ) {
NodeProperty p = (NodeProperty)j.nextElement();
if( p.isLiveProperty() )
continue;
if( !vrNrd.exists(p.getName()) )
vrNrd.setProperty( p );
}
// Copy properties VCR->VR
NodeRevisionContent rNrc = content.retrieve( sToken, rNrds, rNrd );
vrNrd.setContentType(rNrd.getContentType()); // P_GETCONTENTTYPE
vrNrd.setContentLength(rNrd.getContentLength()); // P_GETCONTENTLENGTH
vrNrd.setContentLanguage(rNrd.getContentLanguage()); // P_GETCONTENTLANGUAGE
String comment = "INITIAL VERSION. ";
if( rNrd.exists(P_COMMENT) )
comment += (String)rNrd.getProperty(P_COMMENT).getValue();
vrNrd.setProperty(
new NodeProperty(P_COMMENT, comment) );
// Set initial VHR properties
Vector vhrLabels = new Vector();
Hashtable vhrProps = new Hashtable();
String vhrBranch = NodeRevisionDescriptors.MAIN_BRANCH;
NodeRevisionDescriptor vhrNrd =
new NodeRevisionDescriptor( NodeRevisionNumber.HIDDEN_0_0, vhrBranch, vhrLabels, vhrProps );
i = pHelp.createInitialProperties(VersionHistoryImpl.getInstance()).iterator();
while( i.hasNext() )
vhrNrd.setProperty( (NodeProperty)i.next() );
// Set initial VCR properties (do not overwrite existing!!)
i = pHelp.createInitialProperties(VersionControlledImpl.getInstance()).iterator();
while( i.hasNext() ) {
NodeProperty p = (NodeProperty)i.next();
if( !rNrd.exists(p.getName()) )
rNrd.setProperty( p );
}
// Create VHR/VR
UriHandler vhrUh = UriHandler.createNextHistoryUri( sToken, nsaToken, rUh );
String vhrUri = String.valueOf( vhrUh );
SubjectNode vhrNode = new SubjectNode();
structure.create( sToken, vhrNode, String.valueOf(vhrUh) );
content.create( sToken, vhrUri, true ); //isVersioned=true
content.create( sToken, vhrUri, vrNrd, rNrc );
NodeRevisionDescriptors vhrNrds =
content.retrieve( sToken, vhrUri );
content.create(
sToken, vhrUri, null, vhrNrd, null ); //branch=null, revisionContent=null
// Create VR node
NodeRevisionNumber vrVersion = vrNrd.getRevisionNumber();
SubjectNode vrNode = new SubjectNode();
UriHandler vrUh =
UriHandler.createVersionUri( vhrUh, String.valueOf(vrVersion) );
String vrUri = String.valueOf( vrUh );
structure.create( sToken, vrNode, String.valueOf(vrUh) );
// Set specific properties
vrNrd.setName(rUh.getName()); // P_DISPLAYNAME
rNrd.setProperty(
new NodeProperty(P_CHECKED_IN, pHelp.createHrefValue(vrUri)) );
vhrNrd.setCreationDate( new Date() ); // P_CREATIONDATE
setCreationUser(vhrNrd);
vhrNrd.setLastModified( new Date() ); // P_GETLASTMODIFIED
vhrNrd.setContentLength( 0 ); // P_GETCONTENTLENGTH
vhrNrd.setETag( PropertyHelper.computeEtag(vhrUri, vhrNrd) ); // P_GETETAG
vhrNrd.setName( vhrUh.getHistoryName() ); // P_DISPLAYNAME
vhrNrd.setProperty(
new NodeProperty(P_VERSION_SET, pHelp.createHrefValue(vrUri)) );
vrNrd.setCreationDate( new Date() ); // P_CREATIONDATE
setCreationUser(vrNrd);
vrNrd.setLastModified( new Date() ); // P_GETLASTMODIFIED
vrNrd.setETag( PropertyHelper.computeEtag(vrUri, vrNrd)); // P_GETETAG
vrNrd.setProperty(
new NodeProperty(P_VERSION_NAME, vrUh.getVersionName()) );
// Store changes
content.store( sToken, resourcePath, rNrd, null ); //revisionContent=null
content.store( sToken, vhrUri, vhrNrd, null ); //revisionContent=null
content.store( sToken, vhrUri, vrNrd, null ); //revisionContent=null
}
/**
* Create new VCR for an existing version history.
* @pre existingVersionPath != null
*
* @param resourcePath the URI of the resource to version-control
* @param existingVersionPath the URI of the VR on which the new VCR will be based
* @throws SlideException
*/
public void versionControl( String resourcePath, String existingVersionPath ) throws SlideException {
Iterator i;
UriHandler rUh = UriHandler.getUriHandler( resourcePath );
UriHandler evUh = UriHandler.getUriHandler( existingVersionPath );
if ( ! evUh.isVersionUri() ) {
throw new PreconditionViolationException(
new ViolatedPrecondition(C_MUST_BE_VERSION, WebdavStatus.SC_CONFLICT), resourcePath);
}
NodeRevisionNumber evNrn = new NodeRevisionNumber( evUh.getVersionName() );
NodeRevisionDescriptors rNrds = null;
NodeRevisionDescriptor rNrd = null;
NodeRevisionDescriptors vcrNrds = null;
NodeRevisionDescriptor vcrNrd = null;
NodeRevisionDescriptors evNrds = null;
NodeRevisionDescriptor evNrd = null;
try {
rNrds = content.retrieve( sToken, resourcePath );
rNrd = content.retrieve( sToken, rNrds );
}
catch( ObjectNotFoundException e ) {}; // can be ignored here!
try {
evNrds = content.retrieve( sToken, existingVersionPath );
evNrd = content.retrieve( sToken, evNrds /*, evNrn*/ ); //existingVersionPath
//redirector should do the job
//s.t. evNrn is not required
}
catch( ObjectNotFoundException e ) {}; // can be ignored here!
ViolatedPrecondition violatedPrecondition =
getVersionControlPreconditionViolation(resourcePath,
rNrd,
rUh,
existingVersionPath,
evNrd,
evUh);
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition,
resourcePath);
}
// create the VCR
String vcrUri = String.valueOf(rUh);
String evUri = String.valueOf(evUh);
UriHandler vcrUh = UriHandler.getUriHandler( vcrUri );
vcrNrd = new NodeRevisionDescriptor(0);
i = pHelp.createInitialProperties(VersionControlledImpl.getInstance()).iterator();
while( i.hasNext() )
vcrNrd.setProperty( (NodeProperty)i.next() );
// Set specific properties
vcrNrd.setLastModified( new Date() ); //P_GETLASTMODIFIED
vcrNrd.setContentLength( evNrd.getContentLength() ); // P_GETCONTENTLENGTH
vcrNrd.setETag( PropertyHelper.computeEtag(vcrUri, vcrNrd)); // P_GETETAG
vcrNrd.setContentType( evNrd.getContentType() ); // P_GETCONTENTTYPE
vcrNrd.setContentLanguage(evNrd.getContentLanguage()); // P_GETCONTENTLANGUAGE
String[] utok = vcrUh.getUriTokens();
if (!Configuration.useBinding(nsaToken.getUri(sToken, vcrUri).getStore())) {
vcrNrd.setName( utok[utok.length - 1] ); // P_DISPLAYNAME
}
vcrNrd.setCreationDate( new Date() ); // P_CREATIONDATE
setCreationUser(vcrNrd);
vcrNrd.setProperty( new NodeProperty(P_CHECKED_IN,
pHelp.createHrefValue(evUri)) );
// set workspace
setWorkspaceProperty( vcrUri, vcrNrd );
// store
SubjectNode vcrNode = new SubjectNode();
structure.create( sToken, vcrNode, vcrUri );
NodeRevisionContent evContent =
content.retrieve( sToken, evNrds, evNrd );
content.create( sToken, vcrUri, vcrNrd, evContent );
// Set status created
resp.setStatus( WebdavStatus.SC_CREATED );
}
/**
* Returns the precondition that might have been violated on an attempt to create
* a new VCR in a workspace for an existing version history.
* The following precondtions are checked:
* <ul>
* <li><DAV:cannot-add-to-existing-history></li>
* <li><DAV:must-be-version></li>
* <li><DAV:one-version-controlled-resource-per-history-per-workspace></li>
* </ul>
*
* @param resourcePath the path of the resource.
* @param resourceNrd the NodeRevisionDescriptor of the resource.
* @param resourceUriHandler the UriHandler of the resource.
* @param existingVersionPath the path of the existing version.
* @param existingVersionNrd the NodeRevisionDescriptor of the existing version.
* @param existingVersionUriHandler the UriHandler of the existing version.
*
* @return the precondition that has been violated (if any).
*
* @throws SlideException
*/
public ViolatedPrecondition getVersionControlPreconditionViolation(String resourcePath,
NodeRevisionDescriptor resourceNrd,
UriHandler resourceUrihandler,
String existingVersionPath,
NodeRevisionDescriptor existingVersionNrd,
UriHandler existingVersionUrihandler) throws SlideException {
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, resourcePath, resourceNrd );
ResourceKind evRk = AbstractResourceKind.determineResourceKind( nsaToken, existingVersionPath, existingVersionNrd );
if( !(rRk instanceof DeltavCompliantUnmappedUrl) ) {
return new ViolatedPrecondition(C_CANNOT_ADD_TO_EXISTING_HISTORY, WebdavStatus.SC_CONFLICT);
}
if( !(evRk instanceof Version) || existingVersionNrd == null) {
return new ViolatedPrecondition(C_MUST_BE_VERSION, WebdavStatus.SC_CONFLICT);
}
String scope = resourceUrihandler.getAssociatedWorkspaceUri();
if( scope == null )
scope = UriHandler.bestMatchingScope(nsaToken.getName(), resourceUrihandler).toString();
String historyPath = existingVersionUrihandler.getAssociatedHistoryUri();
SearchQueryResult queryResult = searchResourcesWithGivenHistory(historyPath, scope, Integer.MAX_VALUE);
Iterator queryResultIterator = queryResult.iterator();
if (queryResultIterator.hasNext()) {
return new ViolatedPrecondition(C_ONE_VERSION_CONTROLLED_RESOURCE_PER_HISTORY_PER_WORKSPACE,
WebdavStatus.SC_CONFLICT);
}
return null;
}
/**
* Searches all resources in the given <code>scope</code> that have either a
* <code><checked-in></code> or <code><checked-in></code> property
* with a <code><href></code> element containing the given
* <code>historyPath</code>.
*
* @param historyPath the path of the history.
* @param scope the scope of the search.
*
* @return all matching resources.
*
* @throws ServiceAccessException
* @throws BadQueryException
*/
protected SearchQueryResult searchResourcesWithGivenHistory(String historyPath, String scope, int maxDepth) throws ServiceAccessException, BadQueryException {
// make it a relative scope
// if (scope.startsWith("/")) {
// scope = scope.substring (1);
// }
SlideUri slideUri = new SlideUri (req.getRequestURI());
String absPath = slideUri.getContextPath (scope);
Element basicSearch = getResourcesWithVersionHistoryQueryElement(absPath,
historyPath);
String grammarNamespace = basicSearch.getNamespaceURI();
Search searchHelper = nsaToken.getSearchHelper();
SearchQuery searchQuery = searchHelper.createSearchQuery(grammarNamespace,
basicSearch,
sToken,
maxDepth,
req.getRequestURI());
SearchQueryResult queryResult = searchHelper.search(sToken, searchQuery);
return queryResult;
}
/**
* Returns the query document used to search all resources in the given
* <code>scope</code> that have either a <checked-in> or <checked-out>
* property with a <href> value containing the URI that identifies a
* version of the given history.
*
* @param scope the scope of the search.
* @param historyPath the Uri of the history.
*
* @return the query document.
*/
protected Element getResourcesWithVersionHistoryQueryElement(String scope, String historyPath) {
Element resourcesWithVersionHistoryQueryElement = new Element(DaslConstants.E_BASICSEARCH, NamespaceCache.DEFAULT_NAMESPACE);
Element select = new Element(DaslConstants.E_SELECT, NamespaceCache.DEFAULT_NAMESPACE);
resourcesWithVersionHistoryQueryElement.addContent(select);
Element prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
select.addContent(prop);
Element checkedIn = new Element(P_CHECKED_IN, NamespaceCache.DEFAULT_NAMESPACE);
prop.addContent(checkedIn);
Element checkedOut = new Element(P_CHECKED_OUT, NamespaceCache.DEFAULT_NAMESPACE);
prop.addContent(checkedOut);
Element from = new Element(DaslConstants.E_FROM, NamespaceCache.DEFAULT_NAMESPACE);
resourcesWithVersionHistoryQueryElement.addContent(from);
Element scopeElement = new Element(DaslConstants.E_SCOPE, NamespaceCache.DEFAULT_NAMESPACE);
from.addContent(scopeElement);
Element href = new Element(E_HREF, NamespaceCache.DEFAULT_NAMESPACE);
scopeElement.addContent(href);
href.setText(scope);
Element where = new Element(DaslConstants.E_WHERE, NamespaceCache.DEFAULT_NAMESPACE);
resourcesWithVersionHistoryQueryElement.addContent(where);
Element or = new Element(Literals.OR, NamespaceCache.DEFAULT_NAMESPACE);
where.addContent(or);
Element propcontains = new Element(DaslConstants.E_PROPCONTAINS, NamespaceCache.SLIDE_NAMESPACE);
or.addContent(propcontains);
prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
propcontains.addContent(prop);
prop.addContent((Element)checkedIn.clone());
Element literal = new Element(DaslConstants.E_LITERAL, NamespaceCache.DEFAULT_NAMESPACE);
propcontains.addContent(literal);
literal.setText(historyPath);
propcontains = new Element(DaslConstants.E_PROPCONTAINS, NamespaceCache.SLIDE_NAMESPACE);
or.addContent(propcontains);
prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
propcontains.addContent(prop);
prop.addContent((Element)checkedOut.clone());
literal = new Element(DaslConstants.E_LITERAL, NamespaceCache.DEFAULT_NAMESPACE);
propcontains.addContent(literal);
literal.setText(historyPath);
return resourcesWithVersionHistoryQueryElement;
}
/**
* Set the workspace property if needed.
*
* @param rUri the URI of the resource to set the workspace property
* @param rNrd the NodeRevisionDescriptor to set the workspace property
*/
public void setWorkspaceProperty( String rUri, NodeRevisionDescriptor rNrd ) {
UriHandler rUh = UriHandler.getUriHandler( rUri );
String wsUri = rUh.getAssociatedWorkspaceUri();
if( wsUri != null ) {
rNrd.setProperty(
new NodeProperty(P_WORKSPACE, pHelp.createHrefValue(wsUri)) );
}
else {
rNrd.removeProperty(P_WORKSPACE);
}
}
/**
* Create the specified workspace.
*
* @param resourcePath the URI of the workspace to create
* @throws SlideException
*/
public void mkworkspace( String resourcePath ) throws SlideException {
Iterator i;
UriHandler rUh = UriHandler.getUriHandler( resourcePath );
NodeRevisionDescriptor rNrd = null;
try {
NodeRevisionDescriptors rNrds = content.retrieve( sToken, resourcePath );
rNrd = content.retrieve( sToken, rNrds );
}
catch( ObjectNotFoundException e ) {}; // can be ignored here!
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, resourcePath, rNrd );
if( !(rRk instanceof DeltavCompliantUnmappedUrl) ) {
throw new PreconditionViolationException(
new ViolatedPrecondition(C_RESOURCE_MUST_BE_NULL, WebdavStatus.SC_CONFLICT), resourcePath);
}
if( !rUh.isWorkspaceUri() ) {
throw new PreconditionViolationException(
new ViolatedPrecondition(C_WORKSPACE_LOCATION_OK, WebdavStatus.SC_FORBIDDEN), resourcePath);
}
if( !rRk.isSupportedMethod(req.getMethod()) ) {
throw new MethodNotAllowedException( rRk );
}
// Set initial ws properties
String wsUri = String.valueOf(rUh);
NodeRevisionDescriptor wsNrd =
new NodeRevisionDescriptor(0);
i = pHelp.createInitialProperties(WorkspaceImpl.getInstance()).iterator();
while( i.hasNext() )
wsNrd.setProperty( (NodeProperty)i.next() );
// Set specific properties
wsNrd.setProperty(
new NodeProperty(P_WORKSPACE, pHelp.createHrefValue(wsUri)) );
wsNrd.setLastModified( new Date() ); //P_GETLASTMODIFIED
wsNrd.setContentLength( 0 ); // P_GETCONTENTLENGTH
wsNrd.setETag( PropertyHelper.computeEtag(wsUri, wsNrd) ); // P_GETETAG
if (!Configuration.useBinding(nsaToken.getUri(sToken, wsUri).getStore())) {
wsNrd.setName( rUh.getWorkspaceName() ); // P_DISPLAYNAME
}
wsNrd.setCreationDate( new Date() ); // P_CREATIONDATE
setCreationUser(wsNrd);
// Create the ws resource
SubjectNode wsNode = new SubjectNode();
structure.create( sToken, wsNode, wsUri );
content.create( sToken, wsUri, wsNrd, null ); // revisionContent = null
// Set status created
resp.setStatus( WebdavStatus.SC_CREATED );
}
/**
* Checkout a resource (for both: checkout-in-place and working-resource features).
* @param resourcePath the request URI
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param applyToVersion true, if the request body contained a DAV:apply-to-version element
* @return the URI of the created working resource, null if no resource was created
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkout( String resourcePath, boolean forkOk, boolean applyToVersion )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
return checkout(resourcePath, forkOk, applyToVersion, false);
}
/**
* Checkout a resource (for both: checkout-in-place and working-resource features).
* @param resourcePath the request URI
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param applyToVersion true, if the request body contained a DAV:apply-to-version element
* @param isAutoVersionCheckout true, if this is an implicit request due to auto-versioning
* @return the URI of the created working resource, null if no resource was created
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkout( String resourcePath, boolean forkOk, boolean applyToVersion, boolean isAutoVersionCheckout )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
UriHandler rUh = UriHandler.getUriHandler( resourcePath );
NodeRevisionDescriptors rNrds = content.retrieve( sToken, resourcePath );
NodeRevisionDescriptor rNrd = content.retrieve( sToken, rNrds );
if( rUh.isVersionUri() ) {
NodeRevisionContent rNrc = content.retrieve( sToken, rNrds, rNrd );
return checkout( rNrds, rNrd, rNrc, forkOk, null ); // autoUpdateUri=null
}
else {
return checkout( rNrds, rNrd, forkOk, applyToVersion, isAutoVersionCheckout);
}
}
/**
* Checkout a resource (for both: checkout-in-place and working-resource features).
* @param rNrds the revision descriptors instance
* @param rNrd the revision descriptor instance
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param applyToVersion true, if the request body contained a DAV:apply-to-version element
* @return the URI of the created working resource, null if no resource was created
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkout( NodeRevisionDescriptors rNrds,
NodeRevisionDescriptor rNrd, boolean forkOk, boolean applyToVersion )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
return checkout(rNrds, rNrd, forkOk, applyToVersion, false);
}
/**
* Checkout a resource (for both: checkout-in-place and working-resource features).
* Checkout a resource (for both: checkout-in-place and working-resource features).
* @param rNrds the revision descriptors instance
* @param rNrd the revision descriptor instance
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param applyToVersion true, if the request body contained a DAV:apply-to-version element
* @param isAutoVersionCheckout true, if this is an implicit request due to auto-versioning
* @return the URI of the created working resource, null if no resource was created
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkout( NodeRevisionDescriptors rNrds,
NodeRevisionDescriptor rNrd, boolean forkOk, boolean applyToVersion, boolean isAutoVersionCheckout )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
Iterator i;
String rUri = getUri( rNrds, rNrd );
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, rNrds, rNrd );
if( !rRk.isSupportedMethod(req.getMethod()) ) {
// check precondition C_MUST_BE_CHECKED_IN
if( rRk instanceof CheckedOut ) {
throw new PreconditionViolationException(new ViolatedPrecondition(C_MUST_BE_CHECKED_IN, WebdavStatus.SC_CONFLICT), rNrds.getUri());
}
throw new MethodNotAllowedException( rRk );
}
if( rRk instanceof CheckedInVersionControlled ) {
// get checked-in VR
NodeProperty cinProp = rNrd.getProperty( P_CHECKED_IN );
String cinHref = getElementValue((String)cinProp.getValue());
UriHandler cinUriHandler = UriHandler.getUriHandler(cinHref);
String cinhUri = cinUriHandler.getAssociatedHistoryUri();
NodeRevisionNumber cinNrn = new NodeRevisionNumber(cinUriHandler.getVersionName());
NodeRevisionDescriptors cinNrds = content.retrieve(sToken, cinhUri);
NodeRevisionDescriptor cinNrd = content.retrieve(sToken, cinNrds, cinNrn);
// working resource feature
if( applyToVersion ) {
NodeRevisionContent cinNrc = content.retrieve( sToken, cinNrds, cinNrd );
return checkout( cinNrds, cinNrd, cinNrc, forkOk, rUri ); // autoUpdateUri=rUri
}
ViolatedPrecondition violatedPrecondition = getCheckoutPreconditionViolation(cinNrds, cinNrd, forkOk);
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition, rNrds.getUri());
}
NodeRevisionDescriptors vhrNrds = content.retrieve(sToken, cinhUri);
// do the checkout
backupSpecificLiveProperties(rNrds, rNrd);
rNrd.removeProperty( cinProp );
rNrd.setProperty(
new NodeProperty(P_CHECKED_OUT, cinProp.getValue()) );
rNrd.setProperty(
new NodeProperty(P_PREDECESSOR_SET, cinProp.getValue()) );
NodeProperty property = cinNrd.getProperty(P_CHECKOUT_FORK);
if (property != null) {
rNrd.setProperty(property);
}
property = cinNrd.getProperty(P_CHECKIN_FORK);
if (property != null) {
rNrd.setProperty(property);
}
if (isAutoVersionCheckout) {
NodeLock writeLock = getWriteLock(readonlySlideToken(), rNrds);
if (writeLock != null) {
NodeProperty p =
new NodeProperty(I_CHECKIN_LOCKTOKEN,
writeLock.getLockId(),
NamespaceCache.SLIDE_URI);
p.setKind( NodeProperty.Kind.PROTECTED );
rNrd.setProperty( p );
}
}
// update checked-in VR's DAV:checkout-set property
PropertyHelper.addHrefToProperty(cinNrd, P_CHECKOUT_SET, rUri);
// Store changes
content.store( sToken, rNrds.getUri(), rNrd, null ); //revisionContent=null
content.store( sToken, cinNrds.getUri(), cinNrd, null );
return null;
}
else {
Domain.warn(
"Do not know how to checkout a '"+rRk+"' resource" );
resp.setStatus(WebdavStatus.SC_CONFLICT);
throw new WebdavException( WebdavStatus.SC_CONFLICT );
}
}
/**
* Checkout a resource (working-resource features only).
* @param rNrds the revision descriptors instance associated to the version being checked-out
* @param rNrd the revision descriptor instance associated to the version being checked-out
* @param rNrc the revision content instance associated to the version being checked-out
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param autoUpdateUri the URI of the VCR that will be updated when the WR will be checked-in
* @return the URI of the created working resource
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkout( NodeRevisionDescriptors rNrds, NodeRevisionDescriptor rNrd, NodeRevisionContent rNrc,
boolean forkOk, String autoUpdateUri )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
Iterator i;
Enumeration j;
String rUri = getUri( rNrds, rNrd );
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, rNrds, rNrd );
if( !rRk.isSupportedMethod(req.getMethod()) ) {
// check precondition C_MUST_BE_CHECKED_IN
if( rRk instanceof CheckedOut ) {
throw new PreconditionViolationException(new ViolatedPrecondition(C_MUST_BE_CHECKED_IN, WebdavStatus.SC_CONFLICT), rNrds.getUri());
}
throw new MethodNotAllowedException( rRk );
}
if( rRk instanceof Version ) {
UriHandler rUh = UriHandler.getUriHandler( rUri );
String vhUri = rUh.getAssociatedHistoryUri();
ViolatedPrecondition violatedPrecondition = getCheckoutPreconditionViolation(rNrds, rNrd, forkOk);
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition, rNrds.getUri());
}
NodeRevisionDescriptors vhrNrds = content.retrieve(sToken, vhUri);
// create the workingresource
UriHandler wrUh = UriHandler.createNextWorkingresourceUri( sToken, nsaToken, rUh );
String wrUri = String.valueOf( wrUh );
SubjectNode wrNode = new SubjectNode();
structure.create( sToken, wrNode, String.valueOf(wrUh) );
// set WR props
NodeRevisionDescriptor wrNrd = new NodeRevisionDescriptor();
i = pHelp.createInitialProperties(WorkingImpl.getInstance()).iterator();
while( i.hasNext() )
wrNrd.setProperty( (NodeProperty)i.next() );
// content.create( sToken, wrUri, wrNrd, rNrc );
// set specific live props
wrNrd.setProperty(
new NodeProperty(P_CHECKED_OUT, pHelp.createHrefValue(rUri)) );
wrNrd.setProperty(
new NodeProperty(P_PREDECESSOR_SET, pHelp.createHrefValue(rUri)) );
NodeProperty coutfProp = rNrd.getProperty(P_CHECKOUT_FORK);
if( coutfProp != null )
wrNrd.setProperty( coutfProp );
NodeProperty cinfProp = rNrd.getProperty(P_CHECKIN_FORK);
if( cinfProp != null )
wrNrd.setProperty( cinfProp );
wrNrd.setContentType(rNrd.getContentType()); // P_GETCONTENTTYPE
wrNrd.setContentLength( rNrd.getContentLength() ); // P_GETCONTENTLENGTH
wrNrd.setContentLanguage(rNrd.getContentLanguage()); // P_GETCONTENTLANGUAGE
wrNrd.setLastModified( new Date() ); //P_GETLASTMODIFIED
wrNrd.setCreationDate( new Date() ); // P_CREATIONDATE
setCreationUser(wrNrd);
wrNrd.setETag( PropertyHelper.computeEtag(wrUri, wrNrd) ); // P_GETETAG
// set auto-update
if( autoUpdateUri != null && autoUpdateUri.length() > 0 ) {
UriHandler autoUpdateUh = new UriHandler( autoUpdateUri );
wrNrd.setProperty(
new NodeProperty(P_AUTO_UPDATE, pHelp.createHrefValue(autoUpdateUri)) );
wrNrd.setName( autoUpdateUh.getName() );
}
else {
wrNrd.removeProperty( P_AUTO_UPDATE );
wrNrd.setName( rNrd.getName() );
}
// Copy dead properties VR -> WR
j = rNrd.enumerateProperties();
while( j.hasMoreElements() ) {
NodeProperty p = (NodeProperty)j.nextElement();
if( p.isLiveProperty() )
continue;
wrNrd.setProperty( p );
}
// update version's DAV:checkout-set property
PropertyHelper.addHrefToProperty(rNrd, P_CHECKOUT_SET, wrUri);
content.store( sToken, rNrds.getUri(), rNrd, null);
// store changes
content.create( sToken, wrUri, wrNrd, rNrc );
content.store( sToken, wrUri, wrNrd, null );
// Set status created
resp.setStatus( WebdavStatus.SC_CREATED );
return wrUri;
}
else {
Domain.warn(
"Do not know how to checkout a '"+rRk+"' resource" );
resp.setStatus(WebdavStatus.SC_CONFLICT);
throw new WebdavException( WebdavStatus.SC_CONFLICT );
}
}
/**
* Returns the ViolatedPrecondition if one of the precondition defined for
* the <code>CHECKOUT</code> methods has been violated, otherwise
* <code>null</code>.
*
* @param cinNrds the NodeRevisionDescriptors of the VR to checkout.
* @param cinNrd the NodeRevisionDescriptor of the VR to checkout.
* @param isForkOk indicates if <code><fork-ok></code> is set in
* the request content.
*
* @return the ViolatedPrecondition (if any).
*/
protected ViolatedPrecondition getCheckoutPreconditionViolation(NodeRevisionDescriptors cinNrds, NodeRevisionDescriptor cinNrd, boolean isForkOk) throws IllegalArgumentException, IOException, JDOMException, SlideException {
// use a non-blocking slide token.
SlideToken stok = readonlySlideToken();
ViolatedPrecondition violatedPrecondition = null;
NodeProperty checkoutForkProperty =cinNrd.getProperty(P_CHECKOUT_FORK);
if (checkoutForkProperty != null) {
Element checkoutForkElement = pHelp.parsePropertyValue(checkoutForkProperty.getValue().toString());
if (checkoutForkElement != null) {
// check if the version has successors
Enumeration successors = cinNrds.getSuccessors(cinNrd.getRevisionNumber());
if ( (successors != null) && successors.hasMoreElements()) {
// check precondition C_CHECKOUT_OF_VERSION_WITH_DESCENDANT_IS_FORBIDDEN
if (E_FORBIDDEN.equals(checkoutForkElement.getName())) {
return new ViolatedPrecondition(C_CHECKOUT_OF_VERSION_WITH_DESCENDANT_IS_FORBIDDEN, WebdavStatus.SC_FORBIDDEN);
}
// check precondition C_CHECKOUT_OF_VERSION_WITH_DESCENDANT_IS_DISCOURAGED
else if (E_DISCOURAGED.equals(checkoutForkElement.getName()) && !isForkOk) {
return new ViolatedPrecondition(C_CHECKOUT_OF_VERSION_WITH_DESCENDANT_IS_DISCOURAGED, WebdavStatus.SC_CONFLICT);
}
}
// check if the version is already checked out
PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(stok, nsaToken, sConf);
NodeProperty checkoutSetProp = propertyHelper.getProperty(P_CHECKOUT_SET, cinNrds, cinNrd, req.getContextPath(), null);
if( checkoutSetProp != null && checkoutSetProp.getValue() != null ) {
XMLValue checkoutSetValue = new XMLValue( checkoutSetProp.getValue().toString() );
if (checkoutSetValue.iterator().hasNext()) {
// check precondition C_CHECKOUT_OF_CHECKED_OUT_VERSION_IS_FORBIDDEN
if (E_FORBIDDEN.equals(checkoutForkElement.getName())) {
return new ViolatedPrecondition(C_CHECKOUT_OF_CHECKED_OUT_VERSION_IS_FORBIDDEN, WebdavStatus.SC_FORBIDDEN);
}
// check precondition C_CHECKOUT_OF_CHECKED_OUT_VERSION_IS_DISCOURAGED
else if (E_DISCOURAGED.equals(checkoutForkElement.getName()) && !isForkOk) {
return new ViolatedPrecondition(C_CHECKOUT_OF_CHECKED_OUT_VERSION_IS_DISCOURAGED, WebdavStatus.SC_CONFLICT);
}
}
}
}
}
return violatedPrecondition;
}
/**
* Uncheckout the specified resource.
*
* @param resourcePath the path of the resource to uncheckout.
*/
public void uncheckout(String resourcePath) throws SlideException, JDOMException, IOException, PreconditionViolationException {
NodeRevisionDescriptors rNrds = content.retrieve( sToken, resourcePath );
NodeRevisionDescriptor rNrd = content.retrieve( sToken, rNrds );
uncheckout( rNrds, rNrd);
}
/**
* Uncheckout the specified resource.
*
* @param rNrds the NodeRevisionDescriptors of the resource to uncheckout.
* @param rNrd the NodeRevisionDescriptor of the resource to uncheckout.
*/
public void uncheckout( NodeRevisionDescriptors rNrds, NodeRevisionDescriptor rNrd)
throws SlideException, JDOMException, IOException, PreconditionViolationException {
Iterator i;
String rUri = getUri( rNrds, rNrd );
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, rNrds, rNrd );
// check precondition C_MUST_BE_CHECKED_OUT_VERSION_CONTROLLED_RESOURCE
if ( ! (rRk instanceof CheckedOutVersionControlled) ) {
throw new PreconditionViolationException(new ViolatedPrecondition(C_MUST_BE_CHECKED_OUT_VERSION_CONTROLLED_RESOURCE,
WebdavStatus.SC_CONFLICT),
rNrds.getUri());
}
if( !rRk.isSupportedMethod(req.getMethod()) ) {
throw new MethodNotAllowedException( rRk );
}
// get checked-out VR
NodeProperty coutProp = rNrd.getProperty( P_CHECKED_OUT );
String coutHref = getElementValue((String)coutProp.getValue());
UriHandler coutUriHandler = UriHandler.getUriHandler(coutHref);
String coutUri = coutUriHandler.getAssociatedHistoryUri();
NodeRevisionNumber coutNrn = new NodeRevisionNumber(coutUriHandler.getVersionName());
NodeRevisionDescriptors coutNrds = content.retrieve(sToken, coutUri);
NodeRevisionDescriptor coutNrd = content.retrieve(sToken, coutNrds, coutNrn);
NodeRevisionContent coutNrc = content.retrieve( sToken, coutNrds, coutNrd );
// update its DAV:checkout-set property
if (!PropertyHelper.removeHrefFromProperty(coutNrd, P_CHECKOUT_SET, rUri)) {
StringBuffer b = new StringBuffer("Invalid path");
PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(sToken, nsaToken, sConf);
NodeProperty checkoutSetProp = propertyHelper.getProperty(P_CHECKOUT_SET, coutNrds, coutNrd, req.getContextPath(), null);
if( checkoutSetProp != null && checkoutSetProp.getValue() != null ) {
XMLValue checkoutSetValue = new XMLValue( checkoutSetProp.getValue().toString() );
if (checkoutSetValue.iterator().hasNext()) {
b.append(" - please use "+checkoutSetValue.getTextValue()+" instead");
}
}
throw new ConflictException(
rUri, new SlideException(b.toString()));
}
content.store(sToken, coutNrds.getUri(), coutNrd, null);
// update VCR to previous VR
rNrd.removeProperty( P_CHECKED_OUT );
update( rNrds, rNrd, coutNrds, coutNrd );
// restore some live properties
restoreSpecificLiveProperties( rNrds, rNrd );
// Store changes
content.store( sToken, rNrds.getUri(), rNrd, null ); // revisionContent=null
// remove the hidden 0.0 revision
content.remove( sToken, rNrds.getUri(), NodeRevisionNumber.HIDDEN_0_0 );
}
/**
* Checkin the specified resource (for both: checkout-in-place and working-resource features).
* @param resourcePath the request URI
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param keepCheckedOut true, if the request body contained a DAV:keep-checked-out element
* @param autoVersion true, if the checkin is due to auto-versioning
* @return the URI of the created version resource
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkin( String resourcePath, boolean forkOk, boolean keepCheckedOut, boolean autoVersion )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
NodeRevisionDescriptors rNrds = content.retrieve( sToken, resourcePath );
NodeRevisionDescriptor rNrd = content.retrieve( sToken, rNrds );
return checkin( rNrds, rNrd, forkOk, keepCheckedOut, autoVersion );
}
/**
* Checkin the specified resource (for both: checkout-in-place and working-resource features).
* @param rNrds the revision descriptors instance
* @param rNrd the revision descriptor instance
* @param forkOk true, if the request body contained a DAV:fork-ok element
* @param keepCheckedOut true, if the request body contained a DAV:keep-checked-out element
* @param autoVersion true, if the checkin is due to auto-versioning
* @return the URI of the created version resource
* @throws SlideException
* @throws JDOMException
* @throws IOException
* @throws PreconditionViolatedException
*/
public String checkin( NodeRevisionDescriptors rNrds, NodeRevisionDescriptor rNrd,
boolean forkOk, boolean keepCheckedOut, boolean autoVersion )
throws SlideException, JDOMException, IOException, PreconditionViolationException {
Iterator i;
Enumeration j;
String rUri = getUri( rNrds, rNrd );
ResourceKind rRk = AbstractResourceKind.determineResourceKind( nsaToken, rNrds, rNrd );
if( !rRk.isSupportedMethod(req.getMethod()) ) {
// check precondition C_MUST_BE_CHECKED_OUT
if( (rRk instanceof CheckedInVersionControlled) ) {
throw new PreconditionViolationException(
new ViolatedPrecondition(C_MUST_BE_CHECKED_OUT, WebdavStatus.SC_CONFLICT), rUri);
}
throw new MethodNotAllowedException( rRk );
}
if( rRk instanceof CheckedOutVersionControlled || rRk instanceof Working ) {
boolean isWorkingResource = (rRk instanceof Working);
NodeProperty coutProp = rNrd.getProperty( P_CHECKED_OUT );
NodeProperty predSetProp = rNrd.getProperty( P_PREDECESSOR_SET );
NodeProperty autoUpdProp = rNrd.getProperty( P_AUTO_UPDATE );
// prepare auto-update
NodeRevisionDescriptors autoUpdNrds = null;
NodeRevisionDescriptor autoUpdNrd = null;
if( autoUpdProp != null ) {
Element autoUpdElm = pHelp.parsePropertyValue( (String)autoUpdProp.getValue() );
String autoUpdUri = autoUpdElm.getTextTrim();
autoUpdNrds = content.retrieve( sToken, autoUpdUri );
autoUpdNrd = content.retrieve( sToken, autoUpdNrds );
}
// Retrieve VHR
Element coutElm = pHelp.parsePropertyValue( (String)coutProp.getValue() );
String vrUriOld = coutElm.getTextTrim();
UriHandler vrUhOld = UriHandler.getUriHandler( vrUriOld );
NodeRevisionNumber vrNrnOld = new NodeRevisionNumber( vrUhOld.getVersionName() );
String vhrUri = vrUhOld.getAssociatedHistoryUri();
NodeRevisionDescriptors vhrNrds = content.retrieve( sToken, vhrUri );
NodeRevisionDescriptor vhrNrd = content.retrieve( sToken, vhrNrds ); //vhrUri
NodeProperty vSetProp = vhrNrd.getProperty( P_VERSION_SET );
// Retrieve old VR
NodeRevisionDescriptor vrNrdOld =
content.retrieve( sToken, vhrNrds, vrNrnOld ); // vrUriOld
// update the old VR's DAV:checkout-set property
if (!PropertyHelper.removeHrefFromProperty(vrNrdOld, P_CHECKOUT_SET, rUri)) {
StringBuffer b = new StringBuffer("Invalid path");
PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(sToken, nsaToken, sConf);
NodeProperty checkoutSetProp = propertyHelper.getProperty(P_CHECKOUT_SET, vhrNrds, vrNrdOld, req.getContextPath(), null);
if( checkoutSetProp != null && checkoutSetProp.getValue() != null ) {
XMLValue checkoutSetValue = new XMLValue( checkoutSetProp.getValue().toString() );
if (checkoutSetValue.iterator().hasNext()) {
b.append(" - please use "+checkoutSetValue.getTextValue()+" instead");
}
}
throw new ConflictException(
rUri, new SlideException(b.toString()));
}
content.store(sToken, vhrNrds.getUri(), vrNrdOld, null);
// check preconditions
ViolatedPrecondition violatedPrecondition =
getCheckinPreconditionViolation( predSetProp, vhrNrds, forkOk, autoUpdNrd );
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition, rUri);
}
// check forking
String forkBranch = getForkBranch(predSetProp, vhrNrds, forkOk);
NodeRevisionDescriptor vrNrdNew = null;
if (forkBranch != null) {
// Create a new branch
NodeRevisionNumber branchedRevisionNumber =
content.fork(sToken, vhrNrds.getUri(), forkBranch, vrNrdOld);
vhrNrds = content.retrieve( sToken, vhrUri );
vrNrdNew = content.retrieve(sToken, vhrNrds, branchedRevisionNumber);
vrNrdNew.setContentLength(rNrd.getContentLength());
}
else {
// Create new VR in the MAIN branch
vrNrdNew = new NodeRevisionDescriptor( rNrd.getContentLength() );
}
i = pHelp.createInitialProperties(VersionImpl.getInstance()).iterator();
while( i.hasNext() )
vrNrdNew.setProperty( (NodeProperty)i.next() );
// Copy dead properties VCR --> VR-new
j = rNrd.enumerateProperties();
while( j.hasMoreElements() ) {
NodeProperty p = (NodeProperty)j.nextElement();
if( p.isLiveProperty() )
continue;
if( !vrNrdNew.exists(p.getName()) )
vrNrdNew.setProperty( p );
}
// Copy specific live properties VCR/WR -> VR
vrNrdNew.setContentType(rNrd.getContentType()); // P_GETCONTENTTYPE
vrNrdNew.setContentLength(rNrd.getContentLength()); // P_GETCONTENTLENGTH
vrNrdNew.setContentLanguage( rNrd.getContentLanguage() ); // P_GETCONTENTLANGUAGE
String comment = (autoVersion ? "CREATED BY AUTO-VERSIONING. " : "");
if( rNrd.exists(P_COMMENT) )
comment += (String)rNrd.getProperty(P_COMMENT).getValue();
vrNrdNew.setProperty(
new NodeProperty(P_COMMENT, comment) );
vrNrdNew.setProperty( rNrd.getProperty(P_CHECKOUT_FORK) );
vrNrdNew.setProperty( rNrd.getProperty(P_CHECKIN_FORK) );
NodeRevisionContent rNrc = content.retrieve( sToken, rNrds, rNrd );
if (forkBranch != null) {
content.store(sToken, vhrUri, vrNrdNew, rNrc);
}
else {
String branch = vrNrdOld.getBranchName();
content.create( sToken, vhrUri, branch, vrNrdNew, rNrc );
}
// create new VR node
String vrUriNew = vhrUri+"/"+vrNrdNew.getRevisionNumber().toString();
UriHandler vrUhNew = UriHandler.getUriHandler( vrUriNew );
SubjectNode vrNodeNew = new SubjectNode();
structure.create( sToken, vrNodeNew, vrUriNew );
// set specific properties
if( keepCheckedOut ) {
rNrd.setProperty(
new NodeProperty(P_CHECKED_OUT, pHelp.createHrefValue(vrUriNew)) );
rNrd.setProperty(
new NodeProperty(P_PREDECESSOR_SET, "") );
PropertyHelper.addHrefToProperty(rNrd, P_PREDECESSOR_SET, vrUriNew);
PropertyHelper.addHrefToProperty(vrNrdNew, P_CHECKOUT_SET, rUri);
}
else {
if( !isWorkingResource ) {
rNrd.removeProperty( coutProp );
rNrd.setProperty(
new NodeProperty(P_CHECKED_IN, pHelp.createHrefValue(vrUriNew)) );
rNrd.removeProperty( I_CHECKIN_LOCKTOKEN , NamespaceCache.SLIDE_URI);
// retry with default (DAV:) namespace which was the
// former namespace of this property
rNrd.removeProperty( I_CHECKIN_LOCKTOKEN );
rNrd.removeProperty(P_PREDECESSOR_SET);
rNrd.removeProperty(P_CHECKOUT_FORK);
rNrd.removeProperty(P_CHECKIN_FORK);
}
}
vhrNrd.setLastModified( new Date() ); // P_GETLASTMODIFIED
vhrNrd.setProperty( new NodeProperty(
P_VERSION_SET, ((String)vSetProp.getValue())+pHelp.createHrefValue(vrUriNew)) );
vrNrdNew.setName( rNrd.getName() ); // P_DISPLAYNAME
vrNrdNew.setCreationDate( new Date() ); // P_CREATIONDATE
vrNrdNew.setLastModified( new Date() ); // P_GETLASTMODIFIED
vrNrdNew.setETag( PropertyHelper.computeEtag(vrUriNew, vrNrdNew) ); // P_GETETAG
vrNrdNew.setProperty(
new NodeProperty(P_VERSION_NAME, vrUhNew.getVersionName()) );
vrNrdNew.setProperty(
new NodeProperty(P_PREDECESSOR_SET, predSetProp.getValue()) );
// Store changes
if( keepCheckedOut || !isWorkingResource ) {
content.store( sToken, rUri, rNrd, null ); //revisionContent=null
try {
// remove the hidden 0.0 revision and create new one if keepCheckedOut
content.remove( sToken, rUri, NodeRevisionNumber.HIDDEN_0_0 );
}
catch( RevisionDescriptorNotFoundException x ) {
// the implicit CHECKOUT from COPY (auto-versioning) does not create a
// backup descriptor.
Domain.info( "Checkin: no backup descriptor found at "+rUri );
}
if( keepCheckedOut )
backupSpecificLiveProperties( rNrds, rNrd );
}
else {
// remove the WR
macro.delete( sToken, rUri );
}
content.store( sToken, vhrUri, vhrNrd, null ); //revisionContent=null
content.store( sToken, vhrUri, vrNrdNew, null ); //revisionContent=null
// auto-update
if( autoUpdNrd != null ) {
update( autoUpdNrds, autoUpdNrd, vhrNrds, vrNrdNew );
}
// Set status created
resp.setStatus( WebdavStatus.SC_CREATED );
return vrUriNew;
}
else {
Domain.warn(
"Do not know how to checkout a '"+rRk+"' resource" );
resp.setStatus(WebdavStatus.SC_CONFLICT);
return null;
}
}
private void setCreationUser(NodeRevisionDescriptor nrd) throws ServiceAccessException, ObjectNotFoundException {
// Set the creation user
String creationUser = ((SubjectNode)nsaToken.getSecurityHelper().getPrincipal(sToken)).getPath().lastSegment();
nrd.setCreationUser(creationUser);
nrd.setOwner(creationUser);
}
/**
* Returns the ViolatedPrecondition if one of the precondition defined for
* the <code>CHECKIN</code> methods has been violated, otherwise
* <code>null</code>.
*
* @param predSetProp the <code>predecessor-set</code> NodeProperty
* of the VCR to checkin.
* @param vhrNrds the NodeRevisionDescriptors of the associated VHR.
* @param isForkOk indicates if <code><fork-ok></code> is set in
* the request content.
* @param autoUpdNrd the NodeRevisionDescriptor of the VCR referenced via auto-update
* if not null, indicates that a working resource is being checked-in
* for which the auto-update property was set
*
* @return the ViolatedPrecondition (if any).
*/
protected ViolatedPrecondition getCheckinPreconditionViolation(NodeProperty predSetProp, NodeRevisionDescriptors vhrNrds, boolean isForkOk, NodeRevisionDescriptor autoUpdNrd ) throws LinkedObjectNotFoundException, ServiceAccessException, ObjectLockedException, RevisionDescriptorNotFoundException, JDOMException, IllegalArgumentException, ObjectNotFoundException, AccessDeniedException, IOException {
// use a non-blocking slide token.
SlideToken stok = readonlySlideToken();
ViolatedPrecondition violatedPrecondition = null;
if ( (predSetProp != null) && (predSetProp.getValue() != null) ) {
XMLValue predecessors = new XMLValue( (String)predSetProp.getValue() );
Iterator iterator = predecessors.iterator();
while (iterator.hasNext()) {
String href = ((Element)iterator.next()).getTextTrim();
if (href != null) {
UriHandler predecessorUriHandler = UriHandler.getUriHandler( href);
// check precondition C_VERSION_HISTORY_IS_TREE
if ( !predecessorUriHandler.isVersionUri() ||
!vhrNrds.getUri().equals(predecessorUriHandler.getAssociatedHistoryUri()) ) {
return new ViolatedPrecondition(C_VERSION_HISTORY_IS_TREE, WebdavStatus.SC_FORBIDDEN);
}
// check precondition C_CHECKIN_FORK_FORBIDDEN
NodeRevisionNumber predecessorNrn = new NodeRevisionNumber(predecessorUriHandler.getVersionName());
NodeRevisionDescriptor predecessorNrd = content.retrieve(stok,
vhrNrds,
predecessorNrn);
NodeProperty predecessorCheckinForkProperty = predecessorNrd.getProperty(P_CHECKIN_FORK);
if (predecessorCheckinForkProperty != null) {
Enumeration predecessorSuccessors = vhrNrds.getSuccessors(predecessorNrn);
if ( (predecessorSuccessors != null) &&
(predecessorSuccessors.hasMoreElements()) &&
(predecessorCheckinForkProperty.getValue() != null) ) {
String checkinFork = getElementName(predecessorCheckinForkProperty.getValue().toString());
if (E_FORBIDDEN.equals(checkinFork)) {
return new ViolatedPrecondition(C_CHECKIN_FORK_FORBIDDEN, WebdavStatus.SC_FORBIDDEN);
}
// check precondition C_CHECKIN_FORK_DISCOURAGED
else if (E_DISCOURAGED.equals(checkinFork) && !isForkOk ) {
return new ViolatedPrecondition(C_CHECKIN_FORK_DISCOURAGED, WebdavStatus.SC_CONFLICT);
}
}
}
// check precondition C_NO_OVERWRITE_BY_AUTO_UPDATE
if( autoUpdNrd != null ) {
NodeProperty cinProp = autoUpdNrd.getProperty( P_CHECKED_IN );
if( cinProp != null ) {
Element cinHrefElm = pHelp.parsePropertyValue( (String)cinProp.getValue() );
UriHandler cinUh = new UriHandler( cinHrefElm.getTextTrim() );
NodeRevisionNumber cinNrn = new NodeRevisionNumber( cinUh.getVersionName() );
if( !vhrNrds.getUri().equals(cinUh.getAssociatedHistoryUri()) ) {
// violation
return new ViolatedPrecondition(C_NO_OVERWRITE_BY_AUTO_UPDATE, WebdavStatus.SC_CONFLICT);
}
if( !vhrNrds.isAncestorDescendant(cinNrn, predecessorNrn) ) {
// violation
return new ViolatedPrecondition(C_NO_OVERWRITE_BY_AUTO_UPDATE, WebdavStatus.SC_CONFLICT);
}
}
}
}
}
}
return violatedPrecondition;
}
/**
* Returns the ViolatedPrecondition if one of the precondition defined for
* the <code>CHECKIN</code> methods has been violated, otherwise
* <code>null</code>.
*
* @param predSetProp the <code>predecessor-set</code> NodeProperty
* of the VCR to checkin.
* @param vhrNrds the NodeRevisionDescriptors of the associated VHR.
* @param isForkOk indicates if <code><fork-ok></code> is set in
* the request content.
*
* @return the violated precondition.
*/
protected String getForkBranch(NodeProperty predSetProp, NodeRevisionDescriptors vhrNrds, boolean isForkOk) throws LinkedObjectNotFoundException, ServiceAccessException, ObjectLockedException, RevisionDescriptorNotFoundException, JDOMException, IllegalArgumentException, ObjectNotFoundException, AccessDeniedException, IOException {
String forkBranch = null;
if ( (predSetProp != null) && (predSetProp.getValue() != null) ) {
XMLValue predecessors = new XMLValue( (String)predSetProp.getValue() );
Iterator iterator = predecessors.iterator();
if (iterator.hasNext()) {
String href = ((Element)iterator.next()).getTextTrim();
if (href != null) {
UriHandler predecessorUriHandler = UriHandler.getUriHandler( href);
NodeRevisionNumber predecessorNrn = new NodeRevisionNumber(predecessorUriHandler.getVersionName());
NodeRevisionDescriptor predecessorNrd = content.retrieve(sToken,
vhrNrds,
predecessorNrn);
NodeProperty predecessorCheckinForkProperty = predecessorNrd.getProperty(P_CHECKIN_FORK);
if (predecessorCheckinForkProperty != null) {
Enumeration predecessorSuccessors = vhrNrds.getSuccessors(predecessorNrn);
if ( (predecessorSuccessors != null) &&
predecessorSuccessors.hasMoreElements() ) {
forkBranch = "branch_" + predecessorNrn.toString();
}
}
}
}
}
return forkBranch;
}
/**
* If the resource described by the given <code>resourceUri</code> is a
* VCR this method returns the URI of the associated VR,
* otherwise <code>null</code>
*
* @param resourceUri the URI of the resource.
*
* @return the URI of the associated VR.
*
* @throws SlideException
*/
public String getUriOfAssociatedVR(String resourceUri) throws SlideException {
return getUriOfAssociatedVR(nsaToken, sToken, content, resourceUri);
}
/**
* Returns the URI of the resource defined by the given NodeRevisionDescriptor(s).
*
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource.
*
* @return the URI of the resource.
*
* @throws SlideException
*/
public String getUri(NodeRevisionDescriptors revisionDescriptors,
NodeRevisionDescriptor revisionDescriptor) throws SlideException {
return getUri(nsaToken, sToken, content, revisionDescriptors, revisionDescriptor);
}
/**
* Updates the VCR specified by <code>vcrPath</code> with the properties
* and the content of the VR specified by the given <code>vrPath</code>.
*
* @param vcrUri the URI of the VCR to update.
* @param vrUri the URI of the VR from which to update.
*
* @throws SlideException
*/
public void update(String vcrUri, String vrUri) throws SlideException {
NodeRevisionDescriptors vcrRevisionDescriptors = content.retrieve( sToken,vcrUri );
NodeRevisionDescriptor vcrRevisionDescriptor = content.retrieve( sToken, vcrRevisionDescriptors);
NodeRevisionDescriptors vrRevisionDescriptors = content.retrieve( sToken, vrUri );
NodeRevisionDescriptor vrRevisionDescriptor = content.retrieve( sToken, vrRevisionDescriptors); // vrUri
update(vcrRevisionDescriptors, vcrRevisionDescriptor, vrRevisionDescriptors, vrRevisionDescriptor);
}
/**
* Updates the VCR specified by <code>vcrRevisionDescriptors</code> and
* <code>vcrRevisionDescriptors</code> with the properties and the content
* of the VR specified by the given <code>vrRevisionDescriptors</code>
* and <code>vrRevisionDescriptor</code>.
*
* @pre (AbstractResourceKind.determineResourceKind(vrRevisionDescriptor) instanceof Version)
*
* @param vcrRevisionDescriptors the NodeRevisionDescriptors of the VCR to update.
* @param vcrRevisionDescriptor the NodeRevisionDescriptor of the VCR to update.
* @param vrRevisionDescriptors the NodeRevisionDescriptors of the VR from
* which to update.
* @param vrRevisionDescriptor the NodeRevisionDescriptor of the VR from
* which to update.
*
* @throws SlideException
*/
public void update(NodeRevisionDescriptors vcrRevisionDescriptors, NodeRevisionDescriptor vcrRevisionDescriptor, NodeRevisionDescriptors vrRevisionDescriptors, NodeRevisionDescriptor vrRevisionDescriptor) throws SlideException {
// ***************************************
// TODO:
// 1) Preconditions; Problem: not specified formally.
// ***************************************
ResourceKind vrResourceKind = VersionImpl.getInstance();
ResourceKind cinvcrResourceKind = CheckedInVersionControlledImpl.getInstance();
String vcrUri = getUri(vcrRevisionDescriptors, vcrRevisionDescriptor);
Enumeration propertyEnum;
// Remove all VCR dead properties first
propertyEnum = vcrRevisionDescriptor.enumerateProperties();
while (propertyEnum.hasMoreElements()) {
NodeProperty p = (NodeProperty)propertyEnum.nextElement();
if( p.isLiveProperty() )
continue;
vcrRevisionDescriptor.removeProperty(p);
}
// Copy all dead properties of VR to VCR
propertyEnum = vrRevisionDescriptor.enumerateProperties();
while (propertyEnum.hasMoreElements()) {
NodeProperty p = (NodeProperty)propertyEnum.nextElement();
if( !p.isLiveProperty() ) {
vcrRevisionDescriptor.setProperty(p);
}
}
// update specific live properties
String vrUri = getUri(vrRevisionDescriptors, vrRevisionDescriptor);
vcrRevisionDescriptor.setProperty(new NodeProperty(P_CHECKED_IN,
pHelp.createHrefValue(vrUri)) );
vcrRevisionDescriptor.setLastModified(new Date());
vcrRevisionDescriptor.setContentLength(vrRevisionDescriptor.getContentLength());
vcrRevisionDescriptor.setContentType(vrRevisionDescriptor.getContentType());
vcrRevisionDescriptor.setContentLanguage(vrRevisionDescriptor.getContentLanguage());
vcrRevisionDescriptor.setETag(PropertyHelper.computeEtag(vcrRevisionDescriptors.getUri(), vcrRevisionDescriptor) );
// set workspace
setWorkspaceProperty( vcrUri, vcrRevisionDescriptor );
// get the VR content
NodeRevisionContent vrContent = content.retrieve(sToken, vrRevisionDescriptors, vrRevisionDescriptor);
// store the content
content.store( sToken, vcrUri, vcrRevisionDescriptor, vrContent );
}
/**
* Backups specific live properties of the given <code>revisionDescriptor</code>
* at the 0.0 revision of the NodeRevisionDescriptors of the VCR. A good idea seems to
* be to backup the non-protected live properties.
*
* @param rNrds the NodeRevisionDescriptors of the
* VCR to backup.
* @param rNrd the NodeRevisionDescriptor of the
* VCR to backup.
*
* @throws SlideException
*/
protected void backupSpecificLiveProperties(NodeRevisionDescriptors rNrds, NodeRevisionDescriptor rNrd) throws SlideException {
NodeRevisionDescriptor backupNrd =
new NodeRevisionDescriptor( NodeRevisionNumber.HIDDEN_0_0, "backup", new Vector(), new Hashtable() );
NodeProperty p;
p = rNrd.getProperty( P_AUTO_VERSION );
if( p != null )
backupNrd.setProperty( p );
p = rNrd.getProperty( P_COMMENT );
if( p != null )
backupNrd.setProperty( p );
p = rNrd.getProperty( P_DISPLAYNAME );
if( p != null )
backupNrd.setProperty( p );
p = rNrd.getProperty( P_CREATOR_DISPLAYNAME );
if( p != null )
backupNrd.setProperty( p );
try {
content.retrieve( sToken, rNrds, NodeRevisionNumber.HIDDEN_0_0 );
content.store( sToken, rNrds.getUri(), backupNrd, null );
}
catch (RevisionDescriptorNotFoundException e) {
content.create( sToken, rNrds.getUri(), null, backupNrd, null ); // branch=null, revisionContent=null
}
}
/**
* Restores specific live properties of the given <code>revisionDescriptor</code>
* from the hidden 0.0 revision of the NodeRevisionDescriptors of the VCR.
*
* @param rNrds the NodeRevisionDescriptors of the
* VCR to restore.
* @param rNrd the NodeRevisionDescriptor of the
* VCR to restore.
*
* @throws SlideException
*/
protected void restoreSpecificLiveProperties(NodeRevisionDescriptors rNrds, NodeRevisionDescriptor rNrd) throws SlideException {
NodeRevisionDescriptor backupNrd =
content.retrieve(sToken, rNrds, NodeRevisionNumber.HIDDEN_0_0);
NodeProperty p;
p = backupNrd.getProperty( P_AUTO_VERSION );
if( p != null )
rNrd.setProperty( p );
p = backupNrd.getProperty( P_COMMENT );
if( p != null )
rNrd.setProperty( p );
p = backupNrd.getProperty( P_DISPLAYNAME );
if( p != null )
rNrd.setProperty( p );
p = backupNrd.getProperty( P_CREATOR_DISPLAYNAME );
if( p != null )
rNrd.setProperty( p );
content.store(sToken, rNrds.getUri(), rNrd, null);
}
/**
* Returns the name of the element that represents the value of the
* <code><auto-version></code> property of the given
* <code>revisionDescriptor</code> (e.g. <code>checkout-checkin</code>).
*
* @param revisionDescriptor the NodeRevisionDescriptor for which to
* return the value of the
* <code><auto-version></code> property.
*
* @return the value of the <code><auto-version></code> property
* of the given <code>revisionDescriptor</code>.
*/
public String getAutoVersionElementName(NodeRevisionDescriptor revisionDescriptor) {
String autoVersionValue = null;
NodeProperty autoVersionProperty = revisionDescriptor.getProperty(DeltavConstants.P_AUTO_VERSION);
if ( (autoVersionProperty != null) && (autoVersionProperty.getValue() != null) ) {
if (autoVersionProperty.getValue().toString().length() > 0) {
autoVersionValue = getElementName(autoVersionProperty.getValue().toString());
}
else {
autoVersionValue = "";
}
}
return autoVersionValue;
}
/**
* Indicates if the (VCR) reource be checked out prior to modifying it
* depending on its <code><auto-version></code> property.
*
* @param resourceUri the URI of the resource.
*
* @return <code>true</code> if the resource must be checked out prior to
* modifying it.
*
* @throws SlideException
*/
public boolean mustCheckoutAutoVersionedVCR(String resourceUri) throws SlideException {
NodeRevisionDescriptors vcrRevisionDescriptors = content.retrieve(sToken,resourceUri);
NodeRevisionDescriptor vcrRevisionDescriptor = content.retrieve( sToken, vcrRevisionDescriptors);
return mustCheckoutAutoVersionedVCR(vcrRevisionDescriptors, vcrRevisionDescriptor);
}
/**
* Indicates if the (VCR) reource be checked out prior to modifying it
* depending on its <code><auto-version></code> property.
*
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource.
*
* @return <code>true</code> if the resource must be checked out prior to
* modifying it.
*/
public boolean mustCheckoutAutoVersionedVCR(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor) {
String autoVersionValue = getAutoVersionElementName(revisionDescriptor);
return ( (autoVersionValue != null) &&
( DeltavConstants.E_CHECKOUT_CHECKIN.equals(autoVersionValue) ||
DeltavConstants.E_CHECKOUT_UNLOCKED_CHECKIN.equals(autoVersionValue) ||
DeltavConstants.E_CHECKOUT.equals(autoVersionValue) ||
DeltavConstants.E_LOCKED_CHECKOUT.equals(autoVersionValue) ) );
}
/**
* Indicates if the (VCR) reource be checked in after modifying it
* depending on its <code><auto-version></code> property.
*
* @param slideToken the SlideToken to use.
* @param resourceUri the URI of the resource.
*
* @return <code>true</code> if the resource must be checked in after
* modifying it.
*
* @throws SlideException
*/
public boolean mustCheckinAutoVersionedVCR(SlideToken slideToken, String resourceUri) throws SlideException {
NodeRevisionDescriptors vcrRevisionDescriptors = content.retrieve(sToken,resourceUri);
NodeRevisionDescriptor vcrRevisionDescriptor = content.retrieve( sToken, vcrRevisionDescriptors);
return mustCheckinAutoVersionedVCR(slideToken, vcrRevisionDescriptors, vcrRevisionDescriptor);
}
/**
* Indicates if the (VCR) reource be checked in after modifying it
* depending on its <code><auto-version></code> property.
*
* @param slideToken the SlideToken to use.
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource.
*
* @return <code>true</code> if the resource must be checked in after
* modifying it.
*/
public boolean mustCheckinAutoVersionedVCR(SlideToken slideToken, NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
boolean checkin = false;
String autoVersionValue = getAutoVersionElementName(revisionDescriptor);
if (autoVersionValue != null) {
checkin = DeltavConstants.E_CHECKOUT_CHECKIN.equals(autoVersionValue);
if ( !checkin && DeltavConstants.E_CHECKOUT_UNLOCKED_CHECKIN.equals(autoVersionValue)) {
checkin = ! isWriteLocked(slideToken, revisionDescriptors);
}
}
return checkin;
}
/**
* Indicates if the resource specified by the given NodeRevisionDescriptors
* is write locked. Reads all URLs in read only mode
*
* @param slideToken the SlideToken to use.
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
*
* @return <code>true</code> if the resource is write locked.
*/
public boolean isWriteLocked(SlideToken slideToken, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException {
return (getWriteLock(readonlySlideToken(), revisionDescriptors) != null);
}
/**
* Returns the write lock of the resource specified by the given
* NodeRevisionDescriptors if one exists, otherwise <code>null</code>.
*
* @param slideToken the SlideToken to use.
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
*
* @return the write lock of the resource.
*/
private NodeLock getWriteLock(SlideToken slideToken, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException {
NodeLock writeLock = null;
try {
Enumeration lockEnum = lock.enumerateLocks(slideToken, revisionDescriptors.getUri());
if (lockEnum != null && lockEnum.hasMoreElements()) {
// there are no other types of locks beside write locks ... so take the first one if there
writeLock = (NodeLock)lockEnum.nextElement();
}
}
catch (ObjectNotFoundException e) {}
catch (LockTokenNotFoundException e) {}
return writeLock;
}
/**
* Expects a String containing an XML Element like
* <code><example>value</example></code>
* and returns the text <code>value</code> of this element.
* If the String is not of the expected format, <code>null</code> is returned.
*
* @pre true
* @post true
*
* @param elementString the String containing an XML Element like
* <code><example>value</example></code>.
*
* @return the text value of the Element given by the XML String.
*/
public static String getElementValue(String elementString) {
String text = null;
Element element = getElement(elementString);
if (element != null) {
text = element.getText();
}
return text;
}
/**
* Expects a String containing an XML Element and returns the
* <code>name</code> of this element.
* If the String is not of the expected format, <code>null</code> is returned.
*
* @pre true
* @post true
*
* @param elementString the String containing an XML Element like
* <code><example>value</example></code>.
*
* @return the name of the Element given by the XML String.
*/
public static String getElementName(String elementString) {
String name = null;
Element element = getElement(elementString);
if (element != null) {
name = element.getName();
}
return name;
}
/**
* Expects a String containing at least one XML Element and returns this Element.
* If the String is not of the expected format, <code>null</code> is returned.
*
* @pre true
* @post true
*
* @param elementString the String containing an XML Element.
*
* @return the Element given by the XML String.
*/
public static Element getElement(String elementString) {
Element element = null;
try {
Document document = getSAXBuilder().build(new StringReader(elementString));
element = document.getRootElement();
}
catch (JDOMException e) {}
catch (Exception e) {
e.printStackTrace();
}
return element;
}
/**
* Returns the SAXBuilder used by various methods to create JDOM Documents.
*
* @return the SAXBuilder used to create JDOM Documents.
*/
protected static SAXBuilder getSAXBuilder() {
if (saxBuilder == null) {
saxBuilder = new SAXBuilder();
}
return saxBuilder;
}
/**
* Returns slide Uri determinating the NodeRevisionDescriptors and
* NodeRevisionDescriptor associated with the given <code>resourcePath</code>.
* If the given <code>label</code> is not <code>null</code>, and the
* <code>resourcePath</code> identifies a VCR, the revision with that label
* of the associated history is returned.
*
* @param nsaToken the NamespaceAccessToken to use.
* @param sToken the SlideToken to use.
* @param content the Content helper to use.
* @param resourcePath the path of the resource for which to retrieve
* the SlideResource.
* @param label the label of the revision to return. May be
* <code>null</code>.
*
* @return slide Uri determinating the NodeRevisionDescriptors and
* NodeRevisionDescriptor associated with the given
* <code>resourcePath</code>.
*
* @throws SlideException
* @throws LabeledRevisionNotFoundException if no revision with the specified
* label was found.
*/
private static String getLabeledResourceUri(NamespaceAccessToken nsaToken, SlideToken sToken, Content content, String resourcePath, String label) throws SlideException, LabeledRevisionNotFoundException {
NodeRevisionDescriptors revisionDescriptors =
content.retrieve( sToken, resourcePath );
NodeRevisionDescriptor revisionDescriptor =
content.retrieve( sToken, revisionDescriptors);
ResourceKind resourceKind = AbstractResourceKind.determineResourceKind( nsaToken, resourcePath, revisionDescriptor);
if ( (resourceKind instanceof VersionControlled) && (label != null) ) {
String vrUri = getUriOfAssociatedVR(nsaToken, sToken, content, revisionDescriptors.getUri());
UriHandler vrUriHandler = UriHandler.getUriHandler(vrUri);
String historyUri = vrUriHandler.getAssociatedHistoryUri();
revisionDescriptors = content.retrieve(sToken, historyUri);
revisionDescriptor = retrieveLabeledRevision(nsaToken, sToken, content, historyUri, label);
}
return getUri(nsaToken, sToken, content, revisionDescriptors, revisionDescriptor);
}
/**
* If the <code>resourcePath</code> identifies a VHR, the associated revision
* with the given <code>label</code> is returned. If the <code>resourcePath</code>
* does not identify a VHR , <code>null</code> is returned.
*
* @param nsaToken the NamespaceAccessToken to use.
* @param sToken the SlideToken to use.
* @param content the Content helper to use.
* @param historyUri the path of the resource for which to retrieve
* the NRD.
* @param label the label of the revision to return.
*
* @return the associated revision with the given <code>label</code>.
*
* @throws SlideException
* @throws LabeledRevisionNotFoundException if no revision with the specified
* label was found.
*/
public static NodeRevisionDescriptor retrieveLabeledRevision(NamespaceAccessToken nsaToken, SlideToken sToken, Content content, String historyUri, String label) throws SlideException, LabeledRevisionNotFoundException {
NodeRevisionDescriptor labeledRevision = null;
UriHandler historyUriHandler = UriHandler.getUriHandler(historyUri);
if (historyUriHandler.isHistoryUri()) {
NodeRevisionDescriptors historyNrds = content.retrieve(sToken, historyUri);
NodeRevisionDescriptor historyNrd =
content.retrieve(sToken, historyNrds, NodeRevisionNumber.HIDDEN_0_0);
NodeProperty versionSet = historyNrd.getProperty(P_VERSION_SET);
try {
XMLValue versionSetValue = new XMLValue(versionSet.getValue().toString());
NodeRevisionDescriptor vrNrd = null;
NodeProperty labelNameSetProperty = null;
String labelNameSetString = null;
Iterator versionSetIterator = versionSetValue.iterator();
String vrUri = null;
UriHandler vrUriHandler = null;
boolean found = false;
while ( !found && versionSetIterator.hasNext() ) {
vrUri = ((Element)versionSetIterator.next()).getText();
vrUriHandler = UriHandler.getUriHandler(vrUri);
NodeRevisionNumber vrRevisionNumber = new NodeRevisionNumber(vrUriHandler.getVersionName());
vrNrd = content.retrieve(sToken, historyNrds, vrRevisionNumber);
labelNameSetProperty = vrNrd.getProperty(P_LABEL_NAME_SET);
if ( (labelNameSetProperty != null) && (labelNameSetProperty.getValue() != null) ) {
labelNameSetString = labelNameSetProperty.getValue().toString();
if (labelNameSetString != null) {
XMLValue labelNameSet = new XMLValue(labelNameSetString);
Iterator labelNameSetIterator = labelNameSet.iterator();
while ( !found && labelNameSetIterator.hasNext() ) {
found = label.equals(((Element)labelNameSetIterator.next()).getText());
}
}
}
}
if (found) {
labeledRevision = vrNrd;
}
else {
throw new LabeledRevisionNotFoundException(historyUri, label);
}
}
catch (JDOMException e) {}
catch (IllegalArgumentException e) {}
}
return labeledRevision;
}
/**
* If the resource described by the given <code>resourceUri</code> is a
* VCR this method returns the URI of the associated VR,
* otherwise <code>null</code>
*
* @param nsaToken the NamespaceAccessToken to use.
* @param sToken the SlideToken to use.
* @param content the Content helper to use.
* @param resourceUri the URI of the resource.
*
* @return the URI of the associated VR.
*
* @throws SlideException
*/
public static String getUriOfAssociatedVR(NamespaceAccessToken nsaToken,
SlideToken sToken,
Content content,
String resourceUri) throws SlideException {
String vrUri = null;
NodeRevisionDescriptors revisionDescriptors = content.retrieve(sToken, resourceUri);
if (!revisionDescriptors.isVersioned()) {
NodeRevisionDescriptor revisionDescriptor =
content.retrieve( sToken, revisionDescriptors);
NodeProperty property = revisionDescriptor.getProperty(P_CHECKED_OUT);
if ( (property == null) || (property.getValue() == null) ) {
property = revisionDescriptor.getProperty(P_CHECKED_IN);
}
if ( (property != null) && (property.getValue() != null) ) {
try {
XMLValue xmlValue = new XMLValue(property.getValue().toString());
Iterator iterator = xmlValue.iterator();
if (iterator.hasNext()) {
Element element = (Element)iterator.next();
vrUri = element.getText();
}
}
catch (JDOMException e) {}
catch (IllegalArgumentException e) {}
}
}
return vrUri;
}
/**
* Returns the URI of the resource defined by the given NodeRevisionDescriptor(s).
*
*
* @param nsaToken the NamespaceAccessToken to use.
* @param sToken the SlideToken to use.
* @param content the Content helper to use.
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource.
*
* @return the URI of the resource.
*
* @throws SlideException
*/
public static String getUri(NamespaceAccessToken nsaToken,
SlideToken sToken,
Content content,
NodeRevisionDescriptors revisionDescriptors,
NodeRevisionDescriptor revisionDescriptor) throws SlideException {
StringBuffer uri = new StringBuffer();
UriHandler uriHandler = UriHandler.getUriHandler(revisionDescriptors.getUri());
if ( ! uriHandler.isHistoryUri() ) {
// any resource
uri.append(revisionDescriptors.getUri());
}
else {
if (revisionDescriptor.getRevisionNumber().equals(NodeRevisionNumber.HIDDEN_0_0)) {
// history resource
uri.append(revisionDescriptors.getUri());
}
else {
// version resource
uri.append(revisionDescriptors.getUri());
if ( ! revisionDescriptors.getUri().endsWith("/") ) {
uri.append("/");
}
uri.append(revisionDescriptor.getRevisionNumber().toString());
}
}
return uri.toString();
}
}