Return-Path: Delivered-To: apmail-incubator-jackrabbit-commits-archive@www.apache.org Received: (qmail 22126 invoked from network); 6 Mar 2005 14:03:16 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 6 Mar 2005 14:03:16 -0000 Received: (qmail 87804 invoked by uid 500); 6 Mar 2005 14:03:15 -0000 Mailing-List: contact jackrabbit-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: jackrabbit-dev@incubator.apache.org Delivered-To: mailing list jackrabbit-commits@incubator.apache.org Received: (qmail 87773 invoked by uid 500); 6 Mar 2005 14:03:14 -0000 Delivered-To: apmail-incubator-jackrabbit-cvs@incubator.apache.org Received: (qmail 87769 invoked by uid 99); 6 Mar 2005 14:03:14 -0000 X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from minotaur.apache.org (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.28) with SMTP; Sun, 06 Mar 2005 06:03:11 -0800 Received: (qmail 22069 invoked by uid 65534); 6 Mar 2005 14:03:10 -0000 Message-ID: <20050306140310.22066.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Mailer: svnmailer-1.0.0-dev Date: Sun, 06 Mar 2005 14:03:10 -0000 Subject: svn commit: r156314 [3/15] - in incubator/jackrabbit/trunk/contrib/jcr-server: ./ client/ client/src/ client/src/java/ client/src/java/org/ client/src/java/org/apache/ client/src/java/org/apache/jackrabbit/ client/src/java/org/apache/jackrabbit/client/ server/ server/src/ server/src/java/ server/src/java/org/ server/src/java/org/apache/ server/src/java/org/apache/jackrabbit/ server/src/java/org/apache/jackrabbit/server/ server/src/java/org/apache/jackrabbit/server/simple/ server/src/java/org/apache/jackrabbit/server/simple/dav/ server/src/java/org/apache/jackrabbit/server/simple/dav/lock/ server/src/java/org/apache/jackrabbit/webdav/ server/src/java/org/apache/jackrabbit/webdav/spi/ server/src/java/org/apache/jackrabbit/webdav/spi/lock/ server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/ server/src/java/org/apache/jackrabbit/webdav/spi/observation/ server/src/java/org/apache/jackrabbit/webdav/spi/search/ server/src/java/org/apache/jackrabbit/webdav/spi/transaction/ server/src/java/org/apache/jackrabbit/webdav/spi/version/ server/src/java/org/apache/jackrabbit/webdav/spi/version/report/ webapp/ webapp/src/ webapp/src/webapp/ webapp/src/webapp/WEB-INF/ webapp/src/webapp/WEB-INF/repository/ webdav/ webdav/src/ webdav/src/java/ webdav/src/java/org/ webdav/src/java/org/apache/ webdav/src/java/org/apache/jackrabbit/ webdav/src/java/org/apache/jackrabbit/webdav/ webdav/src/java/org/apache/jackrabbit/webdav/lock/ webdav/src/java/org/apache/jackrabbit/webdav/observation/ webdav/src/java/org/apache/jackrabbit/webdav/ordering/ webdav/src/java/org/apache/jackrabbit/webdav/property/ webdav/src/java/org/apache/jackrabbit/webdav/search/ webdav/src/java/org/apache/jackrabbit/webdav/transaction/ webdav/src/java/org/apache/jackrabbit/webdav/util/ webdav/src/java/org/apache/jackrabbit/webdav/version/ webdav/src/java/org/apache/jackrabbit/webdav/version/report/ To: jackrabbit-cvs@incubator.apache.org From: tripod@apache.org X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/server/simple/dav/DavResourceImpl.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/server/simple/dav/DavResourceIm= pl.java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/DavResourceImpl.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/DavResourceImpl.java Sun Mar 6 06:02:39 2005 @@ -0,0 +1,659 @@ +/* + * Copyright 2005 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.jackrabbit.server.simple.dav; + +import javax.jcr.*; +import java.util.*; +import java.io.*; + +import org.apache.jackrabbit.webdav.*; +import org.apache.jackrabbit.webdav.util.Text; +import org.apache.jackrabbit.webdav.spi.lock.JcrActiveLock; +import org.apache.jackrabbit.webdav.spi.JcrDavException; +import org.apache.jackrabbit.webdav.lock.*; +import org.apache.jackrabbit.webdav.property.*; + +/** + * DavResourceImpl imeplements a DavResource. + */ +public class DavResourceImpl implements DavResource { + + private DavResourceFactory factory; + private LockManager lockManager; + private DavSession session; + private Node node; + private DavResourceLocator locator; + + private DavPropertySet properties; + private boolean isCollection =3D true; + + /** is created on initProperties */ + private NodeResource nodeResource; + + /** + * Create a new {@link DavResource}. + * + * @param locator + * @param factory + * @param session + */ + public DavResourceImpl(DavResourceLocator locator, DavResourceFactory = factory, DavSession session) { + this.session =3D session; + this.factory =3D factory; + this.locator =3D locator; + if (locator !=3D null && locator.getResourcePath() !=3D null) { + try { + init(session.getRepositorySession().getItem(locator.getRes= ourcePath())); + } catch (RepositoryException e) { + // ignore: exists field evaluates to false + } + } + } + + /** + * Init the webdav resource and retrieve the relevant property. + * + * @param repositoryItem + * @throws RepositoryException + */ + private void init(Item repositoryItem) throws RepositoryException { + if (repositoryItem =3D=3D null || !repositoryItem.isNode()) { + return; + } + node =3D (Node)repositoryItem; + + // define what is a resource in webdav + if (node.isNodeType("nt:resource") || node.isNodeType("nt:file")) { + isCollection =3D false; + } + } + + /** + * @return DavResource#COMPLIANCE_CLASS + * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass() + */ + public String getComplianceClass() { + return DavResource.COMPLIANCE_CLASS; + } + + /** + * @return DavResource#METHODS + * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods() + */ + public String getSupportedMethods() { + return DavResource.METHODS; + } + + /** + * @see DavResource#exists() ) + */ + public boolean exists() { + return node !=3D null; + } + + /** + * @see DavResource#isCollection() + */ + public boolean isCollection() { + return isCollection; + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getLocator() + */ + public DavResourceLocator getLocator() { + return locator; + } + + /** + * @see DavResource#getResourcePath() + */ + public String getResourcePath() { + return locator.getResourcePath(); + } + + /** + * @see DavResource#getHref() + */ + public String getHref() { + return locator.getHref(isCollection()); + } + + /** + * @see DavResource#getDisplayName() + */ + public String getDisplayName() { + String name =3D null; + if (exists()) { + try { + name =3D node.getName(); + } catch (RepositoryException e) { + // ignore + } + } + if (name =3D=3D null && getResourcePath() !=3D null) { + name =3D Text.getLabel(getResourcePath()); + } + return name; + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getModificationTime() + */ + public long getModificationTime() { + initProperties(); + return nodeResource =3D=3D null ? 0 : nodeResource.getModificationTime(); + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getStream() + */ + public InputStream getStream() { + initProperties(); + return nodeResource =3D=3D null ? null : nodeResource.getStream(); + } + + /** + * @see DavResource#getProperty(org.apache.jackrabbit.webdav.property.= DavPropertyName) + */ + public DavProperty getProperty(DavPropertyName name) { + initProperties(); + return properties.get(name); + } + + /** + * @see DavResource#getProperties() + */ + public DavPropertySet getProperties() { + initProperties(); + return properties; + } + + /** + * @see DavResource#getPropertyNames() + */ + public DavPropertyName[] getPropertyNames() { + return getProperties().getPropertyNames(); + } + + /** + * Fill the set of properties + */ + private void initProperties() { + if (properties =3D=3D null && exists()) { + properties =3D new DavPropertySet(); + try { + nodeResource =3D new NodeResource(this, node); + properties.add(new DefaultDavProperty(DavPropertyName.GETC= ONTENTLENGTH, nodeResource.getContentLength()+"")); + properties.add(new DefaultDavProperty(DavPropertyName.CREA= TIONDATE, nodeResource.getCreationDate())); + properties.add(new DefaultDavProperty(DavPropertyName.GETL= ASTMODIFIED, nodeResource.getLastModified())); + String contentType =3D nodeResource.getContentType(); + if (contentType !=3D null) { + properties.add(new DefaultDavProperty(DavPropertyName.= GETCONTENTTYPE, contentType)); + } + properties.add(new DefaultDavProperty(DavPropertyName.GETE= TAG, nodeResource.getETag())); + } catch (RepositoryException e) { + // should not occure.... + } + + if (getDisplayName() !=3D null) { + properties.add(new DefaultDavProperty(DavPropertyName.DISP= LAYNAME, getDisplayName())); + } + if (isCollection()) { + properties.add(new ResourceType(ResourceType.COLLECTION)); + // Windows XP support + properties.add(new DefaultDavProperty(DavPropertyName.ISCO= LLECTION, "1")); + } else { + properties.add(new ResourceType(ResourceType.DEFAULT_RESOU= RCE)); + // Windows XP support + properties.add(new DefaultDavProperty(DavPropertyName.ISCO= LLECTION, "0")); + } + + /* set current lock information. If no lock is set to this res= ource, + an empty lockdiscovery will be returned in the response. */ + properties.add(new LockDiscovery(getLock(Type.WRITE, Scope.EXC= LUSIVE))); + + /* lock support information: all locks are lockable. */ + SupportedLock supportedLock =3D new SupportedLock(); + supportedLock.addEntry(Type.WRITE, Scope.EXCLUSIVE); + properties.add(supportedLock); + } + } + + /** + * @param property + * @throws DavException + * @see DavResource#setProperty(org.apache.jackrabbit.webdav.property.= DavProperty) + */ + public void setProperty(DavProperty property) throws DavException { + if (isLocked(this)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED); + } + + /** + * @param propertyName + * @throws DavException + * @see DavResource#removeProperty(org.apache.jackrabbit.webdav.proper= ty.DavPropertyName) + */ + public void removeProperty(DavPropertyName propertyName) throws DavExc= eption { + if (isLocked(this)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED); + } + + /** + * @see DavResource#getCollection() + */ + public DavResource getCollection() { + DavResource parent =3D null; + if (getResourcePath() !=3D null && !getResourcePath().equals("/"))= { + String parentPath =3D Text.getRelativeParent(getResourcePath()= , 1); + if (parentPath.equals("")) { + parentPath=3D"/"; + } + DavResourceLocator parentloc =3D locator.getFactory().createRe= sourceLocator(locator.getPrefix(), locator.getWorkspacePath(), parentPath); + try { + parent =3D factory.createResource(parentloc, session); + } catch (DavException e) { + // should not occur + } + } + return parent; + } + + /** + * @see DavResource#getMembers() + */ + public DavResourceIterator getMembers() { + ArrayList list =3D new ArrayList(); + if (exists() && isCollection()) { + try { + NodeIterator it =3D node.getNodes(); + while(it.hasNext()) { + list.add(buildResourceFromItem(it.nextNode())); + } + } catch (RepositoryException e) { + // should not occure + } catch (DavException e) { + // should not occure + } + } + return new DavResourceIteratorImpl(list); + } + + /** + * @see DavResource#addMember(DavResource, InputStream) + */ + public void addMember(DavResource member, InputStream in) throws DavEx= ception { + if (!exists() || in =3D=3D null) { + throw new DavException(DavServletResponse.SC_BAD_REQUEST); + } + + try { + String fileName =3D member.getDisplayName(); + Node file; + boolean makeVersionable =3D true; // todo: to be configurable somewhe= re + if (node.hasNode(fileName)) { + file =3D node.getNode(fileName); + if (file.hasNode("jcr:content")) { + // remove an existing repository entry for 'overwriting' is not poss= ible + file.getNode("jcr:content").remove(); + } + } else { + file =3D node.addNode(fileName, "nt:file"); + if (makeVersionable) { + file.addMixin("mix:versionable"); + } + } + + if (fileName.endsWith(".xml")) { + importXml(file, in, "text/xml"); + } else { + // todo: retrieve proper mimetype from filename + importFile(file, in, "application/octet-stream"); + } + session.getRepositorySession().save(); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } catch (IOException e) { + throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_E= RROR, e.getMessage()); + } + } + + /** + * Imports a xml into the repository + * @param parentNode + * @param in + * @param contentType + * @throws RepositoryException + * @throws IOException + */ + private void importXml(Node parentNode, InputStream in, String content= Type) + throws RepositoryException, IOException { + Node content =3D parentNode.addNode("jcr:content", "nt:unstructured"); + content.setProperty("jcr:mimeType", contentType); + content.setProperty("jcr:lastModified", Calendar.getInstance()); + session.getRepositorySession().importXML(content.getPath(), in); + } + + /** + * Imports a plain file to the repository + * @param parentNode + * @param in + * @param contentType + * @throws RepositoryException + */ + private void importFile(Node parentNode, InputStream in, String conten= tType) + throws RepositoryException { + Node content =3D parentNode.addNode("jcr:content", "nt:resource"); + content.setProperty("jcr:mimeType", contentType); + content.setProperty("jcr:encoding", ""); + content.setProperty("jcr:data", in); + content.setProperty("jcr:lastModified", Calendar.getInstance()); + } + + /** + * @see DavResource#addMember(DavResource) + */ + public void addMember(DavResource member) throws DavException { + if (!exists()) { + throw new DavException(DavServletResponse.SC_CONFLICT); + } + try { + node.addNode(member.getDisplayName(), "nt:folder"); + node.save(); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + /** + * @see DavResource#removeMember(DavResource) + */ + public void removeMember(DavResource member) throws DavException { + if (!exists() || !member.exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + if (isLocked(this) || isLocked(member)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + + try { + // make sure, non-jcr locks are removed. + /* + do not use jcr locks until implemented + + if (!isJsrLockable()) { + ActiveLock lock =3D getLock(Type.WRITE, Scope.EXCLUSIVE); + if (lock !=3D null) { + lockManager.releaseLock(lock.getToken(), member); + } + } + */ + ActiveLock lock =3D getLock(Type.WRITE, Scope.EXCLUSIVE); + if (lock !=3D null && lockManager.hasLock(lock.getToken(), member)) { + lockManager.releaseLock(lock.getToken(), member); + } + + Session s =3D session.getRepositorySession(); + Item memItem =3D s.getItem(member.getResourcePath()); + memItem.remove(); + s.save(); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + /** + * @see DavResource#move(DavResource) + */ + public void move(DavResource destination) throws DavException { + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + if (isLocked(this)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + try { + session.getRepositorySession().getWorkspace().move(getResource= Path(), destination.getResourcePath()); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + /** + * @see DavResource#copy(DavResource, boolean) + */ + public void copy(DavResource destination, boolean shallow) throws DavE= xception { + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + if (isLocked(destination)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + // TODO: support shallow and deep copy + if (shallow) { + throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unabl= e to perform shallow copy."); + } + try { + session.getRepositorySession().getWorkspace().copy(getResource= Path(), destination.getResourcePath()); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + /** + * @param type + * @param scope + * @return true if type is {@link Type#WRITE} and scope is {@link Scop= e#EXCLUSIVE} + * @see DavResource#isLockable(org.apache.jackrabbit.webdav.lock.Type,= org.apache.jackrabbit.webdav.lock.Scope) + */ + public boolean isLockable(Type type, Scope scope) { + return Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope); + } + + /** + * @see DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, or= g=2Eapache.jackrabbit.webdav.lock.Scope) + */ + public boolean hasLock(Type type, Scope scope) { + return getLock(type, scope) !=3D null; + } + + /** + * @see DavResource#getLock(Type, Scope) + */ + public ActiveLock getLock(Type type, Scope scope) { + ActiveLock lock =3D null; + if (exists() && Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(= scope)) { + // try to retrieve the repository lock information first + /* + do not use jcr locks until implemented + + if (isJsrLockable()) { + try { + Lock jcrLock =3D node.getLock(); + if (jcrLock !=3D null && jcrLock.isLive()) { + lock =3D new JcrActiveLock(jcrLock); + } + } catch (RepositoryException e) { + // LockException: no lock applies to this node >> igno= re + // RepositoryException, AccessDeniedException or anoth= er error >> ignore + } + } else { + // not-jcr lockable >> check for webdav lock + lock =3D lockManager.getLock(type, scope, this); + } + */ + lock =3D lockManager.getLock(type, scope, this); + } + return lock; + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getLocks() + */ + public ActiveLock[] getLocks() { + return new ActiveLock[] {getLock(Type.WRITE, Scope.EXCLUSIVE)}; + } + + /** + * @see DavResource#lock(LockInfo) + */ + public ActiveLock lock(LockInfo lockInfo) throws DavException { + ActiveLock lock =3D null; + if (isLockable(lockInfo.getType(), lockInfo.getScope())) { + /* + do not use jcr lock until implemented + + if (isJsrLockable()) { + try { + // try to execute the lock operation + Lock jcrLock =3D node.lock(lockInfo.isDeep(), false); + if (jcrLock !=3D null) { + lock =3D new JcrActiveLock(jcrLock); + } + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } else { + // create a new lock which creates a random lock token + lock =3D lockManager.createLock(lockInfo, this); + } + */ + lock =3D lockManager.createLock(lockInfo, this); + } + return lock; + } + + /** + * @see DavResource#refreshLock(LockInfo, String) + */ + public ActiveLock refreshLock(LockInfo lockInfo, String lockToken) thr= ows DavException{ + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + + /* since lock is always has infinite timeout >> no extra refresh n= eeded + return a lockdiscovery with the lock-info and the default scope an= d type */ + ActiveLock lock =3D getLock(lockInfo.getType(), lockInfo.getScope(= )); + if (lock =3D=3D null) { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAILE= D, "No lock present on resource " + getResourcePath()); + } else if (lock.isLockedByToken(lockToken)) { + if (lock instanceof JcrActiveLock) { + try { + // refresh JCR lock and return the original lock objec= t=2E + node.getLock().refresh(); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } else { + lock =3D lockManager.refreshLock(lockInfo, lockToken, this= ); + } + } else { + throw new DavException(DavServletResponse.SC_LOCKED); + } + return lock; + } + + /** + * @see DavResource#unlock(String) + */ + public void unlock(String lockToken) throws DavException { + ActiveLock lock =3D getLock(Type.WRITE, Scope.EXCLUSIVE); + if (lock =3D=3D null) { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAIL= ED); + } else if (lock.isLockedByToken(lockToken)) { + if (lock instanceof JcrActiveLock) { + try { + node.unlock(); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } else { + lockManager.releaseLock(lockToken, this); + } + } else { + throw new DavException(DavServletResponse.SC_LOCKED); + } + } + + /** + * @see DavResource#addLockManager(org.apache.jackrabbit.webdav.lock.L= ockManager) + */ + public void addLockManager(LockManager lockMgr) { + this.lockManager =3D lockMgr; + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getFactory() + */ + public DavResourceFactory getFactory() { + return factory; + } + + /** + * Returns true, if this webdav resource allows for locking without ch= ecking + * its current lock status. + * + * @return true if this resource is lockable. + */ + private boolean isJsrLockable() { + boolean lockable =3D false; + if (exists()) { + try { + lockable =3D node.isNodeType("mix:lockable"); + } catch (RepositoryException e) { + // not jcr-lockable + } + } + return lockable; + } + + /** + * Return true if this resource cannot be modified due to a write lock + * that is not owned by the given session. + * + * @return true if this resource cannot be modified due to a write lock + */ + private boolean isLocked(DavResource res) { + ActiveLock lock =3D res.getLock(Type.WRITE, Scope.EXCLUSIVE); + if (lock =3D=3D null) { + return false; + } else { + String[] sLockTokens =3D session.getLockTokens(); + for (int i =3D 0; i < sLockTokens.length; i++) { + if (sLockTokens[i].equals(lock.getToken())) { + return false; + } + } + return true; + } + } + + /** + * @param item + * @return + * @throws DavException + * @throws RepositoryException + */ + private DavResource buildResourceFromItem(Item item) throws DavExcepti= on, RepositoryException { + DavResourceLocator parentloc =3D locator.getFactory().createResour= ceLocator(locator.getPrefix(), locator.getWorkspacePath(), item.getPath()); + return factory.createResource(parentloc, session); + } +} Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/DavResourceImpl.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/DavResourceImpl.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/server/simple/dav/LocatorFactor= yImpl.java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/LocatorFactoryImpl.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/LocatorFactoryImpl.java Sun Mar 6 06:02:39 = 2005 @@ -0,0 +1,129 @@ +/* + * Copyright 2005 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.jackrabbit.server.simple.dav; + +import org.apache.jackrabbit.webdav.*; + +/** + * ResourceFactoryImpl implements a simple DavLocatorFactory + */ +public class LocatorFactoryImpl implements DavLocatorFactory { + + private final String repositoryPrefix; + + public LocatorFactoryImpl(String repositoryPrefix) { + this.repositoryPrefix =3D repositoryPrefix; + } + + public DavResourceLocator createResourceLocator(String prefix, String = requestHandle) { + String rPrefix =3D prefix + repositoryPrefix; + String rHandle =3D requestHandle; + if (rHandle !=3D null && rHandle.startsWith(repositoryPrefix)) { + rHandle =3D rHandle.substring(repositoryPrefix.length()); + } + if (rHandle =3D=3D null || "".equals(rHandle)) { + rHandle =3D "/"; + } + return new Locator(rPrefix, rHandle, this); + } + + public DavResourceLocator createResourceLocator(String prefix, String = workspacePath, String resourcePath) { + return new Locator(prefix, resourcePath, this); + } + + private class Locator implements DavResourceLocator { + + private final String prefix; + private final String itemPath; + private final DavLocatorFactory factory; + + private Locator(String prefix, String itemPath, DavLocatorFactory = factory) { + this.prefix =3D prefix; + this.factory =3D factory; + if (itemPath.endsWith("/") && !"/".equals(itemPath)) { + itemPath =3D itemPath.substring(0, itemPath.length()-1); + } + this.itemPath =3D itemPath; + } + + public String getPrefix() { + return prefix; + } + + public String getResourcePath() { + return itemPath; + } + + public String getWorkspacePath() { + return ""; + } + + public String getWorkspaceName() { + return ""; + } + + public boolean isSameWorkspace(DavResourceLocator path) { + return isSameWorkspace(path.getWorkspaceName()); + } + + public boolean isSameWorkspace(String workspaceName) { + return getWorkspaceName().equals(workspaceName); + } + + public String getHref(boolean isCollection) { + return prefix + itemPath + (isCollection ? "/" : ""); + } + + public boolean isRootLocation() { + return "/".equals(itemPath); + } + + public DavLocatorFactory getFactory() { + return factory; + } + + /** + * Computes the hash code using the prefix and the itemPath + * + * @return the hash code + */ + public int hashCode() { + int hashCode =3D prefix.hashCode(); + if (itemPath !=3D null) { + hashCode +=3D itemPath.hashCode(); + } + return hashCode % Integer.MAX_VALUE; + } + + /** + * Equality of path is achieved if the specified object is a DavResourceLocator + * and the return values of the two getHref(boolean) = methods are + * equal. + * + * @param obj the object to compare to + * @return true if the 2 objects are equal; + * false otherwise + */ + public boolean equals(Object obj) { + if (obj instanceof DavResourceLocator) { + DavResourceLocator path =3D (DavResourceLocator) obj; + this.getHref(true).equals(path.getHref(true)); + } + return false; + } + } +} Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/server/simple/dav/NodeResource.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/server/simple/dav/NodeResource.= java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/NodeResource.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/NodeResource.java Sun Mar 6 06:02:39 2005 @@ -0,0 +1,279 @@ +/* + * Copyright 2005 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.jackrabbit.server.simple.dav; + +import org.apache.log4j.Logger; +import org.apache.jackrabbit.webdav.util.Text; + +import javax.jcr.*; +import java.util.Date; +import java.util.Locale; +import java.io.*; +import java.text.SimpleDateFormat; + +/** + * The NodeResource class wraps a jcr item in order to respond + * to 'GET', 'HEAD', 'PROPFIND' or 'PROPPATCH' requests. If the item is a + * {@link javax.jcr.Node} its primary property is determined. The value of= the + * primary property can be accessed by {@link #getStream()}. If possible o= ther + * required information (last modification date, content type...) is retri= eved + * from the property siblings.
+ * If the requested item is a {@link javax.jcr.Property} it is treated acc= ordingly. + */ +public class NodeResource { + + /** the default logger */ + private static final Logger log =3D Logger.getLogger(NodeResource.clas= s); + + /** + * modificationDate date format per RFC 1123 + */ + public static SimpleDateFormat modificationDateFormat =3D + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + + /** + * Simple date format for the creation date ISO representation (partia= l). + */ + public static SimpleDateFormat creationDateFormat =3D + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + private static final String PROP_MIMETYPE =3D "jcr:mimeType"; + private static final String PROP_ENCODING =3D "jcr:encoding"; + private static final String PROP_LASTMODIFIED =3D "jcr:lastModified"; + private static final String PROP_CREATED =3D "jcr:created"; + + private long creationTime =3D 0; + private long modificationTime =3D new Date().getTime(); + private long contentLength =3D 0; + private String contentType =3D null; + private InputStream in =3D null; + + /** + * Create a new NodeResource that wraps a JSR170 item. + * + * @throws ItemNotFoundException + * @throws RepositoryException + * @throws IllegalArgumentException if the given item is null + */ + public NodeResource(DavResourceImpl davResource, Node node) throws Ite= mNotFoundException, RepositoryException { + try { + if (davResource.isCollection()) { + createDirListingContent(node); + } else { + if (node.hasProperty(PROP_CREATED)) { + creationTime =3D node.getProperty(PROP_CREATED).getValue().getLong(); + } + Node content =3D node.getPrimaryNodeType().getName().equals("nt:file") + ? node.getNode("jcr:content") + : node; + if (content.getPrimaryNodeType().getName().equals("nt:resource")) { + createPlainFileContent(content); + } else { + createDocViewContent(content); + } + } + } catch (IOException e) { + // ignore + } + } + + private void createPlainFileContent(Node content) throws IOException, = RepositoryException { + if (content.hasProperty(PROP_LASTMODIFIED)) { + modificationTime =3D content.getProperty(PROP_LASTMODIFIED).getLong(); + } + if (content.hasProperty(PROP_MIMETYPE)) { + contentType =3D content.getProperty(PROP_MIMETYPE).getString(); + } + if (content.hasProperty(PROP_ENCODING)) { + String encoding =3D content.getProperty(PROP_ENCODING).getString(); + if (!encoding.equals("")) { + contentType+=3D"; charset=3D\"" + encoding + "\""; + } + } + if (content.hasProperty("jcr:data")) { + Property p =3D content.getProperty("jcr:data"); + contentLength =3D p.getLength(); + in =3D p.getStream(); + } else { + contentLength =3D 0; + } + } + + private void createDocViewContent(Node node) throws IOException, Repos= itoryException { + File tmpfile =3D File.createTempFile("__webdav", ".xml"); + FileOutputStream out =3D new FileOutputStream(tmpfile); + node.getSession().exportDocView(node.getPath(), out, true, false); + out.close(); + in =3D new FileInputStream(tmpfile); + contentLength =3D tmpfile.length(); + modificationTime =3D tmpfile.lastModified(); + contentType =3D "text/xml"; + tmpfile.deleteOnExit(); + } + + private void createSysViewContent(Node node) throws IOException, Repos= itoryException { + File tmpfile =3D File.createTempFile("__webdav", ".xml"); + FileOutputStream out =3D new FileOutputStream(tmpfile); + node.getSession().exportSysView(node.getPath(), out, true, false); + out.close(); + in =3D new FileInputStream(tmpfile); + contentLength =3D tmpfile.length(); + modificationTime =3D tmpfile.lastModified(); + contentType =3D "text/xml"; + tmpfile.deleteOnExit(); + } + + private void createDirListingContent(Node node) throws IOException, Re= positoryException { + File tmpfile =3D File.createTempFile("__webdav", ".xml"); + FileOutputStream out =3D new FileOutputStream(tmpfile); + + String repName =3D node.getSession().getRepository().getDescriptor(Reposi= tory.REP_NAME_DESC); + String repURL =3D node.getSession().getRepository().getDescriptor(Reposit= ory.REP_VENDOR_URL_DESC); + String repVersion =3D node.getSession().getRepository().getDescriptor(Rep= ository.REP_VERSION_DESC); + PrintWriter writer =3D new PrintWriter(out); + writer.print(""); + writer.print(repName); + writer.print(" "); + writer.print(repVersion); + writer.print(" "); + writer.print(node.getPath()); + writer.print(""); + writer.print("

"); + writer.print(node.getPath()); + writer.print("

    "); + writer.print("
  • ..
  • "); + NodeIterator iter =3D node.getNodes(); + while (iter.hasNext()) { + Node child =3D iter.nextNode(); + String label =3D Text.getLabel(child.getPath()); + writer.print("
  • "); + writer.print(label); + writer.print("
  • "); + } + writer.print("

Powered by "); + writer.print(repName); + writer.print(" version "); + writer.print(repVersion); + writer.print(""); + + writer.close(); + out.close(); + in =3D new FileInputStream(tmpfile); + contentLength =3D tmpfile.length(); + modificationTime =3D tmpfile.lastModified(); + contentType =3D "text/html"; + tmpfile.deleteOnExit(); + } + + /** + * Return the content length or '0'. + * @return content Length or '0' if it could not be determined. + */ + public long getContentLength() { + return contentLength; + } + + /** + * Return the creation time or '0'. + * + * @return creation time or '0' if it could not be determined. + */ + public long getCreationTime() { + return creationTime; + } + + /** + * Return the last modification time. By default it is set to the curr= ent + * time. + * + * @return time of last modification or the current time, if it could = not + * be determined. + */ + public long getModificationTime() { + return modificationTime; + } + + /** + * Return the last modification time as formatted string. + * + * @return last modification time as string. + * @see NodeResource#modificationDateFormat + */ + public String getLastModified() { + if (modificationTime >=3D 0) { + return modificationDateFormat.format(new Date(modificationTime)); + } else { + return null; + } + } + + /** + * Return the creation time as formatted string. + * + * @return creation time as string. + * @see NodeResource#creationDateFormat + */ + public String getCreationDate() { + if (creationTime >=3D 0) { + return creationDateFormat.format(new Date(creationTime)); + } else { + return null; + } + } + + /** + * Return the weak ETag + * + * @return weak ETag + */ + public String getETag() { + return "W/\"" + this.contentLength + "-" + this.modificationTime + "\""; + } + + /** + * Return the strong ETag or empty string if it cannot be determined. + * + * @return strong ETag + */ + public String getStrongETag() { + return ""; + } + + /** + * Return the content type or null if it could not be det= ermined. + * + * @return content type + */ + public String getContentType() { + return contentType; + } + + /** + * Return a stream to the resource value. + * + * @return + */ + public InputStream getStream() { + return in; + } +} Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/NodeResource.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/NodeResource.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/server/simple/dav/ResourceFacto= ryImpl.java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/ResourceFactoryImpl.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/ResourceFactoryImpl.java Sun Mar 6 06:02:39= 2005 @@ -0,0 +1,43 @@ +/* + * Copyright 2005 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.jackrabbit.server.simple.dav; + +import org.apache.jackrabbit.webdav.*; +import org.apache.jackrabbit.webdav.lock.LockManager; + +/** + * ResourceFactoryImpl implements a simple DavResourceFactory + */ +public class ResourceFactoryImpl implements DavResourceFactory { + + private final LockManager lockMgr; + + public ResourceFactoryImpl(LockManager lockMgr) { + this.lockMgr =3D lockMgr; + } + + public DavResource createResource(DavResourceLocator locator, DavServl= etRequest request, + DavServletResponse response) throws = DavException { + return createResource(locator, request.getDavSession()); + } + + public DavResource createResource(DavResourceLocator locator, DavSessi= on session) throws DavException { + DavResource res =3D new DavResourceImpl(locator, this, session); + res.addLockManager(lockMgr); + return res; + } +} Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/server/simple/dav/lock/SimpleLo= ckManager.java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/lock/SimpleLockManager.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/server/simple/dav/lock/SimpleLockManager.java Sun Mar 6 06:02= :39 2005 @@ -0,0 +1,197 @@ +/* + * Copyright 2005 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.jackrabbit.server.simple.dav.lock; + +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.jackrabbit.webdav.lock.*; +import org.apache.jackrabbit.webdav.*; +import org.apache.jackrabbit.webdav.util.Text; + +/** + * Simple manager for webdav locks.
+ * NOTE: the timeout requested is always replace by a infinite timeout and + * expiration of locks is not checked. + */ +public class SimpleLockManager implements LockManager { + + /** map of locks */ + private HashMap locks =3D new HashMap(); + + /** + * + * @param lockToken + * @param resource + * @return + * @see LockManager#hasLock(String, org.apache.jackrabbit.webdav.DavRe= source) + */ + public boolean hasLock(String lockToken, DavResource resource) { + ActiveLock lock =3D (ActiveLock) locks.get(resource.getResourcePath()); + if (lock !=3D null && lock.getToken().equals(lockToken)) { + return true; + } + return false; + } + + /** + * Returns the lock applying to the given resource or null
if + * no lock can be found. + * + * @param type + * @param scope + * @param resource + * @return lock that applies to the given resource or null=2E + */ + public ActiveLock getLock(Type type, Scope scope, DavResource resource= ) { + if (!(Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope))) { + return null; + } + String key =3D resource.getResourcePath(); + ActiveLock lock =3D (locks.containsKey(key)) ? (ActiveLock)locks.get(key)= : null; + + // look for an inherited lock + if (lock =3D=3D null) { + // cut path instead of retrieving the parent resource + String parentPath =3D Text.getRelativeParent(key, 1); + boolean found =3D false; + /* stop as soon as parent lock is found: + if the lock is deep or the parent is a collection the lock + applies to the given resource. */ + while (!"/".equals(parentPath) && !(found =3D locks.containsKey(paren= tPath))) { + parentPath =3D Text.getRelativeParent(parentPath, 1); + } + if (found) { + ActiveLock parentLock =3D (ActiveLock)locks.get(parentPath); + if (parentLock.isDeep()) { + lock =3D parentLock; + } + } + } + // since locks have infinite timeout, check for expired lock is omitted. + return lock; + } + + /** + * Adds the lock for the given resource, replacing any existing lock. + * + * @param lockInfo + * @param resource being the lock holder + */ + public synchronized ActiveLock createLock(LockInfo lockInfo, DavResour= ce resource) + throws DavException { + if (lockInfo =3D=3D null || resource =3D=3D null) { + throw new IllegalArgumentException("Neither lockInfo nor resource mus= t be null."); + } + + String resourcePath =3D resource.getResourcePath(); + // test if there is already a lock present on this resource + if (locks.containsKey(resourcePath)) { + throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + r= esource.getResourcePath() + "' already holds a lock."); + } + // test if the new lock would conflict with any lock inherited from the + // collection or with a lock present on any member resource. + Iterator it =3D locks.keySet().iterator(); + while (it.hasNext()) { + String key =3D (String) it.next(); + // TODO: is check for lock on internal-member correct? + if (Text.isDescendant(key, resourcePath)) { + ActiveLock l =3D (ActiveLock) locks.get(key); + if (l.isDeep() || (key.equals(Text.getRelativeParent(resourcePath, 1)) &= & !resource.isCollection())) { + throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + = resource.getResourcePath() + "' already inherits a lock by its collection."= ); + } + } else if (Text.isDescendant(resourcePath, key)) { + if (lockInfo.isDeep() || isInternalMember(resource, key)) { + throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + = resource.getResourcePath() + "' cannot be locked due to a lock present on a= member resource '" + key + "'."); + } + + } + } + ActiveLock lock =3D new DefaultActiveLock(lockInfo); + // Lazy: reset the timeout to 'Infinite', in order to omit the tests for + // lock expiration. + lock.setTimeout(DavConstants.INFINITE_TIMEOUT); + locks.put(resource.getResourcePath(), lock); + return lock; + } + + /** + * + * @param lockInfo + * @param lockToken + * @param resource + * @return + * @throws DavException + * @see DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.Lock= Info, String) + */ + public ActiveLock refreshLock(LockInfo lockInfo, String lockToken, Dav= Resource resource) + throws DavException { + // timeout is always infinite > no test for expiration or adjusting timeo= ut needed. + ActiveLock lock =3D (ActiveLock)locks.get(resource.getResourcePath()); + if (lock =3D=3D null) { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED); + } else if (!lock.getToken().equals(lockToken)) { + throw new DavException(DavServletResponse.SC_LOCKED); + } + return lock; + } + + /** + * Remove the lock hold by the given resource. + * + * @param lockToken + * @param resource that is the lock holder + */ + public synchronized void releaseLock(String lockToken, DavResource res= ource) + throws DavException { + if (!locks.containsKey(resource.getResourcePath())) { + throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED); + } + // since locks have infinite timeout, check for expiration is omitted. + + ActiveLock lock =3D (ActiveLock) locks.get(resource.getResourcePath()); + if (lock.getToken().equals(lockToken)) { + locks.remove(resource.getResourcePath()); + } else { + throw new DavException(DavServletResponse.SC_LOCKED); + } + } + + /** + * Return true, if the resource with the given memberPath is a internal + * non-collection member of the given resource, thus affected by a + * non-deep lock present on the resource. + * + * @param resource + * @param memberPath + * @return + */ + private static boolean isInternalMember(DavResource resource, String m= emberPath) { + if (resource.getResourcePath().equals(Text.getRelativeParent(memberPath, = 1))) { + // find the member with the given path + DavResourceIterator it =3D resource.getMembers(); + while (it.hasNext()) { + DavResource member =3D it.nextResource(); + if (member.getResourcePath().equals(memberPath)) { + // return true if that member is not a collection + return !member.isCollection(); + } + } + } + return false; + } +} + Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native Added: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/ap= ache/jackrabbit/webdav/spi/AbstractItemResource.java URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/jcr-s= erver/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractItemResource= .java?view=3Dauto&rev=3D156314 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/webdav/spi/AbstractItemResource.java (added) +++ incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/org/apach= e/jackrabbit/webdav/spi/AbstractItemResource.java Sun Mar 6 06:02:39 2005 @@ -0,0 +1,483 @@ +/* + * Copyright 2005 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.jackrabbit.webdav.spi; + +import org.apache.log4j.Logger; +import org.apache.jackrabbit.webdav.property.*; +import org.apache.jackrabbit.webdav.*; +import org.apache.jackrabbit.webdav.spi.search.SearchResourceImpl; +import org.apache.jackrabbit.webdav.spi.version.report.NodeTypesReport; +import org.apache.jackrabbit.webdav.spi.version.report.ExportViewReport; +import org.apache.jackrabbit.webdav.spi.version.report.LocateByUuidReport; +import org.apache.jackrabbit.webdav.DavResource; +import org.apache.jackrabbit.webdav.transaction.TxLockEntry; +import org.apache.jackrabbit.webdav.version.report.*; +import org.apache.jackrabbit.webdav.version.DeltaVResource; +import org.apache.jackrabbit.webdav.version.DeltaVConstants; +import org.apache.jackrabbit.webdav.version.OptionsResponse; +import org.apache.jackrabbit.webdav.version.OptionsInfo; +import org.apache.jackrabbit.webdav.search.*; +import org.apache.jackrabbit.webdav.util.Text; + +import javax.jcr.*; +import java.util.*; + +/** + * AbstractItemResource covers common functionality for the v= arious + * resources, that represent a repository item. + */ +abstract class AbstractItemResource extends AbstractResource implements Da= vResource, + SearchResource, DeltaVResource, ItemResourceConstants { + + private static Logger log =3D Logger.getLogger(AbstractItemResource.cl= ass); + + protected final Item item; + protected SupportedReportSetProperty supportedReports; + + /** + * Create a new AbstractItemResource. + * + * @param locator + * @param session + */ + AbstractItemResource(DavResourceLocator locator, DavSession session, D= avResourceFactory factory) { + super(locator, session, factory); + Item repositoryItem =3D null; + if (locator !=3D null) { + try { + repositoryItem =3D getRepositorySession().getItem(locator.= getResourcePath()); + } catch (RepositoryException e) { + // ignore: exists field evaluates to false + log.info(e.getMessage()); + } + } + item =3D repositoryItem; + // initialize the supported locks and reports + initLockSupport(); + initSupportedReports(); + } + + //----------------------------------------------< DavResource interfac= e >--- + /** + * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass() + */ + public String getComplianceClass() { + return ItemResourceConstants.COMPLIANCE_CLASS; + } + + /** + * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods() + */ + public String getSupportedMethods() { + return ItemResourceConstants.METHODS; + } + + /** + * Returns true if there exists a {@link Item repository item} with th= e given + * resource path, false otherwise. + * + * @see DavResource#exists() + */ + public boolean exists() { + return item !=3D null; + } + + /** + * @see DavResource#getDisplayName() ) + */ + public String getDisplayName() { + String name =3D null; + if (exists()) { + try { + name =3D item.getName(); + } catch (RepositoryException e) { + // ignore: should not occure + log.warn(e.getMessage()); + } + } + String resPath =3D getResourcePath(); + if (name =3D=3D null && resPath !=3D null) { + int pos =3D resPath.lastIndexOf('/'); + if (pos>=3D0) { + name =3D resPath.substring(pos+1); + } else { + name =3D resPath; + } + // note: since index info is present only with existing resour= ces + // there is no need to check for any '[index]' suffix. + } + return name; + } + + /** + * Returns the resource representing the parent item of the repository= item + * represented by this resource. If this resoure represents the root i= tem + * a {@link RootCollection} is returned. + * + * @return the collection this resource is internal member of. Except = for the + * repository root, the returned collection always represent the parent + * repository node. + * @see DavResource#getCollection() + */ + public DavResource getCollection() { + DavResource collection =3D null; + + String resourcePath =3D getResourcePath(); + // No special treatment for the root-item needed, because this is + // covered by the RootItemCollection itself. + String parentResourcePath =3D Text.getRelativeParent(resourcePath,= 1); + String parentWorkspacePath =3D getLocator().getWorkspacePath(); + + DavResourceLocator parentLoc =3D getLocator().getFactory().createR= esourceLocator(getLocator().getPrefix(), parentWorkspacePath, parentResourc= ePath); + try { + collection =3D createResourceFromLocator(parentLoc); + } catch (DavException e) { + log.error("Unexpected error while retrieving collection: " + e= .getMessage()); + } + + return collection; + } + + /** + * Moves the underlaying repository item to the indicated destination. + * + * @param destination + * @throws DavException + * @see DavResource#move(DavResource) + * @see Session#move(String, String) + */ + public void move(DavResource destination) throws DavException { + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + DavResourceLocator destPath =3D destination.getLocator(); + if (!getLocator().isSameWorkspace(destPath)) { + throw new DavException(DavServletResponse.SC_FORBIDDEN); + } + + try { + getRepositorySession().move(getResourcePath(), destination.get= ResourcePath()); + complete(); + + } catch (PathNotFoundException e) { + // according to rfc 2518 + throw new DavException(DavServletResponse.SC_NOT_FOUND, e.getM= essage()); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + /** + * Copies the underlaying repository item to the indicated destination= . If + * the locator of the specified destination resource indicates a diffe= rent + * workspace, {@link Workspace#copy(String, String, String)} is used t= o perform + * the copy operation, {@link Workspace#copy(String, String)} otherwis= e=2E + *

+ * Note, that this implementation does not support shallow copy. + * + * @param destination + * @param shallow + * @throws DavException + * @see DavResource#copy(DavResource, boolean) + * @see Workspace#copy(String, String) + * @see Workspace#copy(String, String, String) + */ + public void copy(DavResource destination, boolean shallow) throws DavE= xception { + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + // TODO: support shallow and deep copy is required by RFC 2518 + if (shallow) { + throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unabl= e to perform shallow copy."); + } + + if (!(destination instanceof AbstractItemResource)) { + throw new DavException(DavServletResponse.SC_FORBIDDEN, "Canno= t copy a resource that does not represent a repository item."); + } + + try { + AbstractItemResource destResource =3D (AbstractItemResource) d= estination; + String destResourcePath =3D destResource.getResourcePath(); + Workspace workspace =3D getRepositorySession().getWorkspace(); + if (getLocator().isSameWorkspace(destination.getLocator())) { + workspace.copy(getResourcePath(), destResourcePath); + } else { + Workspace destWorkspace =3D destResource.getRepositorySess= ion().getWorkspace(); + destWorkspace.copy(workspace.getName(), getResourcePath(),= destResourcePath); + } + } catch (PathNotFoundException e) { + // according to RFC 2518, should not occur + throw new DavException(DavServletResponse.SC_NOT_FOUND, e.getM= essage()); + } catch (RepositoryException e) { + throw new JcrDavException(e); + } + } + + //-------------------------------------------< SearchResource interfac= e >--- + /** + * @return + * @see org.apache.jackrabbit.webdav.search.SearchResource#getQueryGra= mmerSet() + */ + public QueryGrammerSet getQueryGrammerSet() { + return new SearchResourceImpl(getLocator(), getSession()).getQuery= GrammerSet(); + } + + /** + * @param sRequest + * @return + * @throws DavException + * @see SearchResource#search(org.apache.jackrabbit.webdav.search.Sear= chRequest) + */ + public MultiStatus search(SearchRequest sRequest) throws DavException { + return new SearchResourceImpl(getLocator(), getSession()).search(s= Request); + } + + //-------------------------------------------< DeltaVResource interfac= e >--- + /** + * @param optionsInfo + * @return object to be used in the OPTIONS response body or nul= l + * @see DeltaVResource#getOptionResponse(org.apache.jackrabbit.webdav.= version.OptionsInfo) + */ + public OptionsResponse getOptionResponse(OptionsInfo optionsInfo) { + OptionsResponse oR =3D null; + if (optionsInfo !=3D null) { + oR =3D new OptionsResponse(); + // currently on DAV:version-history-collection-set and + // DAV:workspace-collection-set is supported. + if (optionsInfo.containsElement(DeltaVConstants.XML_VH_COLLECT= ION_SET, DeltaVConstants.NAMESPACE)) { + String[] hrefs =3D new String[] { getLocatorFromResourcePa= th(VERSIONSTORAGE_PATH).getHref(true)}; + oR.addEntry(DeltaVConstants.XML_VH_COLLECTION_SET, DeltaVC= onstants.NAMESPACE, hrefs); + } else if (optionsInfo.containsElement(DeltaVConstants.XML_WSP= _COLLECTION_SET, DeltaVConstants.NAMESPACE)) { + // workspaces cannot be created anywhere. + oR.addEntry(DeltaVConstants.XML_WSP_COLLECTION_SET, DeltaV= Constants.NAMESPACE, new String[0]); + } + } + return oR; + } + + /** + * @param reportInfo + * @return the requested report + * @throws DavException + * @see DeltaVResource#getReport(org.apache.jackrabbit.webdav.version.= report.ReportInfo) + */ + public Report getReport(ReportInfo reportInfo) throws DavException { + if (reportInfo =3D=3D null) { + throw new DavException(DavServletResponse.SC_BAD_REQUEST, "A R= EPORT request must provide a valid XML request body."); + } + if (!exists()) { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + + if (supportedReports.isSupportedReport(reportInfo)) { + try { + Report report =3D ReportType.getType(reportInfo).createRep= ort(); + report.setInfo(reportInfo); + report.setResource(this); + return report; + } catch (IllegalArgumentException e) { + // should never occur. + throw new DavException(DavServletResponse.SC_INTERNAL_SERV= ER_ERROR, e.getMessage()); + } + } else { + throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENT= ITY, "Unkown report "+ reportInfo.getReportElement().getNamespacePrefix() += reportInfo.getReportElement().getName() +"requested."); + } + } + + /** + * The JCR api does not provide methods to create new workspaces. Call= ing + * addWorkspace on this resource will always fail. + * + * @param workspace + * @throws DavException Always throws. + * @see DeltaVResource#addWorkspace(org.apache.jackrabbit.webdav.DavRe= source) + */ + public void addWorkspace(DavResource workspace) throws DavException { + throw new DavException(DavServletResponse.SC_FORBIDDEN); + } + + /** + * Return an array of DavResource objects that are refere= nced + * by the property with the specified name. + * + * @param hrefPropertyName + * @return array of DavResources + * @throws DavException + * @see DeltaVResource#getReferenceResources(org.apache.jackrabbit.web= dav.property.DavPropertyName) + */ + public DavResource[] getReferenceResources(DavPropertyName hrefPropert= yName) throws DavException { + DavProperty prop =3D getProperty(hrefPropertyName); + if (prop =3D=3D null || !(prop instanceof HrefProperty)) { + throw new DavException(DavServletResponse.SC_CONFLICT, "Unknow= n Href-Property '"+hrefPropertyName+"' on resource "+getResourcePath()); + } + + List hrefs =3D ((HrefProperty)prop).getHrefs(); + DavResource[] refResources =3D new DavResource[hrefs.size()]; + Iterator hrefIter =3D hrefs.iterator(); + int i =3D 0; + while (hrefIter.hasNext()) { + refResources[i] =3D getResourceFromHref((String)hrefIter.next(= )); + i++; + } + return refResources; + } + + /** + * Retrieve the DavResource object that is represented by + * the given href String. + * + * @param href + * @return DavResource object + */ + private DavResource getResourceFromHref(String href) throws DavExcepti= on { + // build a new locator: remove trailing prefix + DavResourceLocator locator =3D getLocator(); + String prefix =3D locator.getPrefix(); + if (href.startsWith(prefix)) { + href =3D href.substring(prefix.length()); + } + DavResourceLocator loc =3D locator.getFactory().createResourceLoca= tor(prefix, href); + + // create a new resource object + DavResource res; + if (getRepositorySession().itemExists(loc.getResourcePath())) { + res =3D createResourceFromLocator(loc); + } else { + throw new DavException(DavServletResponse.SC_NOT_FOUND); + } + return res; + } + + //--------------------------------------------------------------------= ------ + /** + * Initialize the {@link org.apache.jackrabbit.webdav.lock.SupportedLo= ck} property + * with entries that are valid for any type item resources. + * + * @see org.apache.jackrabbit.webdav.lock.SupportedLock + * @see org.apache.jackrabbit.webdav.transaction.TxLockEntry + */ + protected void initLockSupport() { + if (exists()) { + // add supportedlock entries for local and eventually for glob= al transaction locks + supportedLock.addEntry(new TxLockEntry(true)); + supportedLock.addEntry(new TxLockEntry(false)); + } + } + + /** + * Define the set of reports supported by this resource. + * + * @see SupportedReportSetProperty + */ + protected void initSupportedReports() { + if (exists()) { + supportedReports =3D new SupportedReportSetProperty(new Report= Type[] { + ReportType.EXPAND_PROPERTY, + NodeTypesReport.NODETYPES_REPORT, + ExportViewReport.EXPORTVIEW_REPORT, + LocateByUuidReport.LOCATE_BY_UUID_REPORT + }); + } else { + supportedReports =3D new SupportedReportSetProperty(); + } + } + + /** + * Fill the property set for this resource. + */ + protected void initProperties() { + super.initProperties(); + if (exists()) { + try { + properties.add(new DefaultDavProperty(JCR_NAME, item.getNa= me())); + properties.add(new DefaultDavProperty(JCR_PATH, item.getPa= th())); + properties.add(new DefaultDavProperty(JCR_DEPTH, String.va= lueOf(item.getDepth()))); + } catch (RepositoryException e) { + log.error("Error while accessing jcr properties: " + e.get= Message()); + } + + // transaction resource additional protected properties + if (item.isNew()) { + properties.add(new DefaultDavProperty(JCR_ISNEW, null, tru= e)); + } else if (item.isModified()) { + properties.add(new DefaultDavProperty(JCR_ISMODIFIED, null= , true)); + } + + // DeltaV properties + properties.add(supportedReports); + // creator-displayname, comment: not value available from jcr + properties.add(new DefaultDavProperty(DeltaVConstants.CREATOR_= DISPLAYNAME, null, true)); + properties.add(new DefaultDavProperty(DeltaVConstants.COMMENT,= null, true)); + + // TODO: required supported-live-property-set + } + } + + /** + * If this resource exists but does not contain a transaction id, comp= lete + * will try to persist any modifications prsent on the underlaying rep= ository + * item. + * + * @throws DavException if calling {@link Item#save()} fails + */ + void complete() throws DavException { + if (exists() && getTransactionId() =3D=3D null) { + try { + if (item.isModified()) { + item.save(); + } + } catch (RepositoryException e) { + // this includes LockException, ConstraintViolationExcepti= on etc. not detected before + log.error("Error while completing request: " + e.getMessag= e() +" -> reverting changes."); + try { + item.refresh(false); + } catch (RepositoryException re) { + log.error("Error while reverting changes: " + re.getMe= ssage()); + } + throw new JcrDavException(e); + } + } + } + + /** + * Build a new {@link DavResourceLocator} from the given repository it= em. + * + * @param repositoryItem + * @return a new locator for the specified item. + * @see #getLocatorFromResourcePath(String) + */ + protected DavResourceLocator getLocatorFromItem(Item repositoryItem) { + String itemPath =3D null; + try { + if (repositoryItem !=3D null) { + itemPath =3D repositoryItem.getPath(); + } + } catch (RepositoryException e) { + // ignore: should not occur + log.warn(e.getMessage()); + } + return getLocatorFromResourcePath(itemPath); + } + + /** + * Shortcut for getSession().getRepositorySession() + * + * @return repository session present in the {@link #session}. + */ + protected Session getRepositorySession() { + return getSession().getRepositorySession(); + } +} \ No newline at end of file Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/webdav/spi/AbstractItemResource.java ---------------------------------------------------------------------------= --- svn =3D=20 Propchange: incubator/jackrabbit/trunk/contrib/jcr-server/server/src/java/o= rg/apache/jackrabbit/webdav/spi/AbstractItemResource.java ---------------------------------------------------------------------------= --- svn:eol-style =3D native