0001: /*
0002: * (C) Copyright IBM Corp. 2000 All rights reserved.
0003: *
0004: * The program is provided "AS IS" without any warranty express or
0005: * implied, including the warranty of non-infringement and the implied
0006: * warranties of merchantibility and fitness for a particular purpose.
0007: * IBM will not be liable for any damages suffered by you as a result
0008: * of using the Program. In no event will IBM be liable for any
0009: * special, indirect or consequential damages or lost profits even if
0010: * IBM has been advised of the possibility of their occurrence. IBM
0011: * will not be liable for any third party claims against you.
0012: *
0013: * Portions Copyright (C) Simulacra Media Ltd, 2004.
0014: */
0015:
0016: package com.ibm.webdav.impl;
0017:
0018: //import java.net.URLConnection;
0019: import java.io.*;
0020: import java.net.*;
0021: import java.rmi.*;
0022: import java.rmi.server.*;
0023: import java.util.*;
0024:
0025: import javax.xml.parsers.*;
0026:
0027: import org.w3c.dom.*;
0028:
0029: import com.ibm.webdav.*;
0030: import com.ibm.webdav.Collection;
0031: import com.ibm.webdav.protocol.http.*;
0032:
0033: /** Implements the Resource interface and all the WebDAV semantics. ResourceImpl
0034: * delegates certain low-level repository operations to managers provided for a
0035: * particular repository implementation. There are three repository managers
0036: * factoring the repository-specific behavior: NamesapceManager, PropertiesManager,
0037: * and LockManager. ResourceImplFactory constructs the appropriate managers for
0038: * this resource based on its URL. Mapping information from URL to repository
0039: * manager is configured in the dav4j.properties file.
0040: * <p>
0041: * ResourceImpl is generally used by a server to implement the WebDAV protocol.
0042: * However, it may also be used directly on the client if the resource URL is the localhost
0043: * and in that case, there are no remote procedure calls, and no need for a
0044: * server to run.
0045: * @author Jim Amsden <jamsden@us.ibm.com>
0046: * @see ResourceImplCollection
0047: * @see ResourceHTTPSkel
0048: */
0049: public class ResourceImpl implements IRResource {
0050: /** Setting debug to true causes debug information to be printed to System.err for
0051: * each method. This value can be changed by setting its value in
0052: * the dav4j.properties file and restarting the server.
0053: */
0054: public static boolean debug = false;
0055: public static java.util.Properties webdavProperties = new java.util.Properties();
0056: // properties taken from dav4j.properties.
0057: private static Vector liveProperties = new Vector();
0058: // the generic live properties
0059:
0060: static {
0061: // Find the dav4j.properties file in the classpath
0062: String classpath = System.getProperty("java.class.path");
0063: StringTokenizer paths = new StringTokenizer(classpath, ";");
0064: File propertiesFile = null;
0065: boolean found = false;
0066:
0067: while (!found && paths.hasMoreTokens()) {
0068: String path = paths.nextToken();
0069: propertiesFile = new File(path, "dav4j.properties");
0070: found = propertiesFile.exists();
0071: }
0072:
0073: if (found) {
0074: try {
0075: webdavProperties.load(new FileInputStream(
0076: propertiesFile));
0077: } catch (Exception exc) {
0078: exc.printStackTrace();
0079: }
0080: }
0081:
0082: String debugString = webdavProperties.getProperty("debug");
0083: debug = (debugString != null) && debugString.equals("true");
0084:
0085: // create the live properties
0086: liveProperties.addElement(new LockDiscovery());
0087: }
0088:
0089: // contexts for communicating HTTP and WebDAV headers (method contol couples)
0090: protected ResourceContext context = new ResourceContext();
0091:
0092: //------------------------------------------------------------------------------------
0093: protected String fileName = null;
0094: protected URL url = null;
0095: protected NamespaceManager namespaceManager = null;
0096: protected PropertiesManager propertiesManager = null;
0097: protected LockManager lockManager = null;
0098: static protected SearchManager searchManager = null;
0099: static protected UserAuthenticator authenticator = null;
0100:
0101: public ResourceImpl() {
0102: this .url = null;
0103: this .fileName = null;
0104: }
0105:
0106: /** Construct a ResourceImpl for the given URL.
0107: *
0108: * @param url the URL of the resource
0109: * @param localName a translation of the URL (filePortion) into
0110: * a name that has local meaning to a server.
0111: * @exception com.ibm.webdav.WebDAVException
0112: */
0113: public ResourceImpl(URL url, String localName)
0114: throws WebDAVException {
0115: this .url = url;
0116: this .fileName = localName;
0117:
0118: if (url.getProtocol().equals("rmi")) {
0119: try {
0120: UnicastRemoteObject.exportObject(this );
0121: } catch (java.rmi.RemoteException exc) {
0122: throw new WebDAVException(
0123: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
0124: "Unable to export rmi object");
0125: }
0126: }
0127:
0128: // TODO: get the Namespace to use from the dav4j.properties file
0129: // need to use a factory to do this
0130: namespaceManager = ResourceImplFactory
0131: .createNamespaceManager(this );
0132: propertiesManager = ResourceImplFactory
0133: .createPropertiesManager(this , namespaceManager);
0134: lockManager = ResourceImplFactory.createLockManager(this ,
0135: namespaceManager, propertiesManager);
0136:
0137: if (searchManager == null) {
0138: searchManager = ResourceImplFactory
0139: .createSearchManager(this );
0140: }
0141:
0142: if (authenticator == null) {
0143: authenticator = ResourceImplFactory.getAuthenticator(this );
0144: }
0145:
0146: // Set some default response context
0147: // Don't let proxy servers cache contents or properties
0148: getResponseContext().put("Cache-Control", "No-Cache");
0149: getResponseContext().put("Pragma", "No-Cache");
0150:
0151: // identify ourselves
0152: getResponseContext().put("Server", "IBM DAV4J Server/1.0");
0153: }
0154:
0155: /** Construct a ResourceImpl for the given URL.
0156: *
0157: * @param url the URL of the resource
0158: * @param localName a translation of the URL (filePortion) into
0159: * a name that has local meaning to a server.
0160: * @param targetSelector the revision target selector for this Collection
0161: * @exception com.ibm.webdav.WebDAVException
0162: */
0163: public ResourceImpl(URL url, String localName,
0164: TargetSelector targetSelector) throws WebDAVException {
0165: this .url = url;
0166: this .fileName = localName;
0167:
0168: if (url.getProtocol().equals("rmi")) {
0169: try {
0170: UnicastRemoteObject.exportObject(this );
0171: } catch (java.rmi.RemoteException exc) {
0172: throw new WebDAVException(
0173: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
0174: "Unable to export rmi object");
0175: }
0176: }
0177:
0178: // TODO: get the Namespace to use from the dav4j.properties file
0179: // need to use a factory to do this
0180: namespaceManager = ResourceImplFactory
0181: .createNamespaceManager(this );
0182: propertiesManager = ResourceImplFactory
0183: .createPropertiesManager(this , namespaceManager);
0184: lockManager = ResourceImplFactory.createLockManager(this ,
0185: namespaceManager, propertiesManager);
0186: if (searchManager == null) {
0187: searchManager = ResourceImplFactory
0188: .createSearchManager(this );
0189: }
0190:
0191: if (authenticator == null) {
0192: authenticator = ResourceImplFactory.getAuthenticator(this );
0193: }
0194:
0195: // Set some default response context
0196: // Don't let proxy servers cache contents or properties
0197: getResponseContext().put("Cache-Control", "No-Cache");
0198: getResponseContext().put("Pragma", "No-Cache");
0199:
0200: // identify ourselves
0201: getResponseContext().put("Server", "IBM DAV4J Server/1.0");
0202: }
0203:
0204: /** This method must be called after the client has completed writing to the contents
0205: * output stream that was obtained from <code>getContentsOutputStream()</code>.
0206: * @exception com.ibm.webdav.WebDAVException
0207: */
0208: public void closeContentsOutputStream(ResourceContext context)
0209: throws WebDAVException {
0210: closeContentsOutputStream(context, null);
0211: }
0212:
0213: /** Copy this resource to the destination URL.
0214: * Partial results are possible, check the returned status for details.
0215: *
0216: * @param destinationURL the destination
0217: * @param overwrite true implies overrite the destination if it exists
0218: * @param propertiesToCopy a collection of properties that must be copied or
0219: * the method will fail. propertiesToCopy may have one of the following values:
0220: * <ul>
0221: * <li>null - ignore properties that cannot be copied</li>
0222: * <li>empty collection - all properties must be copied or the method will fail</li>
0223: * <li>a collection of URIs - a list of the properties that must be copied
0224: * or the method will fail</li>
0225: * </ul>
0226: *
0227: * @return the status of the copy operation for each resource copied
0228: * @exception com.ibm.webdav.WebDAVException
0229: */
0230: public MultiStatus atomicMove(ResourceContext context,
0231: String destinationURL, boolean overwrite)
0232: throws WebDAVException {
0233: this .context = context;
0234:
0235: setStatusCode(WebDAVStatus.SC_CREATED);
0236:
0237: // create a MultiStatus to hold the results
0238: MultiStatus multiStatus = new MultiStatus();
0239:
0240: try {
0241: // validate the uri
0242: if (!hasValidURI()) {
0243: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0244: "Invalid URI");
0245: }
0246:
0247: // make sure the resource exists
0248: if (!exists()) {
0249: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
0250: "Cannot copy a lock-null resource");
0251: }
0252:
0253: // the destination may be a relative URL
0254: URL destURL = new URL(this .url, destinationURL);
0255: Resource destination = new Resource(destURL.toString());
0256:
0257: // are the source and destination the same?
0258: if (this .equals(destination)) {
0259: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
0260: "Can't copy source on top of itself");
0261: }
0262:
0263: // is the destination locked?
0264: destination.getRequestContext().precondition(
0265: getRequestContext().precondition());
0266: destination.getRequestContext().authorization(
0267: getRequestContext().authorization());
0268:
0269: if (destination.exists()) {
0270: if (destination.isLocked()) {
0271: if (!destination.isLockedByMe()) {
0272: throw new WebDAVException(
0273: WebDAVStatus.SC_LOCKED,
0274: "Destination resource is locked");
0275: }
0276: }
0277: }
0278:
0279: // check to see if the destination exists and its OK to overwrite it
0280: if (destination.exists()) {
0281: if (!overwrite) {
0282: throw new WebDAVException(
0283: WebDAVStatus.SC_PRECONDITION_FAILED,
0284: "Destination exists and overwrite not specified");
0285: } else {
0286: setStatusCode(WebDAVStatus.SC_NO_CONTENT);
0287: }
0288: }
0289:
0290: this .namespaceManager.move(URLDecoder
0291: .decode(ResourceFactory.getRealPath(destURL)));
0292:
0293: // everything must have gone OK, there
0294: // is no response for a successful delete
0295: getResponseContext().contentType("text/xml");
0296: } catch (WebDAVException exc) {
0297: throw exc;
0298: } catch (java.net.MalformedURLException exc) {
0299: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0300: "Malformed URL");
0301: } catch (java.io.IOException exc) {
0302: throw new WebDAVException(
0303: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
0304: }
0305:
0306: return multiStatus;
0307: }
0308:
0309: /** Copy this resource to the destination URL.
0310: * Partial results are possible, check the returned status for details.
0311: *
0312: * @param destinationURL the destination
0313: * @param overwrite true implies overrite the destination if it exists
0314: * @param propertiesToCopy a collection of properties that must be copied or
0315: * the method will fail. propertiesToCopy may have one of the following values:
0316: * <ul>
0317: * <li>null - ignore properties that cannot be copied</li>
0318: * <li>empty collection - all properties must be copied or the method will fail</li>
0319: * <li>a collection of URIs - a list of the properties that must be copied
0320: * or the method will fail</li>
0321: * </ul>
0322: *
0323: * @return the status of the copy operation for each resource copied
0324: * @exception com.ibm.webdav.WebDAVException
0325: */
0326: public MultiStatus copy(ResourceContext context,
0327: String destinationURL, boolean overwrite,
0328: Vector propertiesToCopy) throws WebDAVException {
0329: this .context = context;
0330:
0331: setStatusCode(WebDAVStatus.SC_CREATED);
0332:
0333: // create a MultiStatus to hold the results
0334: MultiStatus multiStatus = new MultiStatus();
0335:
0336: try {
0337: // validate the uri
0338: if (!hasValidURI()) {
0339: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0340: "Invalid URI");
0341: }
0342:
0343: // make sure the resource exists
0344: if (!exists()) {
0345: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
0346: "Cannot copy a lock-null resource");
0347: }
0348:
0349: // the destination may be a relative URL
0350: URL destURL = new URL(this .url, destinationURL);
0351: Resource destination = new Resource(destURL.toString());
0352:
0353: String sContentType = namespaceManager.getContentType();
0354:
0355: // are the source and destination the same?
0356: if (this .equals(destination)) {
0357: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
0358: "Can't copy source on top of itself");
0359: }
0360:
0361: // is the destination locked?
0362: destination.getRequestContext().precondition(
0363: getRequestContext().precondition());
0364: destination.getRequestContext().authorization(
0365: getRequestContext().authorization());
0366:
0367: if (destination.exists()) {
0368: if (destination.isLocked()) {
0369: if (!destination.isLockedByMe()) {
0370: throw new WebDAVException(
0371: WebDAVStatus.SC_LOCKED,
0372: "Destination resource is locked");
0373: }
0374: }
0375: }
0376:
0377: // check to see if the destination exists and its OK to overwrite it
0378: if (destination.exists()) {
0379: if (!overwrite) {
0380: throw new WebDAVException(
0381: WebDAVStatus.SC_PRECONDITION_FAILED,
0382: "Destination exists and overwrite not specified");
0383: } else {
0384: setStatusCode(WebDAVStatus.SC_NO_CONTENT);
0385: }
0386: }
0387:
0388: InputStream is = getContentsInputStream(context);
0389:
0390: OutputStream os = destination.getContentsOutputStream();
0391: if (is != null) {
0392: byte[] buf = new byte[8192];
0393: int numRead = 0;
0394:
0395: while ((numRead = is.read(buf, 0, buf.length)) != -1) {
0396: os.write(buf, 0, numRead);
0397: }
0398: is.close();
0399: }
0400:
0401: destination.closeContentsOutputStream(sContentType);
0402:
0403: // copy the properties
0404: WebDAVStatus savedStatusCode = getStatusCode();
0405: MultiStatus ms2 = copyProperties(destination,
0406: propertiesToCopy);
0407:
0408: if (!ms2.isOK()) {
0409: // todo: add code here to back out this partial copy. That might require
0410: // restoring the resource that used to be at the destination. For now, we'll throw
0411: // an exception.
0412: throw new WebDAVException(
0413: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
0414: "problem copying properties");
0415: }
0416:
0417: setStatusCode(savedStatusCode);
0418:
0419: // remove all locks on the destination. Copy doesn't copy locks
0420: // become super-user for this operation
0421: String authorization = getRequestContext().authorization();
0422: destination.getRequestContext().setBasicAuthorization(
0423: "root", "");
0424:
0425: Enumeration locks = destination.getLocks().elements();
0426:
0427: while (locks.hasMoreElements()) {
0428: ActiveLock lock = (ActiveLock) locks.nextElement();
0429:
0430: // ignore exceptions, the unlock should work
0431: try {
0432: destination.unlock(lock.getLockToken());
0433: } catch (Exception exc) {
0434: }
0435: }
0436:
0437: destination.getRequestContext()
0438: .authorization(authorization);
0439:
0440: // everything must have gone OK, there
0441: // is no response for a successful delete
0442: getResponseContext().contentType("text/xml");
0443: } catch (WebDAVException exc) {
0444: throw exc;
0445: } catch (java.net.MalformedURLException exc) {
0446: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0447: "Malformed URL");
0448: } catch (java.io.IOException exc) {
0449: throw new WebDAVException(
0450: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
0451: }
0452:
0453: return multiStatus;
0454: }
0455:
0456: /** Copy the properties of this resource to the destination resource.
0457: * Follow any keepalive instructions in the propertiesToCopy vector.
0458: * @param destination the destination resource
0459: * @param propertiesToCopy properties that must be kept alive at the destination
0460: * <ul>
0461: * <li>null - ignore properties that cannot be copied</li>
0462: * <li>empty collection - all properties must be copied or the method will fail</li>
0463: * <li>a collection of URIs - a list of the properties that must be copied
0464: * or the method will fail</li>
0465: * </ul>
0466: * @return a MultiStatus indicating the result of the copy operation
0467: * @exception com.ibm.webdav.WebDAVException
0468: */
0469: protected MultiStatus copyProperties(Resource destination,
0470: Vector propertiesToCopy) throws WebDAVException {
0471: MultiStatus result = getProperties(context);
0472: boolean bOnlySomeProperties = ((propertiesToCopy != null) && (propertiesToCopy
0473: .size() > 0));
0474:
0475: // create a property update document
0476: Document document = null;
0477:
0478: try {
0479: DocumentBuilderFactory factory = DocumentBuilderFactory
0480: .newInstance();
0481: factory.setNamespaceAware(true);
0482:
0483: DocumentBuilder docbuilder = factory.newDocumentBuilder();
0484: document = docbuilder.newDocument();
0485: } catch (Exception e) {
0486: throw new WebDAVException(
0487: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
0488: .getMessage());
0489: }
0490:
0491: //document.setVersion(Resource.XMLVersion);
0492: //document.setEncoding(Resource.defaultXMLEncoding);
0493: Element propertyUpdate = document.createElementNS("DAV:",
0494: "D:propertyupdate");
0495:
0496: propertyUpdate.setAttribute("xmlns:D", "DAV:");
0497: document.appendChild(propertyUpdate);
0498:
0499: Element set = document.createElementNS("DAV:", "D:set");
0500:
0501: propertyUpdate.appendChild(set);
0502:
0503: Element prop = document.createElementNS("DAV:", "D:prop");
0504:
0505: set.appendChild(prop);
0506:
0507: Hashtable PropsWillCopy = new java.util.Hashtable();
0508:
0509: // fill in the properties from the source
0510: PropertyResponse response = (PropertyResponse) result
0511: .getResponses().nextElement();
0512: Enumeration propertyNames = response.getPropertyNamesPN();
0513:
0514: while (propertyNames.hasMoreElements()) {
0515: PropertyName name = (PropertyName) propertyNames
0516: .nextElement();
0517: PropertyValue value = response.getProperty(name);
0518: Node node = document.importNode(value.value, true);
0519: PropsWillCopy.put(name, node);
0520: prop.appendChild((Element) node);
0521: }
0522:
0523: // attempt to update all the properties at the destination
0524: MultiStatus msRc = destination.setProperties(document);
0525:
0526: // now look at what happened, and adjust based on the propertiesToCopy
0527: Enumeration resources = msRc.getResponses();
0528:
0529: while (resources.hasMoreElements()) {
0530: Response resmember = (Response) resources.nextElement();
0531: PropertyResponse propresponse = resmember
0532: .toPropertyResponse();
0533: Dictionary htProperties = (Hashtable) propresponse
0534: .getPropertiesByPropName();
0535: Enumeration propertynames = htProperties.keys();
0536:
0537: while (propertynames.hasMoreElements()) {
0538: PropertyName propname = (PropertyName) propertynames
0539: .nextElement();
0540: PropertyValue pv = (PropertyValue) htProperties
0541: .get(propname);
0542: int stat = pv.getStatus();
0543:
0544: if ((stat != WebDAVStatus.SC_OK)
0545: && (stat != WebDAVStatus.SC_FAILED_DEPENDENCY)) {
0546: Node node = (Node) PropsWillCopy.get(propname);
0547:
0548: if ((propertiesToCopy == null)
0549: || (propertiesToCopy.size() > 0 && !propertiesToCopy
0550: .contains(propname))) {
0551: prop.removeChild(node); // don't need to copy this one
0552: }
0553: }
0554: }
0555: }
0556:
0557: // attempt to update the remaining properties again
0558: // after removing the ones that can be allowed to fail.
0559: // This has to be a two step process because there's no
0560: // way to determine what properties are live on anoter
0561: // server. We're trying to get a propertyupdate element
0562: // on PROPPATCH too so this extra step can be avoided.
0563: return destination.setProperties(document);
0564: }
0565:
0566: /** Create a instance of a ResourceImpl with the given URL and localName.
0567: *
0568: * @param url the URL of the resource to create
0569: * @param localName the name of the resource on the server machine
0570: * @return a ResourceImpl or one of its subclasses.
0571: * @exception com.ibm.webdav.WebDAVException
0572: */
0573: public static ResourceImpl create(URL url, String localName)
0574: throws WebDAVException {
0575: ResourceImpl resource = new ResourceImpl(url, localName);
0576:
0577: if (resource.isCollection()) {
0578: resource = new CollectionImpl(url, localName, null);
0579: }
0580:
0581: return resource;
0582: }
0583:
0584: /** Build a multistatus property response that returns the error specified
0585: by the given exception. It should return this error for every property provided
0586: in the specified document which should represent the XML of a PROPPATCH
0587: request.
0588: *
0589: * @param exc an exception that describes the error to be placed in the MultiStatus created.
0590: * @param updates an XML Document containing DAV:propertyupdate elements
0591: * describing the edits that were request orginally requested and
0592: * apparently generated the given exception.
0593: * @return a MultiStatus indicating the status of the updates
0594: * @exception com.ibm.webdav.WebDAVException
0595: */
0596: public MultiStatus createPropPatchMultiStatus(WebDAVException exc,
0597: Document updates) throws WebDAVException {
0598: MultiStatus ms2 = new MultiStatus();
0599: Element el0 = updates.getDocumentElement();
0600: Element txel0 = (Element) el0;
0601: NodeList nl = txel0.getElementsByTagNameNS("DAV:", "prop");
0602:
0603: /*Element na[] = txel0.searchDescendantsAll( Match.NSLOCAL, //Match.QNAME,
0604: "DAV:", "prop" );*/
0605: int nllen = nl.getLength();
0606: int idx = 0;
0607: String lxx = "xx";
0608:
0609: if (nllen <= 0) {
0610: throw exc;
0611: }
0612:
0613: while (idx < nllen) {
0614: Element txelProp = (Element) nl.item(idx);
0615: Node node2 = txelProp.getFirstChild();
0616: Element txel2 = null;
0617:
0618: try {
0619: txel2 = (Element) node2;
0620: } catch (Exception exc2) {
0621: throw exc;
0622: }
0623:
0624: {
0625: // todo: add code to handle the responsedescription in the exception and
0626: // include it in the multistatus response.
0627: PropertyName pn = new PropertyName(txel2);
0628: PropertyResponse response = new PropertyResponse(
0629: getURL().toString());
0630: response.addProperty(pn, (Element) txel2
0631: .cloneNode(false), exc.getStatusCode());
0632: ms2.addResponse(response);
0633: }
0634:
0635: idx++;
0636: }
0637:
0638: return ms2;
0639: }
0640:
0641: /** Delete this resouce from the server. The actual effect of the delete operation is
0642: * determined by the underlying repository manager. The visible effect to WebDAV
0643: * is that the resource is no longer available.
0644: *
0645: * @return a MultiStatus containing the status of the delete method on each
0646: * effected resource.
0647: * @exception com.ibm.webdav.WebDAVException
0648: */
0649: public MultiStatus delete(ResourceContext context)
0650: throws WebDAVException {
0651: this .context = context;
0652:
0653: setStatusCode(WebDAVStatus.SC_NO_CONTENT);
0654:
0655: MultiStatus result = new MultiStatus();
0656:
0657: // validate the uri
0658: if (!hasValidURI()) {
0659: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0660: "Invalid URI");
0661: }
0662:
0663: // make sure the parent collection exists
0664: CollectionImpl parent = (CollectionImpl) getParentCollection();
0665:
0666: if ((parent != null) && !parent.exists()) {
0667: throw new WebDAVException(WebDAVStatus.SC_CONFLICT,
0668: "Parent collection does not exist");
0669: }
0670:
0671: // TODO support shared locks here or wherever needs it
0672: /*
0673: *
0674:
0675: QUICK FIX
0676:
0677: Commenting this out to allow addition of members to locked collections
0678:
0679: Will have to implement the shared lock thing eventually to support this
0680:
0681:
0682: // make sure the parent collection is not locked, or is locked by this user
0683: if (parent != null) {
0684: parent.getRequestContext().precondition(
0685: getRequestContext().precondition());
0686: parent.getRequestContext().authorization(
0687: getRequestContext().authorization());
0688:
0689: if (parent.isLocked() && !parent.isLockedByMe()) {
0690: throw new WebDAVException(
0691: WebDAVStatus.SC_LOCKED,
0692: "Parent collection is locked by another user");
0693: }
0694: }
0695: */
0696:
0697: if (!exists()) {
0698: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
0699: "Resource does not exist");
0700: }
0701:
0702: // check to see if the resource is locked by another user
0703: if (isLocked() && !isLockedByMe()) {
0704: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
0705: "Resource is locked by another user");
0706: }
0707:
0708: // reset statusCode because isLocked has a side effect of changing it
0709: // to 207 multistatus.
0710: setStatusCode(WebDAVStatus.SC_NO_CONTENT);
0711:
0712: // Attempt to delete this resource
0713: namespaceManager.delete();
0714: propertiesManager.deleteProperties();
0715: getResponseContext().contentType("text/xml");
0716:
0717: return result;
0718: }
0719:
0720: /** Unlock the lock identified by the lockToken on this resource. This method
0721: * is used internally to unlock resources copied or moved as well as unlocked.
0722: *
0723: * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
0724: * or <code>getLocks()</code>.
0725: *
0726: * @return a MultiStatus containing any responses on resources that could not
0727: * be unlocked.
0728: * @exception com.ibm.webdav.WebDAVException
0729: */
0730: protected MultiStatus doUnlock(String lockToken)
0731: throws WebDAVException {
0732: String principal = getRequestContext().getAuthorizationId();
0733:
0734: // get the locks on this resource
0735: Enumeration locks = getLocks().elements();
0736:
0737: // find the lock to unlock
0738: ActiveLock lockToRemove = null;
0739:
0740: while (locks.hasMoreElements()) {
0741: ActiveLock activeLock = (ActiveLock) locks.nextElement();
0742:
0743: if (activeLock.getLockToken().equals(lockToken)
0744: && (activeLock.getPrincipal().equals(principal)
0745: || principal.equals("root") || authenticator
0746: .isSuperUser(this ) == true)) {
0747: lockToRemove = activeLock;
0748:
0749: break;
0750: }
0751: }
0752:
0753: if (lockToRemove == null) {
0754: throw new WebDAVException(
0755: WebDAVStatus.SC_PRECONDITION_FAILED,
0756: "resource is not locked by this principal");
0757: }
0758:
0759: MultiStatus result = lockManager.unlock(lockToRemove);
0760:
0761: // delete a lock-null resource that has no remaining activelocks
0762: locks = getLocks().elements();
0763:
0764: if (!locks.hasMoreElements() && namespaceManager.isLockNull()) {
0765: propertiesManager.deleteProperties();
0766: }
0767:
0768: getResponseContext().contentType("text/xml");
0769:
0770: return result;
0771: }
0772:
0773: /** See if the contents of this resource exists. A resource exists
0774: * if it has contents or state maintained by a server.
0775: *
0776: * @return true if the contents exists, false otherwise
0777: * @exception com.ibm.webdav.WebDAVException
0778: */
0779: public boolean exists() throws WebDAVException {
0780: return namespaceManager.exists();
0781: }
0782:
0783: public boolean authenticateUser(String user, String pwd)
0784: throws WebDAVException {
0785: boolean bIsAuthenticated = true;
0786:
0787: if (authenticator != null) {
0788: bIsAuthenticated = authenticator.authenticate(user, pwd);
0789: }
0790:
0791: return bIsAuthenticated;
0792: }
0793:
0794: /** Get the active lock on this resource owned by the given principal if any.
0795: * NOTE: this method cannot be reliably implemented based on version 10 of
0796: * the WebDAV spec as an activelock element in a lockdiscovery does not contain
0797: * the authorization credentials of the owner of the lock. For now, this method
0798: * relies on an additional principal element in the activelock that contains
0799: * the required id. This is an IBM EXTENSTION. When WebDAV ACLs are introduced,
0800: * the principal will likely be added to the activelock element.
0801: *
0802: * @param principal the authorization id of the requesting principal
0803: *
0804: * @return the active lock owned by that principal or null if the resource is
0805: * not locked by that principal.
0806: * @exception com.ibm.webdav.WebDAVException
0807: */
0808: protected ActiveLock getActiveLockFor(String scope, String type,
0809: int timeout, Element owner) throws WebDAVException {
0810: String principal = getRequestContext().getAuthorizationId();
0811:
0812: if (principal == null) {
0813: throw new WebDAVException(WebDAVStatus.SC_UNAUTHORIZED,
0814: "missing authorization identification");
0815: }
0816:
0817: // check all the parameters
0818: if ((scope == null)
0819: || (!scope.equals(ActiveLock.exclusive) && !scope
0820: .equals(ActiveLock.shared))) {
0821: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0822: "unsupported or missing lock scope: " + scope);
0823: }
0824:
0825: if ((type == null) || !type.equals(ActiveLock.writeLock)) {
0826: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0827: "unsupported or missing lock type: " + type);
0828: }
0829:
0830: // handle locking non-existant resources
0831: if (!exists()) {
0832: namespaceManager.createLockNullResource();
0833: }
0834:
0835: // We extend ActiveLock to include the principal and expiration date
0836: ActiveLock activeLock = new ActiveLock();
0837: activeLock.setScope(scope);
0838: activeLock.setLockType(type);
0839: activeLock.setDepth(Collection.shallow);
0840:
0841: if (owner != null) {
0842: activeLock.setOwner(owner);
0843: }
0844:
0845: if (timeout < 0) {
0846: activeLock.setTimeout("Infinite");
0847: } else {
0848: activeLock.setTimeout("Second-" + timeout);
0849: }
0850:
0851: String lockToken = "opaquelocktoken:" + new UUID();
0852: activeLock.setLockToken(lockToken);
0853: activeLock.setPrincipal(principal);
0854:
0855: return activeLock;
0856: }
0857:
0858: /** Get an InputStream for accessing the contents of this resource. This method may provide
0859: * more efficient access for resources that have large contents. Clients may want to create
0860: * a Reader to perform appropriate character conversions on this stream.
0861: *
0862: * @return an InputStream on the contents
0863: * @exception com.ibm.webdav.WebDAVException
0864: */
0865: public InputStream getContentsInputStream(ResourceContext context)
0866: throws WebDAVException {
0867: this .context = context;
0868:
0869: // validate the uri
0870: if (!hasValidURI()) {
0871: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0872: "Invalid URI");
0873: }
0874:
0875: InputStream is = namespaceManager.getContentsInputStream();
0876:
0877: return is;
0878: }
0879:
0880: /** Get an OutputStream for setting the contents of this resource. This method may provide
0881: * more efficient access for resources that have large contents. Remember to call
0882: * closeContentsOutputStream() when all the data has been written.
0883: *
0884: * @return an OutputStream to set the contents
0885: * @exception com.ibm.webdav.WebDAVException
0886: */
0887: public OutputStream getContentsOutputStream(ResourceContext context)
0888: throws WebDAVException {
0889: this .context = context;
0890:
0891: // validate the uri
0892: if (!hasValidURI()) {
0893: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
0894: "Invalid URI");
0895: }
0896:
0897: // make sure the parent collection exists
0898: CollectionImpl parent = (CollectionImpl) getParentCollection();
0899:
0900: if ((parent != null) && !parent.exists()) {
0901: throw new WebDAVException(WebDAVStatus.SC_CONFLICT,
0902: "Parent collection does not exist");
0903: }
0904:
0905: //TODO support shared locks here or wherever needs it
0906: /*
0907: *
0908:
0909: QUICK FIX
0910:
0911: Commenting this out to allow addition of members to locked collections
0912:
0913: Will have to implement the shared lock thing eventually to support this
0914:
0915:
0916: // make sure the parent collection is not locked, or is locked by this user
0917: if (parent != null) {
0918: // use this resource's precondition, it should contain the
0919: // parent locktoken if needed
0920: parent.getRequestContext().precondition(
0921: getRequestContext().precondition());
0922: parent.getRequestContext().authorization(
0923: getRequestContext().authorization());
0924:
0925: if (parent.isLocked() && !parent.isLockedByMe()) {
0926: throw new WebDAVException(
0927: WebDAVStatus.SC_LOCKED,
0928: "Parent collection is locked by another user");
0929: }
0930: }*/
0931:
0932: // check to see if the resource is locked by another user
0933: if (exists() && isLocked() && !isLockedByMe()) {
0934: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
0935: "Resource is locked by another user");
0936: }
0937:
0938: // Resources that already exist are overwritten
0939: return namespaceManager.getContentsOutputStream();
0940: }
0941:
0942: /**
0943: * Insert the method's description here.
0944: * Creation date: (4/14/2000 4:14:55 PM)
0945: * @return com.ibm.webdav.ResourceContext
0946: */
0947: public com.ibm.webdav.ResourceContext getContext() {
0948: return context;
0949: }
0950:
0951: /** Return lock manager for this resource
0952: */
0953: public LockManager getLockManager() {
0954: return lockManager;
0955: }
0956:
0957: /**Return authenticator for this resource
0958: *
0959: */
0960: public UserAuthenticator getUserAuthenticator() {
0961: return ResourceImpl.authenticator;
0962: }
0963:
0964: /** Get the locks that exist on this resource.
0965: *
0966: * @return a Vector of ActiveLock objects
0967: * @exception com.ibm.webdav.WebDAVException
0968: */
0969: public Vector getLocks() throws WebDAVException {
0970: return lockManager.getLocks();
0971: }
0972:
0973: /** This method can be used for obtaining meta-information about this resource without
0974: * actually reading the resource contents. This meta-information is maintained by the server
0975: * in addition to the resource properties.</p>
0976: * <p>
0977: * After this call, the resource context has been updated and
0978: * <code>getStatusCode()</code>, <code>getStatusMessage()</code>, and <code>getResponseContext()</code>
0979: * as well as all the ResourceContext methods return updated values based on the current
0980: * state of the resource.</p>
0981: * <p>This methods corresponds to the HTTP HEAD method.</p>
0982: * <p>
0983: * Do a getContentsInputStream() to set the response context,
0984: * then just don't return the stream.
0985: * @exception com.ibm.webdav.WebDAVException
0986: */
0987: public void getMetaInformation(ResourceContext context)
0988: throws WebDAVException {
0989: this .context = context;
0990:
0991: InputStream is = getContentsInputStream(context);
0992:
0993: try {
0994: is.close();
0995: } catch (WebDAVException exc) {
0996: throw exc;
0997: } catch (java.io.IOException exc) {
0998: }
0999: }
1000:
1001: /** Return the local name of the resource. What this name actually is
1002: * depends on the interpretation of the resource URL by the namespace
1003: * manager servicing it. Repository implementations are free to translate
1004: * the URL any way they want for their own purposes. For example, the
1005: * file system implementation uses the doc.root property to translate
1006: * the file part of the URL into a full pathname.
1007: * @return the repository specific name for this resource
1008: * @exception com.ibm.webdav.WebDAVException
1009: */
1010: public String getName() throws WebDAVException {
1011: if ((fileName == null) && (url != null)) {
1012: fileName = ResourceFactory.getRealPath(url);
1013: }
1014:
1015: String sDecoded = null;
1016: try {
1017: sDecoded = URLDecoder.decode(fileName, "UTF-8");
1018: } catch (UnsupportedEncodingException e) {
1019: throw new WebDAVException(
1020: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
1021: .getLocalizedMessage());
1022: }
1023:
1024: return sDecoded;
1025: }
1026:
1027: /** Get the collection containing this resource.
1028: *
1029: * @return the parent collection
1030: * @exception com.ibm.webdav.WebDAVException
1031: */
1032: public IRCollection getParentCollection() throws WebDAVException {
1033: String parentURL = getURL().toString();
1034: String parentLocalName = getName();
1035: int delimiterPosition = 0;
1036:
1037: if (namespaceManager instanceof VersionedNamespaceManager) {
1038: if (((VersionedNamespaceManager) namespaceManager)
1039: .isVersionURL(parentURL) == true) {
1040: parentURL = ((VersionedNamespaceManager) namespaceManager)
1041: .getResourceURL();
1042: try {
1043: parentLocalName = ResourceFactory
1044: .getRealPath(new URL(url, parentURL));
1045: } catch (MalformedURLException e) {
1046: throw new WebDAVException(
1047: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
1048: .getLocalizedMessage());
1049: }
1050: }
1051: }
1052:
1053: if (parentURL.endsWith("/")) {
1054: delimiterPosition = parentURL.substring(0,
1055: parentURL.length() - 1).lastIndexOf("/");
1056: } else {
1057: delimiterPosition = parentURL.lastIndexOf("/");
1058: }
1059:
1060: parentURL = parentURL.substring(0, delimiterPosition + 1);
1061:
1062: if (parentLocalName.endsWith(File.separator)) {
1063: delimiterPosition = parentLocalName.substring(0,
1064: parentLocalName.length() - 1).lastIndexOf(
1065: File.separator);
1066: } else {
1067: delimiterPosition = parentLocalName
1068: .lastIndexOf(File.separator);
1069: }
1070:
1071: parentLocalName = parentLocalName.substring(0,
1072: delimiterPosition + 1);
1073:
1074: CollectionImpl parent = null;
1075:
1076: try {
1077: URL url = new URL(getURL(), parentURL);
1078: parent = new CollectionImpl(url, parentLocalName, null);
1079: } catch (java.net.MalformedURLException exc) {
1080: exc.printStackTrace();
1081: }
1082:
1083: return parent;
1084: }
1085:
1086: /** Get the URL of the collection containing this resource.
1087: *
1088: * @return the parent collection URL, always ending in a separator
1089: * @exception com.ibm.webdav.WebDAVException
1090: */
1091: public URL getParentURL() throws WebDAVException {
1092: String uri = getURL().getFile();
1093: int delimiterPosition = 0;
1094:
1095: if (uri.endsWith("/")) {
1096: delimiterPosition = uri.substring(0, uri.length() - 1)
1097: .lastIndexOf("/");
1098: } else {
1099: delimiterPosition = uri.lastIndexOf("/");
1100: }
1101:
1102: URL parentURL = null;
1103:
1104: try {
1105: parentURL = new URL(getURL(), uri.substring(0,
1106: delimiterPosition + 1));
1107: } catch (java.net.MalformedURLException exc) {
1108: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
1109: "Malformed URL");
1110: }
1111:
1112: return parentURL;
1113: }
1114:
1115: public MultiStatus getSearchSchema(ResourceContext context,
1116: SearchRequest searchReq) throws WebDAVException {
1117: this .context = context;
1118:
1119: // create a MultiStatus to hold the results
1120: MultiStatus results = new MultiStatus();
1121:
1122: // create a document
1123: Document document = null;
1124:
1125: try {
1126: DocumentBuilderFactory factory = DocumentBuilderFactory
1127: .newInstance();
1128: factory.setNamespaceAware(true);
1129:
1130: DocumentBuilder docbuilder = factory.newDocumentBuilder();
1131: document = docbuilder.newDocument();
1132: } catch (Exception e) {
1133: e.printStackTrace(System.err);
1134: throw new WebDAVException(WebDAVStatus.SC_PROCESSING, e
1135: .getMessage());
1136: }
1137:
1138: SearchSchema schema = searchManager.getSearchSchema(searchReq);
1139:
1140: SchemaResponse response = new SchemaResponse(document, schema,
1141: searchReq.getScopeURI());
1142:
1143: results.addResponse(response);
1144:
1145: return results;
1146: }
1147:
1148: public MultiStatus executeSearch(ResourceContext context,
1149: SearchRequest searchReq) throws WebDAVException {
1150: this .context = context;
1151:
1152: // create a MultiStatus to hold the results
1153: MultiStatus result = new MultiStatus();
1154:
1155: if (searchManager.validate(searchReq)) {
1156: Vector resources = searchManager.executeSearch(searchReq,
1157: this );
1158:
1159: // now get the properties of the members if necessary
1160: Enumeration members = resources.elements();
1161:
1162: while (members.hasMoreElements()) {
1163: ResourceImpl member = (ResourceImpl) members
1164: .nextElement();
1165:
1166: try {
1167: MultiStatus memberResult = null;
1168:
1169: if (member.isCollection()) {
1170: if (searchReq.isAllSelectProperties()) {
1171: memberResult = ((CollectionImpl) member)
1172: .getProperties(context,
1173: Collection.this Resource);
1174: } else {
1175: memberResult = ((CollectionImpl) member)
1176: .getProperties(
1177: context,
1178: (PropertyName[]) searchReq
1179: .getSelectProperties()
1180: .toArray(
1181: new PropertyName[0]),
1182: Collection.this Resource);
1183: }
1184: } else {
1185: if (searchReq.isAllSelectProperties()) {
1186: memberResult = member
1187: .getProperties(context);
1188: } else {
1189: memberResult = member
1190: .getProperties(
1191: context,
1192: (PropertyName[]) searchReq
1193: .getSelectProperties()
1194: .toArray(
1195: new PropertyName[0]));
1196: }
1197: }
1198:
1199: result.mergeWith(memberResult);
1200: } catch (WebDAVException exc) {
1201: MethodResponse response = new MethodResponse(member
1202: .getURL().toString(), exc.getStatusCode());
1203: result.addResponse(response);
1204: } catch (Exception e) {
1205: e.printStackTrace();
1206: throw new WebDAVException(
1207: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1208: "unable to get properties");
1209: }
1210: }
1211: } else {
1212: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
1213: "Invalid query");
1214: }
1215:
1216: getResponseContext().contentType("text/xml");
1217:
1218: return result;
1219: }
1220:
1221: /** Get all the properties of this resource.
1222: *
1223: * @return a MultiStatus of PropertyResponses. It should contain only one
1224: * response element.
1225: * @see com.ibm.webdav.MultiStatus
1226: * @see com.ibm.webdav.PropertyResponse
1227: * @exception com.ibm.webdav.WebDAVException
1228: */
1229: public MultiStatus getProperties(ResourceContext context)
1230: throws WebDAVException {
1231: this .context = context;
1232:
1233: // make sure the resource exists.
1234: if (!(exists() || namespaceManager.isLockNull())) {
1235:
1236: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
1237: "Resource does not exist");
1238: }
1239:
1240: setStatusCode(WebDAVStatus.SC_MULTI_STATUS);
1241: getResponseContext().contentType("text/xml");
1242:
1243: return propertiesManager.getProperties();
1244: }
1245:
1246: /** Get the named properties of this resource.
1247: *
1248: * @param names an arrary of property names to retrieve
1249: *
1250: * @return a MultiStatus of PropertyResponses
1251: * @exception com.ibm.webdav.WebDAVException
1252: * @see com.ibm.webdav.PropertyResponse
1253: */
1254: public MultiStatus getProperties(ResourceContext context,
1255: PropertyName[] names) throws WebDAVException {
1256: this .context = context;
1257:
1258: // make sure the resource exists.
1259: if (!(exists() || namespaceManager.isLockNull())) {
1260: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
1261: "Resource does not exist");
1262: }
1263:
1264: getResponseContext().contentType("text/xml");
1265:
1266: return propertiesManager.getProperties(names);
1267: }
1268:
1269: /** Get the value of the given property for this resource.
1270: *
1271: * @param name the name of the property to retrieve
1272: *
1273: * @return PropertyValue or null if the resource does not have the requested property
1274: * @exception com.ibm.webdav.WebDAVException
1275: */
1276: public PropertyValue getProperty(PropertyName name)
1277: throws WebDAVException {
1278: PropertyName[] names = new PropertyName[1];
1279: names[0] = name;
1280:
1281: Enumeration responses = getProperties(context, names)
1282: .getResponses();
1283: PropertyResponse response = (PropertyResponse) responses
1284: .nextElement();
1285: Dictionary properties = response.getPropertiesByPropName();
1286:
1287: return (PropertyValue) properties.get(name);
1288: }
1289:
1290: /** Get the names of all properties for this resource. The result is similar to
1291: * getProperties(), but the properties have no values.
1292: *
1293: * @return a MultiStatus of PropertyResponses
1294: * (PropertyValue.value is always null, PropertyValue.status contains the status)
1295: * @exception com.ibm.webdav.WebDAVException
1296: * @see com.ibm.webdav.PropertyResponse
1297: */
1298: public MultiStatus getPropertyNames(ResourceContext context)
1299: throws WebDAVException {
1300: this .context = context;
1301:
1302: // make sure the resource exists.
1303: if (!(exists() || namespaceManager.isLockNull())) {
1304: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
1305: "Resource does not exist");
1306: }
1307:
1308: getResponseContext().contentType("text/xml");
1309:
1310: return propertiesManager.getPropertyNames();
1311: }
1312:
1313: /** Get the request context for this resource. The context contains information
1314: * used by methods on a resource when the method is called.
1315: *
1316: * @return the HTTPHeaders providing information that controls
1317: * method execution.
1318: * @exception com.ibm.webdav.WebDAVException
1319: */
1320: public HTTPHeaders getRequestContext() throws WebDAVException {
1321: return context.getRequestContext();
1322: }
1323:
1324: /** Get the response context for this resource. The context contains information
1325: * returned from invocations of methods on a resource.
1326: *
1327: * @return the HTTPHeaders providing information that
1328: * is returned by method execution.
1329: * @exception com.ibm.webdav.WebDAVException
1330: */
1331: public HTTPHeaders getResponseContext() throws WebDAVException {
1332: return context.getResponseContext();
1333: }
1334:
1335: /**
1336: * Insert the method's description here.
1337: * Creation date: (4/13/2000 8:53:11 PM)
1338: * @return com.ibm.webdav.WebDAVStatus
1339: */
1340: public com.ibm.webdav.WebDAVStatus getStatusCode() {
1341: return context.getStatusCode();
1342: }
1343:
1344: /** Get the name that identifies this resource.
1345: *
1346: * @return the URL for this resource
1347: * @exception com.ibm.webdav.WebDAVException
1348: */
1349: public URL getURL() throws WebDAVException {
1350: return url;
1351: }
1352:
1353: /** Is this resource locked with the given lock token?
1354: * @param lockToken the lock token to check for
1355: * @exception com.ibm.webdav.WebDAVException
1356: */
1357: protected boolean hasLock(String lockToken) throws WebDAVException {
1358: boolean hasLock = false;
1359: Enumeration locks = getLocks().elements();
1360:
1361: while (!hasLock && locks.hasMoreElements()) {
1362: ActiveLock lock = (ActiveLock) locks.nextElement();
1363: hasLock = lock.getLockToken().equals(lockToken);
1364: }
1365:
1366: return hasLock;
1367: }
1368:
1369: /** Check for a valid URI
1370: * @return true if this resource has a valid URI
1371: * @exception com.ibm.webdav.WebDAVException
1372: */
1373: public boolean hasValidURI() throws WebDAVException {
1374: return getName() != null;
1375: }
1376:
1377: /** Inherit all deep locks on the parent of this resource.
1378: * @exception com.ibm.webdav.WebDAVException
1379: */
1380: protected void inheritParentDeepLocks() throws WebDAVException {
1381: CollectionImpl parent = (CollectionImpl) getParentCollection();
1382:
1383: Enumeration parentLocks = parent.getLocks().elements();
1384:
1385: while (parentLocks.hasMoreElements()) {
1386: ActiveLock parentLock = (ActiveLock) parentLocks
1387: .nextElement();
1388:
1389: if (parentLock.getDepth().equals(Collection.deep)) {
1390: if (!hasLock(parentLock.getLockToken())) {
1391: lock(parentLock);
1392: }
1393: }
1394: }
1395: }
1396:
1397: /** Returns true if this Resource is a collection. Returns false otherwise.
1398: *
1399: * @return true if this Resource is a collection.
1400: * @exception com.ibm.webdav.WebDAVException
1401: */
1402: public boolean isCollection() throws WebDAVException {
1403: return namespaceManager.isCollection();
1404: }
1405:
1406: /** See if this resource is locked.
1407: *
1408: * @return true if this resource is locked, false otherwise.
1409: * @exception com.ibm.webdav.WebDAVException
1410: */
1411: public boolean isLocked() throws WebDAVException {
1412: // see if there are any active locks
1413: return !getLocks().isEmpty();
1414: }
1415:
1416: /** Is this resource locked by the current authorized user? That is, does the
1417: * current user have sufficient locking access to modify this resource. The
1418: * method, like all methods that do modify the resource, must have a precondition
1419: * set in the context containing the lock token of the resource owned by this
1420: * user. The user is set in the request context using the authorization method.
1421: * @return true if this resource is locked by the principal in the context
1422: * sufficient to modify the resource.
1423: * @exception com.ibm.webdav.WebDAVException
1424: * @see com.ibm.webdav.ResourceContext#authorization
1425: */
1426: public boolean isLockedByMe() throws WebDAVException {
1427: String principal = getRequestContext().getAuthorizationId();
1428: Precondition precondition = getRequestContext().precondition();
1429:
1430: if (precondition == null) {
1431: return false; // it is not locked by me, or the server doesn't know
1432:
1433: //throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST, "Missing If header containing lock token");
1434: }
1435:
1436: // get the locks on this resource
1437: Enumeration locks = getLocks().elements();
1438: boolean isLockedByMe = false;
1439:
1440: // look for a matching lock
1441: while (locks.hasMoreElements()) {
1442: ActiveLock activeLock = (ActiveLock) locks.nextElement();
1443: Condition condition = new Condition(getURL().getFile());
1444: ConditionTerm term = new ConditionTerm();
1445: StateToken stateToken = new StateToken(activeLock
1446: .getLockToken());
1447: term.addConditionFactor(stateToken);
1448: condition.addConditionTerm(term);
1449:
1450: if (precondition.matches(condition)
1451: && activeLock.getPrincipal().equals(principal)
1452: && activeLock.getLockType().equals(
1453: ActiveLock.writeLock)) {
1454: isLockedByMe = true;
1455:
1456: break;
1457: }
1458: }
1459:
1460: return isLockedByMe;
1461: }
1462:
1463: /** See if the target URL has the same host and port (e.g., the same server)
1464: * as this resource. Matches on the host name, not its Internet address.
1465: *
1466: * @target the URL of the target resource
1467: *
1468: * @return true if the target is supported by the same server
1469: */
1470: public boolean isSameServerAs(URL target) {
1471: return target.getHost().equals(url.getHost())
1472: && (target.getPort() == url.getPort());
1473: }
1474:
1475: /** Load properties from the properties manager and update live properties.
1476: *
1477: * @return an XML document containing a properties element.
1478: * @exception com.ibm.webdav.WebDAVException
1479: */
1480: public Document loadProperties() throws WebDAVException {
1481: Document propertiesDocument = propertiesManager
1482: .loadProperties();
1483: updateLiveProperties(propertiesDocument);
1484: if (propertiesManager instanceof VersionedPropertiesManager) {
1485: if (((VersionedNamespaceManager) namespaceManager)
1486: .isVersioned() == true) {
1487: ((VersionedPropertiesManager) propertiesManager)
1488: .updateVersionProperties(propertiesDocument);
1489: }
1490: }
1491:
1492: return propertiesDocument;
1493: }
1494:
1495: /** Lock this resource with the information contained in the given active lock.
1496: * @param activeLock information about the lock
1497: * @return a MultiStatus containing a lockdiscovery property indicating
1498: * @exception com.ibm.webdav.WebDAVException
1499: */
1500: protected MultiStatus lock(ActiveLock activeLock)
1501: throws WebDAVException {
1502: // get the locks on this resource
1503: Enumeration locks = getLocks().elements();
1504:
1505: while (locks.hasMoreElements()) {
1506: ActiveLock lock = (ActiveLock) locks.nextElement();
1507:
1508: if (lock.getScope().equals(ActiveLock.exclusive)) {
1509: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
1510: "Resource has an exclusive lock");
1511: }
1512:
1513: if (lock.getScope().equals(ActiveLock.shared)
1514: && activeLock.getScope().equals(
1515: ActiveLock.exclusive)) {
1516: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
1517: "Resource already has a shared lock");
1518: }
1519:
1520: if (lock.getScope().equals(ActiveLock.shared)
1521: && lock.getPrincipal().equals(
1522: activeLock.getPrincipal())) {
1523: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
1524: "The principal already has a lock on this resource");
1525: }
1526: }
1527:
1528: return lockManager.lock(activeLock);
1529: }
1530:
1531: /** Lock this resource based on the given parameters. This allows control of
1532: * the lock scope (exclusive or shared) the lock type (write), owner information, etc.
1533: *
1534: * @param scope the scope of the lock, exclusive or shared
1535: * @param type the type of the lock, currently only write
1536: * @param timeout the number of seconds before the lock times out or
1537: * -1 for infinite timeout.
1538: * @param owner an XML element containing useful information that can be
1539: * used to identify the owner of the lock. An href to a home page, an
1540: * email address, phone number, etc. Can be null if no owner information
1541: * is provided.
1542: *
1543: * @return a MultiStatus containing a lockdiscovery property indicating
1544: * the results of the lock operation.
1545: * @exception com.ibm.webdav.WebDAVException
1546: */
1547: public MultiStatus lock(ResourceContext context, String scope,
1548: String type, int timeout, Element owner)
1549: throws WebDAVException {
1550: this .context = context;
1551:
1552: ActiveLock activeLock = getActiveLockFor(scope, type, timeout,
1553: owner);
1554: MultiStatus result = lock(activeLock);
1555:
1556: // return the granted lock token in the lockToken response context
1557: getResponseContext().lockToken(activeLock.getLockToken());
1558: getResponseContext().contentType("text/xml");
1559:
1560: return result;
1561: }
1562:
1563: /** Startup an RMI server for a ResourceImpl. The URL would most likely be for
1564: * some root WebDAV collection corresponding to the doc.root of a typical web
1565: * server. The resource identified by the URL must exist.
1566: * @param args root URL, its local file pathname
1567: */
1568: public static void main(String[] args) {
1569: // get the URL of the resource to export
1570: if (args.length != 2) {
1571: System.err
1572: .println("Usage: java ResourceImpl url localName");
1573: System.exit(-1);
1574: }
1575:
1576: // Create a ResourceImpl, export it, and bind it in the RMI Registry
1577: try {
1578: URL url = new URL(args[0]);
1579: String localName = args[1];
1580:
1581: // Create and install a security manager
1582: System.setSecurityManager(new RMISecurityManager());
1583:
1584: ResourceImpl resource = ResourceImpl.create(url, localName);
1585:
1586: // strip the protocol off the URL for the registered name
1587: String name = url.toString();
1588: name = name.substring(name.indexOf(":") + 1);
1589: Naming.rebind(name, resource);
1590:
1591: } catch (Exception exc) {
1592: System.err.println("ResourceImpl error: "
1593: + exc.getMessage());
1594: exc.printStackTrace();
1595: System.exit(-1);
1596: }
1597: } // main
1598:
1599: public MultiStatus createBinding(ResourceContext context,
1600: String bindName, String resourceURI) throws WebDAVException {
1601: this .context = context;
1602:
1603: setStatusCode(WebDAVStatus.SC_CREATED);
1604:
1605: MultiStatus result = new MultiStatus();
1606:
1607: try {
1608: // validate the uri
1609: if (!hasValidURI()) {
1610: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
1611: "Invalid URI");
1612: }
1613:
1614: // make sure the resource exists
1615: if (!exists()) {
1616: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
1617: "Cannot copy a lock-null resource");
1618: }
1619:
1620: //make sure the resource is a collection
1621: if (isCollection() == false) {
1622: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
1623: "URI indentified in BIND request must be an existing collection");
1624: }
1625:
1626: // the destination may be a relative URL
1627: StringBuffer strbuf = new StringBuffer();
1628: strbuf.append(url.toExternalForm());
1629:
1630: if (strbuf.toString().endsWith("/") == false) {
1631: strbuf.append("/");
1632: }
1633: strbuf.append(bindName);
1634:
1635: Resource destination = new Resource(strbuf.toString());
1636:
1637: Resource bindSource = new Resource(resourceURI);
1638:
1639: // are the source and destination the same?
1640: if (bindSource.equals(destination)) {
1641: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
1642: "Can't copy source on top of itself");
1643: }
1644:
1645: destination.getRequestContext().precondition(
1646: getRequestContext().precondition());
1647: destination.getRequestContext().authorization(
1648: getRequestContext().authorization());
1649:
1650: if (destination.exists()) {
1651: throw new WebDAVException(
1652: WebDAVStatus.SC_PRECONDITION_FAILED,
1653: "Destination exists and overwrite not specified");
1654: }
1655:
1656: this .namespaceManager.createBinding(bindName, new URL(
1657: resourceURI));
1658:
1659: // everything must have gone OK, there
1660: // is no response for a successful delete
1661: getResponseContext().contentType("text/xml");
1662: } catch (WebDAVException exc) {
1663: throw exc;
1664: } catch (java.net.MalformedURLException exc) {
1665: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
1666: "Malformed URL");
1667: } catch (java.io.IOException exc) {
1668: throw new WebDAVException(
1669: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
1670: }
1671:
1672: return result;
1673: }
1674:
1675: /** Move this resource to the destination URL.
1676: * Partial results are possible, check the returned status for details
1677: *
1678: * @param destinationURL the destination
1679: * @param overwrite true implies overrite the destination if it exists
1680: * @param propertiesToMove a collection of properties that must be moved or
1681: * the method will fail. propertiesToMove may have one of the following values:
1682: * <ul>
1683: * <li>null - ignore properties that cannot be moved</li>
1684: * <li>empty collection - all properties must be moved or the method will fail</li>
1685: * <li>a collection of URIs - a list of the properties that must be moved
1686: * or the method will fail</li>
1687: * </ul>
1688: *
1689: * @return the status of the move operation for each resource moved
1690: * @exception com.ibm.webdav.WebDAVException
1691: */
1692: public MultiStatus move(ResourceContext context,
1693: String destinationURL, boolean overwrite,
1694: Vector propertiesToMove) throws WebDAVException {
1695: this .context = context;
1696:
1697: MultiStatus result = new MultiStatus();
1698:
1699: if (webdavProperties.getProperty("atomicmove")
1700: .equalsIgnoreCase("true")) {
1701:
1702: // check to see if the resource is locked by another user
1703: if (isLocked() && !isLockedByMe()) {
1704: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
1705: "Resource is locked by another user");
1706: }
1707:
1708: result = atomicMove(context, destinationURL, overwrite);
1709:
1710: Enumeration propertyNames = context.getResponseContext()
1711: .keys();
1712: } else {
1713: // proceed with the move even if the source is locked by
1714: // another principal. Best effort will perform the copy but
1715: // not the delete.
1716: result = copy(context, destinationURL, overwrite,
1717: propertiesToMove);
1718:
1719: ResourceContext copyContext = context;
1720: WebDAVStatus oldStatus = context.getStatusCode();
1721: result.mergeWith(delete(context));
1722:
1723: if (getStatusCode().getStatusCode() == 204) {
1724: // it was a clean delete that doesn't affect the
1725: // final result code.
1726: context.setStatusCode(oldStatus);
1727: }
1728:
1729: Enumeration propertyNames = copyContext
1730: .getResponseContext().keys();
1731:
1732: while (propertyNames.hasMoreElements()) {
1733: String name = (String) propertyNames.nextElement();
1734: String value = (String) copyContext
1735: .getResponseContext().get(name);
1736:
1737: if (!context.getResponseContext().containsKey(name)) {
1738: getResponseContext().put(name, value);
1739: }
1740: }
1741: }
1742:
1743: getResponseContext().contentType("text/xml");
1744:
1745: return result;
1746: }
1747:
1748: /** Is the parent of this resource depth locked with the given lock token?
1749: * @param lockToken the lock token to check
1750: * @return true if the parant of this resource is locked with the lock token
1751: * @exception com.ibm.webdav.WebDAVException
1752: */
1753: public boolean parentIsLockedWith(String lockToken)
1754: throws WebDAVException {
1755: // get the locks on the parent of this resource
1756: boolean isLocked = false;
1757: CollectionImpl parent = null;
1758:
1759: try {
1760: parent = (CollectionImpl) getParentCollection();
1761: } catch (Exception exc) {
1762: }
1763:
1764: if (parent != null) {
1765: Enumeration locks = parent.getLocks().elements();
1766:
1767: // look for a matching lock
1768: while (locks.hasMoreElements()) {
1769: ActiveLock activeLock = (ActiveLock) locks
1770: .nextElement();
1771:
1772: if (activeLock.getLockToken().equals(lockToken)) {
1773: isLocked = true;
1774:
1775: break;
1776: }
1777: }
1778: }
1779:
1780: return isLocked;
1781: }
1782:
1783: /** This method treats this resource as a method or service, and sends its parameter to
1784: * this resource where it is handled in a resource-specific way. For example,
1785: * sending data from an HTML form to a URL representing a Servlet or CGI script that processes
1786: * the form data to produce some result.
1787: *
1788: * @param args a string representing the arguments to the method represented by this URL. The
1789: * arguments are in the form ?parameterName1=value1&parameterName2=value2... as specified
1790: * for URL queries.
1791: *
1792: * @return the results of sending the arguments to the URL
1793: * @exception com.ibm.webdav.WebDAVException
1794: */
1795: public byte[] performWith(ResourceContext context, String args)
1796: throws WebDAVException {
1797: this .context = context;
1798:
1799: return namespaceManager.performWith(args);
1800: }
1801:
1802: /** Refresh the lock on this resource by resetting the lock timeout.
1803: * The context must contain the proper authorization for the requesting
1804: * principal.
1805: *
1806: * @param lockToken the lock token identifying the lock.
1807: * @param timeout the new timeout in seconds. -1 means infinite timeout.
1808: *
1809: * @return updated information about the lock status of this resource
1810: * @exception com.ibm.webdav.WebDAVException
1811: */
1812: public MultiStatus refreshLock(ResourceContext context,
1813: String lockToken, int timeout) throws WebDAVException {
1814: this .context = context;
1815:
1816: String principal = getRequestContext().getAuthorizationId();
1817:
1818: // find the lock
1819: ActiveLock lockToRefresh = null;
1820: Enumeration activeLocks = getLocks().elements();
1821:
1822: while (activeLocks.hasMoreElements()) {
1823: ActiveLock activeLock = (ActiveLock) activeLocks
1824: .nextElement();
1825:
1826: if (activeLock.getLockToken().equals(lockToken)
1827: && (activeLock.getPrincipal().equals(principal)
1828: || principal.equals("root") || ResourceImpl.authenticator
1829: .isSuperUser(this ) == true)) {
1830: lockToRefresh = activeLock;
1831:
1832: break;
1833: }
1834: }
1835:
1836: if (lockToRefresh == null) {
1837: throw new WebDAVException(
1838: WebDAVStatus.SC_PRECONDITION_FAILED,
1839: "principal does not own a lock");
1840: }
1841:
1842: // finally, reset the lock.
1843: lockToRefresh.setTimeout(timeout);
1844: getResponseContext().contentType("text/xml");
1845:
1846: return lockManager.refreshLock(lockToRefresh);
1847: }
1848:
1849: /** Remove the live DAV properties from the properties document. There is no
1850: * reason to save them as they are recalculated each time the properties are
1851: * loaded.
1852: * @param propertiesDocument an XML document containing the current resource properties
1853: */
1854: public void removeLiveProperties(Document propertiesDocument) {
1855: Element properties = (Element) propertiesDocument
1856: .getDocumentElement();
1857: Element p = null;
1858: p = (Element) ((Element) properties).getElementsByTagNameNS(
1859: "DAV:", "supportedlock").item(0);
1860:
1861: if (p != null) {
1862: properties.removeChild(p);
1863: }
1864:
1865: // remove the live properties that are repository specific
1866: propertiesManager.removeLiveProperties(propertiesDocument);
1867: }
1868:
1869: /** Save the properties after removing any live properties that don't need
1870: * to be saved.
1871: * @param propertiesDocument an XML document containing the resource's properties
1872: * @exception com.ibm.webdav.WebDAVException
1873: */
1874: public void saveProperties(Document propertiesDocument)
1875: throws WebDAVException {
1876: // don't save the live properties, they will be recalculated on each load
1877: removeLiveProperties(propertiesDocument);
1878: if (propertiesManager instanceof VersionedPropertiesManager) {
1879: // don't save versoined properties, they will be recalculated on each load
1880: ((VersionedPropertiesManager) propertiesManager)
1881: .removeVersionProperties(propertiesDocument);
1882: }
1883:
1884: propertiesManager.saveProperties(propertiesDocument);
1885: }
1886:
1887: /** Set the contents of this resource. This may create a new resource on the server,
1888: * or update the contents of an existing resource. Sufficient authorization is required
1889: * and administered by the target web server. For text/* MIME types, the caller should
1890: * be sure to convert Strings to byte codes using an acceptable charset, and to set
1891: * that charset in the request context so the server knows how to decode the byte
1892: * stream.
1893: *
1894: * @param value the new contents for the resource
1895: * @exception com.ibm.webdav.WebDAVException
1896: */
1897: public void setContents(byte[] value) throws WebDAVException {
1898: BufferedOutputStream os = (BufferedOutputStream) getContentsOutputStream(context);
1899:
1900: for (int i = 0; i < value.length; i++) {
1901: try {
1902: os.write(value[i]);
1903: } catch (WebDAVException exc) {
1904: throw exc;
1905: } catch (java.io.IOException exc) {
1906: throw new WebDAVException(
1907: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
1908: "IO Error");
1909: }
1910: }
1911:
1912: closeContentsOutputStream(context);
1913: }
1914:
1915: /**
1916: * Insert the method's description here.
1917: * Creation date: (4/14/2000 4:14:55 PM)
1918: * @param newContext com.ibm.webdav.ResourceContext
1919: */
1920: void setContext(com.ibm.webdav.ResourceContext newContext) {
1921: context = newContext;
1922: }
1923:
1924: /** Edit the properties of a resource. The updates must refer to a Document containing a WebDAV
1925: * DAV:propertyupdates element as the document root.
1926: *
1927: * @param updates an XML Document containing DAV:propertyupdate elements
1928: * describing the edits to be made
1929: * @return a MultiStatus indicating the status of the updates
1930: * @exception com.ibm.webdav.WebDAVException
1931: */
1932: public MultiStatus setProperties(ResourceContext context,
1933: Document updates) throws WebDAVException {
1934: this .context = context;
1935:
1936: // make sure the resource exists.
1937: if (!exists()) {
1938: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
1939: "Resource does not exist");
1940: }
1941:
1942: // check to see if the resource is locked by another user
1943: if (isLocked() && !isLockedByMe()) {
1944: return createPropPatchMultiStatus(new WebDAVException(
1945: WebDAVStatus.SC_LOCKED,
1946: "Resource is locked by another user"), updates);
1947: }
1948:
1949: getResponseContext().contentType("text/xml");
1950:
1951: return propertiesManager.setProperties(updates);
1952: }
1953:
1954: /**
1955: * Insert the method's description here.
1956: * Creation date: (4/13/2000 8:48:11 PM)
1957: * @param newRequestContext com.ibm.webdav.ResourceContext
1958: */
1959: public void setRequestContext(ResourceContext newRequestContext) {
1960: context
1961: .setRequestContext(newRequestContext
1962: .getRequestContext());
1963: }
1964:
1965: /**
1966: * Insert the method's description here.
1967: * Creation date: (4/13/2000 8:48:11 PM)
1968: * @param newResponseContext com.ibm.webdav.ResourceContext
1969: */
1970: public void setResponseContext(
1971: com.ibm.webdav.ResourceContext newResponseContext) {
1972: context.setResponseContext(newResponseContext
1973: .getResponseContext());
1974: }
1975:
1976: /**
1977: * Insert the method's description here.
1978: * Creation date: (4/13/2000 8:53:11 PM)
1979: * @param newStatusCode com.ibm.webdav.WebDAVStatus
1980: */
1981: void setStatusCode(int newStatusCode) {
1982: context.getStatusCode().setStatusCode(newStatusCode);
1983: }
1984:
1985: /**
1986: * Insert the method's description here.
1987: * Creation date: (4/13/2000 8:53:11 PM)
1988: * @param newStatusCode com.ibm.webdav.WebDAVStatus
1989: */
1990: void setStatusCode(com.ibm.webdav.WebDAVStatus newStatusCode) {
1991: context.getStatusCode().setStatusCode(
1992: newStatusCode.getStatusCode());
1993: }
1994:
1995: /** Translate the URI reference relative to this resource in order to obtain
1996: * the real path name if the URI references a resource on the same machine.
1997: *
1998: * @param target the URL of the path to translate
1999: *
2000: * @return the pathname to the file on this machine, or the URL if the file
2001: * is not on this machine
2002: * @exception com.ibm.webdav.WebDAVException
2003: */
2004: public String translatePathRelativeToMe(String target)
2005: throws WebDAVException {
2006: String result = target;
2007: URL targetURL = null;
2008:
2009: try {
2010: targetURL = new URL(url, target);
2011: } catch (java.net.MalformedURLException exc) {
2012: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2013: "malformed target URL");
2014: }
2015:
2016: if (targetURL.getHost().equals(url.getHost())) {
2017: // is on this machine, convert the target to a file on this machine
2018: result = targetURL.getFile().replace('/',
2019: File.separatorChar);
2020:
2021: // append it to doc.root
2022: String uri = url.getFile();
2023: String docRoot = fileName.substring(0, fileName.length()
2024: - uri.length());
2025: result = docRoot + result;
2026: }
2027:
2028: return result;
2029: }
2030:
2031: /** Unlock the lock identified by the lockToken on this resource
2032: *
2033: * @param lockToken the lock token obtained from the ActiveLock of a previous <code>lock() </code>
2034: * or <code>getLocks()</code>.
2035: *
2036: * @return a MultiStatus containing any responses on resources that could not
2037: * be unlocked.
2038: * @exception com.ibm.webdav.WebDAVException
2039: */
2040: public MultiStatus unlock(ResourceContext context, String lockToken)
2041: throws WebDAVException {
2042: this .context = context;
2043:
2044: // first, is this the root parent collection locked by this lockToken
2045: if (parentIsLockedWith(lockToken)) {
2046: throw new WebDAVException(
2047: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2048: "Must unlock depth lock from root collection having the lock.");
2049: }
2050:
2051: MultiStatus result = doUnlock(lockToken);
2052: setStatusCode(WebDAVStatus.SC_NO_CONTENT); // the default status code
2053:
2054: return result;
2055: }
2056:
2057: /** Update live properties that are supported by this server. This method
2058: * updates those that are not unique to any repository implementation.
2059: * This is mostly the live DAV properties as defined in the WebDAV spec.
2060: * @param document an XML document containing the resource properties
2061: * @exception com.ibm.webdav.WebDAVException
2062: */
2063: public void updateLiveProperties(Document document)
2064: throws WebDAVException {
2065: Element properties = document.getDocumentElement();
2066:
2067: // remove any live properties that need to be recalculated
2068: removeLiveProperties(document);
2069:
2070: // now recalculate the live properties, the repository independent ones first
2071: Enumeration liveprops = liveProperties.elements();
2072:
2073: while (liveprops.hasMoreElements()) {
2074: LiveProperty liveProperty = (LiveProperty) liveprops
2075: .nextElement();
2076: PropertyValue value = liveProperty.getValueFor(this );
2077: Element e = (Element) ((Element) properties)
2078: .getElementsByTagNameNS(liveProperty.getNSName(),
2079: liveProperty.getNSLocalName()).item(0);
2080:
2081: if ((e != null) && (value != null)
2082: && (value.getValue() != null)) {
2083: properties.removeChild(e);
2084: }
2085:
2086: if ((value != null) && (value.getValue() != null)) {
2087: properties.appendChild(value.getValue());
2088: } else {
2089: // put in an empty element
2090: e = document.createElementNS(liveProperty.getNSName(),
2091: liveProperty.getPreferredPrefix() + ":"
2092: + liveProperty.getNSLocalName());
2093:
2094: e.setAttribute("xmlns:"
2095: + liveProperty.getPreferredPrefix(),
2096: liveProperty.getNSName());
2097: properties.appendChild(e);
2098: }
2099:
2100: // TODO: missing status
2101: }
2102:
2103: // lockdiscovery
2104:
2105: /*
2106: Element lockdiscovery = (TXElement) lockManager.getLockDiscovery();
2107: Element l = ((TXElement) properties).getElementNamed("DAV:", "lockdiscovery");
2108: if (l != null && lockdiscovery != null) {
2109: properties.removeChild(l);
2110: }
2111: properties.appendChild(lockdiscovery);
2112: */
2113:
2114: // creationdate
2115: Element creationDate = (Element) ((Element) properties)
2116: .getElementsByTagNameNS("DAV:", "creationdate").item(0);
2117:
2118: if (creationDate == null) {
2119: creationDate = document.createElementNS("DAV:",
2120: "D:creationdate");
2121:
2122: String cdstring = new SimpleISO8601DateFormat()
2123: .format(new java.util.Date());
2124: creationDate.appendChild(document.createTextNode(cdstring));
2125: properties.appendChild(creationDate);
2126: }
2127:
2128: // displayname - set the default. Subclasses may want to override
2129: Element displayName = (Element) ((Element) properties)
2130: .getElementsByTagNameNS("DAV:", "displayname").item(0);
2131:
2132: if (displayName == null) {
2133: displayName = document.createElementNS("DAV:",
2134: "D:displayname");
2135:
2136: displayName.appendChild(document.createTextNode(URLEncoder
2137: .encode(getName())));
2138: properties.appendChild(displayName);
2139: }
2140:
2141: // get the supportedlock element from the lock manager
2142: properties.appendChild(document.importNode(lockManager
2143: .getSupportedLock(), true));
2144:
2145: // do the ones that are repository specific
2146: propertiesManager.updateLiveProperties(document);
2147: }
2148:
2149: /**
2150: * Checks in current resource
2151: *
2152: * @throws WebDAVException
2153: */
2154: public void checkin() throws WebDAVException {
2155: if (namespaceManager instanceof VersionedNamespaceManager) {
2156: // validate the uri
2157: if (hasValidURI() == false) {
2158: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2159: "Invalid URI");
2160: }
2161:
2162: // make sure the resource exists
2163: if (exists() == false) {
2164: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
2165: "Cannot copy a lock-null resource");
2166: }
2167:
2168: if (((VersionedNamespaceManager) namespaceManager)
2169: .isCheckedOutVersion() == false) {
2170: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2171: "Not checked out");
2172: }
2173:
2174: // check to see if the resource is locked by another user
2175: if (isLocked() && !isLockedByMe()) {
2176: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
2177: "Resource is locked by another user");
2178: }
2179:
2180: String sLoc = ((VersionedNamespaceManager) namespaceManager)
2181: .checkin();
2182: context.getResponseContext().location(sLoc);
2183: setStatusCode(WebDAVStatus.SC_CREATED);
2184: } else {
2185: throw new WebDAVException(
2186: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2187: "Repository does not support this method");
2188: }
2189: }
2190:
2191: /**
2192: * Checks out the current resource
2193: *
2194: * @throws WebDAVException
2195: */
2196: public void checkout() throws WebDAVException {
2197: if (namespaceManager instanceof VersionedNamespaceManager) {
2198: // validate the uri
2199: if (hasValidURI() == false) {
2200: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2201: "Invalid URI");
2202: }
2203:
2204: // make sure the resource exists
2205: if (exists() == false) {
2206: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
2207: "Cannot copy a lock-null resource");
2208: }
2209:
2210: // check to see if the resource is locked by another user
2211: if (isLocked() && !isLockedByMe()) {
2212: throw new WebDAVException(WebDAVStatus.SC_LOCKED,
2213: "Resource is locked by another user");
2214: }
2215:
2216: ((VersionedNamespaceManager) namespaceManager).checkout();
2217: setStatusCode(WebDAVStatus.SC_OK);
2218: } else {
2219: throw new WebDAVException(
2220: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2221: "Repository does not support this method");
2222: }
2223: }
2224:
2225: /**
2226: * Get the named properties for all versions of this resource.
2227: *
2228: * @param context
2229: * @param names an array of PropertyNames to retrieve.
2230: *
2231: * @return
2232: * @throws WebDAVException
2233: */
2234: public MultiStatus getVersionTreeReport(ResourceContext context,
2235: PropertyName[] names) throws WebDAVException {
2236: this .context = context;
2237:
2238: // check the depth parameter
2239: if (namespaceManager.isVersionable() == false) {
2240: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2241: "Invalid depth on copy");
2242: }
2243: MultiStatus result = new MultiStatus();
2244: // now get the properties of the versions if necessary
2245:
2246: Iterator memberIter = ((VersionedNamespaceManager) namespaceManager)
2247: .getVersions().iterator();
2248: while (memberIter.hasNext()) {
2249: ResourceImpl member = (ResourceImpl) memberIter.next();
2250: try {
2251: MultiStatus memberResult = member.getProperties(
2252: context, names);
2253:
2254: result.mergeWith(memberResult);
2255: } catch (WebDAVException exc) {
2256: MethodResponse response = new MethodResponse(member
2257: .getURL().toString(), exc.getStatusCode());
2258: result.addResponse(response);
2259: } catch (Exception e) {
2260: e.printStackTrace();
2261: throw new WebDAVException(
2262: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
2263: "unable to delete resource");
2264: }
2265: }
2266:
2267: getResponseContext().contentType("text/xml");
2268: return result;
2269:
2270: }
2271:
2272: /**
2273: * Get the properties for all versions of this resource.
2274: *
2275: * @param context
2276: * @return
2277: * @throws WebDAVException
2278: */
2279: public MultiStatus getVersionTreeReport(ResourceContext context)
2280: throws WebDAVException {
2281: this .context = context;
2282:
2283: // check the depth parameter
2284: if (namespaceManager.isVersionable() == false) {
2285: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2286: "Invalid depth on copy");
2287: }
2288: MultiStatus result = new MultiStatus();
2289: // now get the properties of the versions if necessary
2290:
2291: Iterator memberIter = ((VersionedNamespaceManager) namespaceManager)
2292: .getVersions().iterator();
2293: while (memberIter.hasNext()) {
2294: ResourceImpl member = (ResourceImpl) memberIter.next();
2295: try {
2296: MultiStatus memberResult = member
2297: .getProperties(context);
2298:
2299: result.mergeWith(memberResult);
2300: } catch (WebDAVException exc) {
2301: MethodResponse response = new MethodResponse(member
2302: .getURL().toString(), exc.getStatusCode());
2303: result.addResponse(response);
2304: } catch (Exception e) {
2305: e.printStackTrace();
2306: throw new WebDAVException(
2307: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
2308: "unable to delete resource");
2309: }
2310: }
2311:
2312: getResponseContext().contentType("text/xml");
2313: return result;
2314:
2315: }
2316:
2317: /**
2318: *
2319: */
2320: public void uncheckout() throws WebDAVException {
2321: if (namespaceManager instanceof VersionedNamespaceManager) {
2322: // validate the uri
2323: if (hasValidURI() == false) {
2324: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2325: "Invalid URI");
2326: }
2327:
2328: // make sure the resource exists
2329: if (exists() == false) {
2330: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
2331: "Cannot copy a lock-null resource");
2332: }
2333:
2334: if (((VersionedNamespaceManager) namespaceManager)
2335: .isCheckedOutVersion() == false) {
2336: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2337: "Not checked out");
2338: }
2339:
2340: ((VersionedNamespaceManager) namespaceManager).uncheckout();
2341: setStatusCode(WebDAVStatus.SC_OK);
2342: } else {
2343: throw new WebDAVException(
2344: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2345: "Repository does not support this method");
2346: }
2347:
2348: }
2349:
2350: /**
2351: *
2352: */
2353: public void versionControl() throws WebDAVException {
2354: if (namespaceManager instanceof VersionedNamespaceManager) {
2355: // validate the uri
2356: if (hasValidURI() == false) {
2357: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2358: "Invalid URI");
2359: }
2360:
2361: // make sure the resource exists
2362: if (exists() == false) {
2363: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
2364: "Cannot copy a lock-null resource");
2365: }
2366:
2367: if (((VersionedNamespaceManager) namespaceManager)
2368: .isVersioned() == true) {
2369: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
2370: "Already versioned");
2371: }
2372:
2373: ((VersionedNamespaceManager) namespaceManager)
2374: .versionControl();
2375: setStatusCode(WebDAVStatus.SC_OK);
2376: } else {
2377: throw new WebDAVException(
2378: WebDAVStatus.SC_METHOD_NOT_ALLOWED,
2379: "Repository does not support this method");
2380: }
2381:
2382: }
2383:
2384: /**
2385: * @return
2386: */
2387: public List getAllowedMethods() throws WebDAVException {
2388:
2389: return namespaceManager.getAllowedMethods();
2390: }
2391:
2392: /* (non-Javadoc)
2393: * @see com.ibm.webdav.impl.IRResource#closeContentsOutputStream(com.ibm.webdav.ResourceContext, java.lang.String)
2394: */
2395: public void closeContentsOutputStream(ResourceContext context,
2396: String sContentType) throws WebDAVException {
2397: this .context = context;
2398:
2399: if (sContentType == null) {
2400: namespaceManager.closeContentsOutputStream();
2401: } else {
2402: namespaceManager.closeContentsOutputStream(sContentType);
2403: }
2404:
2405: // update the live properties
2406: Document propertiesDocument = loadProperties();
2407: saveProperties(propertiesDocument);
2408:
2409: // inherit any deep locks on the parent collection
2410: inheritParentDeepLocks();
2411:
2412: }
2413: }
|