You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by re...@locus.apache.org on 2000/09/25 09:24:54 UTC
cvs commit: jakarta-slide/src/share/org/apache/slide/webdav/method GetMethod.java PutMethod.java WebdavMethod.java
remm 00/09/25 00:24:53
Modified: src/doc status.xml
src/share/org/apache/slide/content ContentImpl.java
NodeRevisionDescriptor.java
src/share/org/apache/slide/lock Lock.java LockImpl.java
NodeLock.java
src/share/org/apache/slide/util/resources
messages.properties
src/share/org/apache/slide/webdav/method GetMethod.java
PutMethod.java WebdavMethod.java
Log:
- Collection browser in the DAV servlet (based on some Catalina and
Tomcat code)
- HTTP/1.1 headers support (should allow resuming, all types of conditional
requests, multipart requests, ETags, ...)
- Lock checking are back in the core
- Added a new easier to use lockCheck method in the lock helper
- Fixes for the handling of Dates in NodeRevisionDescriptor and in the DAV
servlet
- Updated the status.xml page regarding the current progress
Revision Changes Path
1.7 +12 -39 jakarta-slide/src/doc/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/jakarta-slide/src/doc/status.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- status.xml 2000/09/23 07:41:40 1.6
+++ status.xml 2000/09/25 07:24:36 1.7
@@ -57,15 +57,12 @@
<th width="30%">Volunteers</th>
</tr>
<tr>
- <td align="center">High</td>
+ <td align="center">Medium</td>
<td>
- Put back security and lock checks (which were removed due to a
- partial rewrite of the API).
- [org.apache.slide.structure]
- [org.apache.slide.content]
- [org.apache.slide.lock]
+ Add additional helper macros.
+ [org.apache.slide.macro]
</td>
- <td><a href="mailto:remm@apache.org">Remy Maucherat</a></td>
+ <td>---</td>
</tr>
<tr>
<td align="center">Low</td>
@@ -83,15 +80,6 @@
</td>
<td><a href="mailto:remm@apache.org">Remy Maucherat</a></td>
</tr>
- <tr>
- <td align="center">Low</td>
- <td>
- Add additional helper macros (for exemple, macros for users / groups
- management).
- [org.apache.slide.macro]
- </td>
- <td>---</td>
- </tr>
</table>
</p>
@@ -128,7 +116,7 @@
<th width="30%">Volunteers</th>
</tr>
<tr>
- <td align="center">Medium</td>
+ <td align="center">Low</td>
<td>
Add a filesystem content store without versioning, or add an option
to the current filesystem content store which disables
@@ -137,7 +125,7 @@
<td><a href="mailto:cvrc@netscape.com">Murthy Chintalapati</a></td>
</tr>
<tr>
- <td align="center">Medium</td>
+ <td align="center">Low</td>
<td>
Add a limited filesystem descriptors store (without versioning
support), to make it possible to have Slide manage existing
@@ -225,21 +213,6 @@
<tr>
<td align="center">Medium</td>
<td>
- Add a nice collection browser (returned when someone does a GET on
- a collection object), using Catalina code.
- </td>
- <td><a href="mailto:remm@apache.org">Remy Maucherat</a></td>
- </tr>
- <tr>
- <td align="center">Medium</td>
- <td>
- Support HTTP/1.1 headers, using Catalina code.
- </td>
- <td><a href="mailto:remm@apache.org">Remy Maucherat</a></td>
- </tr>
- <tr>
- <td align="center">Low</td>
- <td>
DAV ACL support (based on the drafts).
</td>
<td><a href="mailto:cvrc@netscape.com">Murthy Chintalapati</a></td>
@@ -283,20 +256,20 @@
<tr>
<td align="center">High</td>
<td>
- DAV ACL support.
+ Write a command line client using the DAV library.
</td>
<td>
+ <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ <br/>
+ <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
</td>
</tr>
<tr>
- <td align="center">High</td>
+ <td align="center">Medium</td>
<td>
- Write a command line client using the DAV library.
+ DAV ACL support.
</td>
<td>
- <a href="mailto:remm@apache.org">Remy Maucherat</a>
- <br/>
- <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
</td>
</tr>
</table>
1.4 +129 -22 jakarta-slide/src/share/org/apache/slide/content/ContentImpl.java
Index: ContentImpl.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/ContentImpl.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ContentImpl.java 2000/06/14 05:12:14 1.3
+++ ContentImpl.java 2000/09/25 07:24:39 1.4
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/ContentImpl.java,v 1.3 2000/06/14 05:12:14 remm Exp $
- * $Revision: 1.3 $
- * $Date: 2000/06/14 05:12:14 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/ContentImpl.java,v 1.4 2000/09/25 07:24:39 remm Exp $
+ * $Revision: 1.4 $
+ * $Date: 2000/09/25 07:24:39 $
*
* ====================================================================
*
@@ -77,7 +77,7 @@
* Implementation of the content interface.
*
* @author <a href="mailto:remm@exoffice.com">Remy Maucherat</a>
- * @version $Revision: 1.3 $
+ * @version $Revision: 1.4 $
*/
public final class ContentImpl implements Content {
@@ -154,17 +154,12 @@
ObjectLockedException {
ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
- // Check security
- // For now, we don't do any security check here (that is, no more
- // than what have already been done by the retrieve object,
- // which checks the readObject action.
- // securityHelper.checkCredentials(token, associatedObject,
- // namespaceConfig.getModifyRevisionsAction());
-
- // Check locking
- // We don't perform additional checks for locking either.
- // lockHelper.checkLock(token, (SubjectNode) associatedObject,
- // subject, namespaceConfig.getModifyRevisionsAction());
+ // Checking security and locking
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getReadRevisionMetadataAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getReadRevisionMetadataAction());
Uri objectUri = namespace.getUri(strUri);
NodeRevisionDescriptors revisionDescriptors = null;
@@ -196,6 +191,14 @@
RevisionDescriptorNotFoundException, ObjectLockedException {
ObjectNode associatedObject = structureHelper
.retrieve(token, revisionDescriptors.getUri());
+
+ // Checking security and locking
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getReadRevisionMetadataAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getReadRevisionMetadataAction());
+
Uri objectUri = namespace.getUri(revisionDescriptors.getUri());
return objectUri.getDescriptorsStore()
.retrieveRevisionDescriptor(objectUri, revisionNumber);
@@ -250,6 +253,14 @@
RevisionNotFoundException, RevisionContentNotFoundException,
ObjectLockedException {
ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
+
+ // Checking security and locking
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getReadRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getReadRevisionContentAction());
+
Uri objectUri = namespace.getUri(strUri);
return objectUri.getContentStore()
.retrieveRevisionContent(objectUri,
@@ -273,9 +284,19 @@
// Retrieve the associated object
ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
- // Next we do a security check and a locking check for modifyRevisions
- // TODO !
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
Uri objectUri = namespace.getUri(strUri);
@@ -358,7 +379,7 @@
.retrieveRevisionDescriptor(objectUri,
newRevisionNumber);
Enumeration newPropertiesList =
- revisionDescriptor.getPropertiesValues();
+ revisionDescriptor.enumerateProperties();
while (newPropertiesList.hasMoreElements()) {
oldRevisionDescriptor
.setProperty( (NodeProperty) newPropertiesList
@@ -430,9 +451,19 @@
// Retrieve the associated object
ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
- // Next we do a security check and a locking check for modifyRevisions
- // TODO !
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
Uri objectUri = namespace.getUri(strUri);
@@ -523,6 +554,23 @@
throws ObjectNotFoundException, AccessDeniedException,
LinkedObjectNotFoundException, ServiceAccessException,
RevisionDescriptorNotFoundException, ObjectLockedException {
+
+ // Retrieve the associated object
+ ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
+
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+
Domain.info("Fork not implemented");
}
@@ -542,6 +590,23 @@
throws ObjectNotFoundException, AccessDeniedException,
LinkedObjectNotFoundException, ServiceAccessException,
RevisionDescriptorNotFoundException, ObjectLockedException {
+
+ // Retrieve the associated object
+ ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
+
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getCreateRevisionContentAction());
+
Domain.info("Merge not implemented");
}
@@ -565,6 +630,19 @@
// Retrieve the associated object
ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getModifyRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getModifyRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getModifyRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getModifyRevisionContentAction());
+
}
@@ -579,7 +657,22 @@
LinkedObjectNotFoundException, ServiceAccessException,
RevisionDescriptorNotFoundException, ObjectLockedException {
- // TODO : Add security and locking checks
+ // Retrieve the associated object
+ ObjectNode associatedObject =
+ structureHelper.retrieve(token, revisionDescriptors.getUri());
+
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getRemoveRevisionContentAction());
Uri objectUri = namespace.getUri(revisionDescriptors.getUri());
@@ -614,7 +707,21 @@
LinkedObjectNotFoundException, ServiceAccessException,
RevisionDescriptorNotFoundException, ObjectLockedException {
- // TODO : Add security and locking checks
+ // Retrieve the associated object
+ ObjectNode associatedObject = structureHelper.retrieve(token, strUri);
+
+ // Next we do a security check and a locking check for modifyRevisions
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionMetadataAction());
+ lockHelper.checkLock
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionMetadataAction());
+ securityHelper.checkCredentials
+ (token, associatedObject,
+ namespaceConfig.getRemoveRevisionContentAction());
+ lockHelper.checkLock(token, associatedObject,
+ namespaceConfig.getRemoveRevisionContentAction());
Uri objectUri = namespace.getUri(strUri);
1.6 +14 -7 jakarta-slide/src/share/org/apache/slide/content/NodeRevisionDescriptor.java
Index: NodeRevisionDescriptor.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/NodeRevisionDescriptor.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- NodeRevisionDescriptor.java 2000/09/24 17:20:08 1.5
+++ NodeRevisionDescriptor.java 2000/09/25 07:24:40 1.6
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/NodeRevisionDescriptor.java,v 1.5 2000/09/24 17:20:08 remm Exp $
- * $Revision: 1.5 $
- * $Date: 2000/09/24 17:20:08 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/content/NodeRevisionDescriptor.java,v 1.6 2000/09/25 07:24:40 remm Exp $
+ * $Revision: 1.6 $
+ * $Date: 2000/09/25 07:24:40 $
*
* ====================================================================
*
@@ -77,7 +77,7 @@
* Node Revision Descriptor class.
*
* @author <a href="mailto:remm@exoffice.com">Remy Maucherat</a>
- * @version $Revision: 1.5 $
+ * @version $Revision: 1.6 $
*/
public final class NodeRevisionDescriptor implements Serializable, Cloneable {
@@ -582,6 +582,9 @@
if (creationDate == null) {
return null;
} else {
+ if (creationDate.getValue() instanceof Date) {
+ return format.format((Date) creationDate.getValue());
+ }
return creationDate.getValue().toString();
}
}
@@ -633,7 +636,11 @@
if (lastModified == null) {
return null;
} else {
- return lastModified.getValue().toString();
+ if (lastModified.getValue() instanceof Date) {
+ return format.format((Date) lastModified.getValue());
+ } else {
+ return lastModified.getValue().toString();
+ }
}
}
@@ -726,13 +733,13 @@
private void initDefaultProperties() {
- setCreationDate(format.format(new Date()));
+ setCreationDate(new Date());
setName("");
// By default, a resource is a collection
setProperty(TYPE, "<collection/>", true);
setProperty(SOURCE, "", true);
setContentLength(0);
- setLastModified(format.format(new Date()));
+ setLastModified(new Date());
}
1.3 +29 -7 jakarta-slide/src/share/org/apache/slide/lock/Lock.java
Index: Lock.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/Lock.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Lock.java 2000/09/05 05:38:09 1.2
+++ Lock.java 2000/09/25 07:24:44 1.3
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/Lock.java,v 1.2 2000/09/05 05:38:09 remm Exp $
- * $Revision: 1.2 $
- * $Date: 2000/09/05 05:38:09 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/Lock.java,v 1.3 2000/09/25 07:24:44 remm Exp $
+ * $Revision: 1.3 $
+ * $Date: 2000/09/25 07:24:44 $
*
* ====================================================================
*
@@ -78,7 +78,7 @@
* Lock helper class.
*
* @author <a href="mailto:remm@exoffice.com">Remy Maucherat</a>
- * @version $Revision: 1.2 $
+ * @version $Revision: 1.3 $
*/
public interface Lock {
@@ -232,6 +232,28 @@
/**
+ * Utility function for lock checking. Mirrors Security.checkCredentials.
+ *
+ * @param credentialsToken Credetials token
+ * @param subject Object on which the action is performed
+ * @param action Action to test
+ * @exception ObjectIsLockedException Can't perform specified action
+ * on object
+ * @exception ServiceConnectionFailedException Connection to Lock Store
+ * service failed
+ * @exception ServiceAccessException Low level service access exception
+ * @exception ObjectNotFoundException One of the objects referenced
+ * in the lock token were not found
+ * @exception LinkedObjectNotFoundException Broken link encountered
+ * during object retrieval
+ */
+ void checkLock(CredentialsToken credentialsToken, ObjectNode object,
+ ActionNode action)
+ throws ServiceAccessException, ObjectNotFoundException,
+ ObjectLockedException;
+
+
+ /**
* Check locking for a specific action and credential.
*
* @param credentialsToken Credetials token
@@ -248,7 +270,7 @@
* @exception LinkedObjectNotFoundException Broken link encountered
* during object retrieval
*/
- void checkLock(CredentialsToken credentialsToken, SubjectNode subject,
+ void checkLock(CredentialsToken credentialsToken, ObjectNode subject,
SubjectNode user, ActionNode action)
throws ServiceConnectionFailedException, ServiceAccessException,
ObjectNotFoundException, LinkedObjectNotFoundException,
@@ -271,7 +293,7 @@
* @exception LinkedObjectNotFoundException Broken link encountered
* during object retrieval
*/
- boolean isLocked(CredentialsToken credentialsToken, SubjectNode subject,
+ boolean isLocked(CredentialsToken credentialsToken, ObjectNode subject,
SubjectNode user, ActionNode action, boolean tryToLock)
throws ServiceConnectionFailedException, ServiceAccessException,
ObjectNotFoundException, LinkedObjectNotFoundException;
@@ -298,7 +320,7 @@
* @exception LinkedObjectNotFoundException Broken link encountered
* during object retrieval
*/
- boolean isLocked(CredentialsToken credentialsToken, SubjectNode subject,
+ boolean isLocked(CredentialsToken credentialsToken, ObjectNode subject,
SubjectNode user, ActionNode action, boolean inheritance,
boolean tryToLock)
throws ServiceConnectionFailedException, ServiceAccessException,
1.5 +56 -46 jakarta-slide/src/share/org/apache/slide/lock/LockImpl.java
Index: LockImpl.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/LockImpl.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- LockImpl.java 2000/09/21 22:46:31 1.4
+++ LockImpl.java 2000/09/25 07:24:44 1.5
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/LockImpl.java,v 1.4 2000/09/21 22:46:31 remm Exp $
- * $Revision: 1.4 $
- * $Date: 2000/09/21 22:46:31 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/LockImpl.java,v 1.5 2000/09/25 07:24:44 remm Exp $
+ * $Revision: 1.5 $
+ * $Date: 2000/09/25 07:24:44 $
*
* ====================================================================
*
@@ -78,7 +78,7 @@
* Lock helper class.
*
* @author <a href="mailto:remm@exoffice.com">Remy Maucherat</a>
- * @version $Revision: 1.4 $
+ * @version $Revision: 1.5 $
*/
public final class LockImpl implements Lock {
@@ -357,6 +357,39 @@
/**
+ * Utility function for lock checking. Mirrors Security.checkCredentials.
+ *
+ * @param token Credetials token
+ * @param subject Object on which the action is performed
+ * @param action Action to test
+ * @exception ObjectIsLockedException Can't perform specified action
+ * on object
+ * @exception ServiceAccessException Low level service access exception
+ * @exception ObjectNotFoundException One of the objects referenced
+ * in the lock token were not found
+ */
+ public void checkLock(CredentialsToken token,
+ ObjectNode object, ActionNode action)
+ throws ServiceAccessException, ObjectNotFoundException,
+ ObjectLockedException {
+
+ if (Configuration.useIntegratedLocking()) {
+
+ Uri objectUri = namespace.getUri(object.getUri());
+ ObjectNode realObject = objectUri.getDescriptorsStore()
+ .retrieveObject(objectUri);
+ Uri subjectUri = null;
+ subjectUri = namespace.getUri(namespaceConfig.getUsersPath() + "/"
+ + token.getPublicCredentials());
+ SubjectNode subject = (SubjectNode) subjectUri
+ .getDescriptorsStore().retrieveObject(subjectUri);
+ checkLock(token, realObject, subject, action);
+
+ }
+ }
+
+
+ /**
* Check locking for a specific action and credential.
*
* @param credentialsToken Credetials token
@@ -365,19 +398,14 @@
* @param action Action to test
* @exception ObjectIsLockedException Can't perform specified action
* on object
- * @exception ServiceConnectionFailedException Connection to
- * Lock Store service failed
* @exception ServiceAccessException Low level service access exception
* @exception ObjectNotFoundException One of the objects referenced
* in the lock token were not found
- * @exception LinkedObjectNotFoundException Broken link encountered
- * during object retrieval
*/
public void checkLock(CredentialsToken credentialsToken,
- SubjectNode subject, SubjectNode user,
+ ObjectNode subject, SubjectNode user,
ActionNode action)
- throws ServiceConnectionFailedException, ServiceAccessException,
- ObjectNotFoundException, LinkedObjectNotFoundException,
+ throws ServiceAccessException, ObjectNotFoundException,
ObjectLockedException {
if (Configuration.useIntegratedLocking()) {
@@ -397,19 +425,14 @@
* @param user User to test
* @param action Locked for action
* @return boolean True if the subject is locked
- * @exception ServiceConnectionFailedException Connection to Lock Store
- * service failed
* @exception ServiceAccessException Low level service access exception
* @exception ObjectNotFoundException One of the objects referenced
* in the lock token were not found
- * @exception LinkedObjectNotFoundException Broken link encountered
- * during object retrieval
*/
public boolean isLocked(CredentialsToken credentialsToken,
- SubjectNode subject, SubjectNode user,
+ ObjectNode subject, SubjectNode user,
ActionNode action, boolean tryToLock)
- throws ServiceConnectionFailedException, ServiceAccessException,
- ObjectNotFoundException, LinkedObjectNotFoundException {
+ throws ServiceAccessException, ObjectNotFoundException {
NodeLock token = new NodeLock(subject, user, action,
new Date(), false);
return isLocked(credentialsToken, token, tryToLock);
@@ -428,21 +451,15 @@
* @param tryToLock True if the check is intended to check whether
* or not we can put a new lock
* @return boolean True if the subject is locked
- * @exception ServiceConnectionFailedException Connection to
- * Lock Store service failed
* @exception ServiceAccessException Low level service access exception
* @exception ObjectNotFoundException One of the objects referenced
* in the lock token were not found
- * @exception LinkedObjectNotFoundException Broken link encountered
- * during object retrieval
*/
public boolean isLocked(CredentialsToken credentialsToken,
- SubjectNode subject, SubjectNode user,
+ ObjectNode subject, SubjectNode user,
ActionNode action, boolean inheritance,
boolean tryToLock)
- throws ServiceConnectionFailedException, ServiceAccessException,
- ObjectNotFoundException,
- LinkedObjectNotFoundException {
+ throws ServiceAccessException, ObjectNotFoundException {
NodeLock token = new NodeLock(subject, user, action, new Date(),
inheritance);
return isLocked(credentialsToken, token, tryToLock);
@@ -454,23 +471,18 @@
*
* @param token Lock token to test
* @return boolean True if locked
- * @exception ServiceConnectionFailedException Connection to Lock Store
- * service failed
* @exception ServiceAccessException Low level service access exception
* @exception ObjectNotFoundException One of the objects referenced
* in the lock token were not found
- * @exception LinkedObjectNotFoundException Broken link encountered
- * during object retrieval
*/
public boolean isLocked(CredentialsToken credentialsToken, NodeLock token,
boolean tryToLock)
- throws ServiceConnectionFailedException, ServiceAccessException,
- ObjectNotFoundException, LinkedObjectNotFoundException {
+ throws ServiceAccessException, ObjectNotFoundException {
- Uri subjectUri = namespace.getUri(token.getObjectUri());
- SubjectNode initialSubject = (SubjectNode) subjectUri
- .getDescriptorsStore().retrieveObject(subjectUri);
- Enumeration scopes = subjectUri.getScopes();
+ Uri objectUri = namespace.getUri(token.getObjectUri());
+ ObjectNode initialObject = objectUri.getDescriptorsStore()
+ .retrieveObject(objectUri);
+ Enumeration scopes = objectUri.getScopes();
// At the end of the test, this boolean's value is true if we can
// actually put the lock on the desired subject.
@@ -499,14 +511,14 @@
// locked with an incompatible lock.
if (token.isInheritable()) {
Stack childrenStack = new Stack();
- childrenStack.push(initialSubject);
+ childrenStack.push(initialObject);
while (!isLocked && !childrenStack.empty()) {
- SubjectNode currentSubject = (SubjectNode) childrenStack.pop();
- Uri currentSubjectUri =
- namespace.getUri(currentSubject.getUri());
+ ObjectNode currentObject = (ObjectNode) childrenStack.pop();
+ Uri currentObjectUri =
+ namespace.getUri(currentObject.getUri());
// We test the compatibility of the child
- Enumeration locks = currentSubjectUri.getDescriptorsStore()
- .enumerateLocks(currentSubjectUri);
+ Enumeration locks = currentObjectUri.getDescriptorsStore()
+ .enumerateLocks(currentObjectUri);
while (locks.hasMoreElements()) {
NodeLock currentLockToken = (NodeLock) locks.nextElement();
@@ -519,7 +531,7 @@
// We get the children and add them to the Stack.
Vector childrenVector = new Vector();
- Enumeration childrenUri = currentSubject.enumerateChildren();
+ Enumeration childrenUri = currentObject.enumerateChildren();
while (childrenUri.hasMoreElements()) {
String childUri = (String) childrenUri.nextElement();
Uri tempUri = namespace.getUri(childUri);
@@ -532,9 +544,7 @@
while (children.hasMoreElements()) {
ObjectNode tempObject =
(ObjectNode) children.nextElement();
- if (tempObject instanceof SubjectNode) {
- childrenStack.push(tempObject);
- }
+ childrenStack.push(tempObject);
}
}
}
1.4 +6 -6 jakarta-slide/src/share/org/apache/slide/lock/NodeLock.java
Index: NodeLock.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/NodeLock.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- NodeLock.java 2000/09/20 06:06:15 1.3
+++ NodeLock.java 2000/09/25 07:24:45 1.4
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/NodeLock.java,v 1.3 2000/09/20 06:06:15 remm Exp $
- * $Revision: 1.3 $
- * $Date: 2000/09/20 06:06:15 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/lock/NodeLock.java,v 1.4 2000/09/25 07:24:45 remm Exp $
+ * $Revision: 1.4 $
+ * $Date: 2000/09/25 07:24:45 $
*
* ====================================================================
*
@@ -74,7 +74,7 @@
* NodeLock class.
*
* @author <a href="mailto:remm@exoffice.com">Remy Maucherat</a>
- * @version $Revision: 1.3 $
+ * @version $Revision: 1.4 $
*/
public final class NodeLock implements Cloneable {
@@ -98,7 +98,7 @@
* @param expirationDate Date of expiration of the lock
* @param inheritance True if lock is inheritable
*/
- public NodeLock(SubjectNode locked, SubjectNode user, ActionNode lockType,
+ public NodeLock(ObjectNode locked, SubjectNode user, ActionNode lockType,
Date expirationDate, boolean inheritance) {
this(locked.getUri(), user.getUri(), lockType.getUri(), expirationDate,
inheritance);
@@ -114,7 +114,7 @@
* @param expirationDate Date of expiration of the lock
* @param inheritance True if lock is inheritable
*/
- public NodeLock(SubjectNode locked, SubjectNode user, ActionNode lockType,
+ public NodeLock(ObjectNode locked, SubjectNode user, ActionNode lockType,
Date expirationDate, boolean inheritance,
boolean exclusive) {
this(locked.getUri(), user.getUri(), lockType.getUri(), expirationDate,
1.3 +13 -4 jakarta-slide/src/share/org/apache/slide/util/resources/messages.properties
Index: messages.properties
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/util/resources/messages.properties,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- messages.properties 2000/08/02 04:28:11 1.2
+++ messages.properties 2000/09/25 07:24:48 1.3
@@ -1,9 +1,9 @@
#
# Slide messages
#
-# $Id: messages.properties,v 1.2 2000/08/02 04:28:11 remm Exp $
+# $Id: messages.properties,v 1.3 2000/09/25 07:24:48 remm Exp $
#
-# @version $Revision: 1.2 $ $Date: 2000/08/02 04:28:11 $
+# @version $Revision: 1.3 $ $Date: 2000/09/25 07:24:48 $
#
#
@@ -99,8 +99,17 @@
# Messages produced by webdav
#
org.apache.slide.webdav.GetMethod.directorylistingfor=\
- Directory listing for
-
+ Directory listing for {0}
+org.apache.slide.webdav.GetMethod.filename=\
+ Filename
+org.apache.slide.webdav.GetMethod.size=\
+ Size
+org.apache.slide.webdav.GetMethod.parent=\
+ Up To {0}
+org.apache.slide.webdav.GetMethod.lastModified=\
+ Last Modified
+org.apache.slide.webdav.GetMethod.version=\
+ Jakarta Slide 1.0
#
# Messages produced by org.apache.slide.util.Configuration
1.4 +937 -49 jakarta-slide/src/share/org/apache/slide/webdav/method/GetMethod.java
Index: GetMethod.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/GetMethod.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- GetMethod.java 2000/09/02 03:13:32 1.3
+++ GetMethod.java 2000/09/25 07:24:50 1.4
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/GetMethod.java,v 1.3 2000/09/02 03:13:32 remm Exp $
- * $Revision: 1.3 $
- * $Date: 2000/09/02 03:13:32 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/GetMethod.java,v 1.4 2000/09/25 07:24:50 remm Exp $
+ * $Revision: 1.4 $
+ * $Date: 2000/09/25 07:24:50 $
*
* ====================================================================
*
@@ -66,12 +66,15 @@
import java.security.Principal;
import java.io.*;
import java.util.*;
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.slide.common.*;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.webdav.common.*;
import org.apache.slide.webdav.*;
+import org.apache.slide.util.Messages;
import org.apache.slide.content.*;
import org.apache.slide.lock.*;
import org.apache.slide.structure.*;
@@ -88,6 +91,40 @@
protected final int BUFFER_SIZE = 2048;
+ /**
+ * The set of SimpleDateFormat formats to use in getDateHeader().
+ */
+ protected static final SimpleDateFormat formats[] = {
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+ };
+
+
+ /**
+ * MIME multipart separation string
+ */
+ protected static final String mimeSeparation = "SLIDE_MIME_BOUNDARY";
+
+
+ /**
+ * The input buffer size to use when serving resources.
+ */
+ protected int input = 2048;
+
+
+ /**
+ * The output buffer size to use when serving resources.
+ */
+ protected int output = 2048;
+
+
+ /**
+ * Print content.
+ */
+ protected boolean printContent = true;
+
+
// ----------------------------------------------------- Instance Variables
@@ -145,53 +182,104 @@
content.retrieve(credToken, resourcePath);
if (revisionDescriptors.hasRevisions()) {
+
// Retrieve latest revision descriptor
NodeRevisionDescriptor revisionDescriptor =
content.retrieve(credToken, revisionDescriptors);
- if (WebdavUtil.isCollection(revisionDescriptor)) {
+
+ if (isCollection(revisionDescriptor)) {
+
Writer writer = resp.getWriter();
displayDirectoryBrowsing(object, writer);
writer.close();
+
} else {
- OutputStream os = resp.getOutputStream();
+
+ ResourceInfo resourceInfo =
+ new ResourceInfo(resourcePath, revisionDescriptor);
+
+ // Checking If headers
+ if (!checkIfHeaders(req, resp, resourceInfo))
+ return;
+
+ ServletOutputStream os = resp.getOutputStream();
NodeRevisionContent revisionContent =
content.retrieve(credToken, revisionDescriptors,
revisionDescriptor);
- resp.setStatus(WebdavStatus.SC_OK);
- resp.setContentLength
- ((int) revisionDescriptor.getContentLength());
- //addHeader("Content-Length",
- //(new Long(revisionDescriptor.getContentLength()))
- //.toString());
+ InputStream is = revisionContent.streamContent();
+
+ Vector ranges = parseRange(req, resp, resourceInfo);
+
+ // ETag header
+ resp.setHeader("ETag", getETag(resourceInfo, true));
resp.addHeader
("Last-Modified",
revisionDescriptor.getCreationDate().toString());
- resp.addHeader("Content-Disposition",
- "inline; filename="
- + revisionDescriptors.getUri());
- resp.setContentType(revisionDescriptor.getContentType());
- // Writing content to the output stream
- InputStream is = revisionContent.streamContent();
- byte[] buffer = new byte[BUFFER_SIZE];
- long contentLength = revisionDescriptor.getContentLength();
- long position = 0;
- int nChar = 0;
- while (position < contentLength) {
- nChar = is.read(buffer, 0, BUFFER_SIZE);
- if (nChar == -1) {
- break;
+ if ( ((ranges == null) || (ranges.isEmpty()))
+ && (req.getHeader("Range") == null) ) {
+
+ resp.setContentType
+ (revisionDescriptor.getContentType());
+ resp.setContentLength
+ ((int) revisionDescriptor.getContentLength());
+
+ // Copy the input stream to our output stream
+ // (if requested)
+ if (printContent) {
+ resp.setBufferSize(output);
+ copy(resourceInfo, is, os);
}
- os.write(buffer, 0, nChar);
- position = position + nChar;
+
+ } else {
+
+ if ((ranges == null) || (ranges.isEmpty()))
+ return;
+
+ // Partial content response.
+
+ resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+
+ if (ranges.size() == 1) {
+
+ Range range = (Range) ranges.elementAt(0);
+ resp.addHeader("Content-Range", "bytes "
+ + range.start
+ + "-" + range.end + "/"
+ + range.length);
+ resp.setContentType
+ (revisionDescriptor.getContentType());
+
+ if (printContent) {
+ resp.setBufferSize(output);
+ copy(resourceInfo, is, os, range);
+ }
+
+ } else {
+
+ resp.setContentType
+ ("multipart/byteranges; boundary="
+ + mimeSeparation);
+
+ if (printContent) {
+ resp.setBufferSize(output);
+ copy(resourceInfo, is, os,
+ ranges.elements(),
+ revisionDescriptor.getContentType());
+ }
+
+ }
+
}
- is.close();
- os.close();
+
}
+
} else {
+
Writer writer = resp.getWriter();
displayDirectoryBrowsing(object, writer);
writer.close();
+
}
} catch (RevisionNotFoundException e) {
@@ -243,29 +331,829 @@
/**
* Display a directory browsing page.
+ */
+ protected void displayDirectoryBrowsing(ObjectNode object,
+ Writer servletWriter)
+ throws IOException {
+
+ String contextPath = req.getContextPath();
+ if (contextPath == null)
+ contextPath = "";
+
+ String name = object.getUri();
+
+ // Number of characters to trim from the beginnings of filenames
+ int trim = name.length();
+ if (!name.endsWith("/"))
+ trim += 1;
+ if (name.equals("/"))
+ trim = 1;
+
+ PrintWriter writer = new PrintWriter(servletWriter);
+
+ // Render the page header
+ writer.print("<html>\r\n");
+ writer.print("<head>\r\n");
+ writer.print("<title>");
+ writer.print
+ (Messages.format
+ ("org.apache.slide.webdav.GetMethod.directorylistingfor", name));
+ writer.print("</title>\r\n</head>\r\n");
+ writer.print("<body bgcolor=\"white\">\r\n");
+ writer.print("<table width=\"90%\" cellspacing=\"0\"" +
+ " cellpadding=\"5\" align=\"center\">\r\n");
+
+ // Render the in-page title
+ writer.print("<tr><td colspan=\"3\"><font size=\"+2\">\r\n<strong>");
+ writer.print
+ (Messages.format
+ ("org.apache.slide.webdav.GetMethod.directorylistingfor", name));
+ writer.print("</strong>\r\n</font></td></tr>\r\n");
+
+ // Render the link to our parent (if required)
+ String parentDirectory = name;
+ if (parentDirectory.endsWith("/")) {
+ parentDirectory =
+ parentDirectory.substring(0, parentDirectory.length() - 1);
+ }
+ int slash = parentDirectory.lastIndexOf("/");
+ if (slash >= 0) {
+ String parent = name.substring(0, slash);
+ writer.print("<tr><td colspan=\"3\" bgcolor=\"#ffffff\">\r\n");
+ writer.print("<a href=\"");
+ writer.print(rewriteUrl(contextPath));
+ if (parent.equals(""))
+ parent = "/";
+ writer.print(parent);
+ writer.print("\">");
+ writer.print(Messages.format
+ ("org.apache.slide.webdav.GetMethod.parent", parent));
+ writer.print("</a>\r\n");
+ writer.print("</td></tr>\r\n");
+ }
+
+ // Render the column headings
+ writer.print("<tr bgcolor=\"#cccccc\">\r\n");
+ writer.print("<td align=\"left\"><font size=\"+1\"><strong>");
+ writer.print(Messages.message
+ ("org.apache.slide.webdav.GetMethod.filename"));
+ writer.print("</strong></font></td>\r\n");
+ writer.print("<td align=\"center\"><font size=\"+1\"><strong>");
+ writer.print(Messages.message
+ ("org.apache.slide.webdav.GetMethod.size"));
+ writer.print("</strong></font></td>\r\n");
+ writer.print("<td align=\"right\"><font size=\"+1\"><strong>");
+ writer.print(Messages.message
+ ("org.apache.slide.webdav.GetMethod.lastModified"));
+ writer.print("</strong></font></td>\r\n");
+ writer.print("</tr>\r\n");
+
+ Enumeration resources = object.enumerateChildren();
+ boolean shade = false;
+
+ while (resources.hasMoreElements()) {
+
+ String currentResource = (String) resources.nextElement();
+
+ NodeRevisionDescriptor currentDescriptor = null;
+
+ try {
+
+ NodeRevisionDescriptors revisionDescriptors =
+ content.retrieve(credToken, currentResource);
+ // Retrieve latest revision descriptor
+ currentDescriptor =
+ content.retrieve(credToken, revisionDescriptors);
+
+ } catch (SlideException e) {
+ // Debug
+ e.printStackTrace();
+ }
+
+ String trimmed = currentResource.substring(trim);
+ if (trimmed.equalsIgnoreCase("WEB-INF") ||
+ trimmed.equalsIgnoreCase("META-INF"))
+ continue;
+
+ writer.print("<tr");
+ if (shade)
+ writer.print(" bgcolor=\"eeeeee\"");
+ writer.print(">\r\n");
+ shade = !shade;
+
+ writer.print("<td align=\"left\"> \r\n");
+ writer.print("<a href=\"");
+ writer.print(rewriteUrl(contextPath));
+ writer.print(rewriteUrl(currentResource));
+ writer.print("\"><tt>");
+ writer.print(trimmed);
+ if (isCollection(currentDescriptor)) {
+ writer.print("/");
+ }
+ writer.print("</tt></a></td>\r\n");
+
+ writer.print("<td align=\"right\"><tt>");
+ if (isCollection(currentDescriptor))
+ writer.print(" ");
+ else
+ writer.print(renderSize(currentDescriptor.getContentLength()));
+ writer.print("</tt></td>\r\n");
+
+ writer.print("<td align=\"right\"><tt>");
+ if (currentDescriptor != null)
+ writer.print(currentDescriptor.getLastModified());
+ writer.print("</tt></td>\r\n");
+
+ writer.print("</tr>\r\n");
+ }
+
+
+ // Render the page footer
+ writer.print("<tr><td colspan=\"3\"> </td></tr>\r\n");
+ writer.print("<tr><td colspan=\"3\" bgcolor=\"#cccccc\">");
+ writer.print("<font size=\"-1\">");
+ writer.print(Messages.message
+ ("org.apache.slide.webdav.GetMethod.version"));
+ writer.print("</font></td></tr>\r\n");
+ writer.print("</table>\r\n");
+ writer.print("</body>\r\n");
+ writer.print("</html>\r\n");
+
+ // Return an input stream to the underlying bytes
+ writer.flush();
+
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+
+ /**
+ * Render the specified file size (in bytes).
+ *
+ * @param size File size (in bytes)
+ */
+ private String renderSize(long size) {
+
+ long leftSide = size / 1024;
+ long rightSide = (size % 1024) / 103; // Makes 1 digit
+ if ((leftSide == 0) && (rightSide == 0) && (size > 0))
+ rightSide = 1;
+
+ return ("" + leftSide + "." + rightSide + " kb");
+
+ }
+
+
+ /**
+ * URL rewriter.
+ *
+ * @param path Path which has to be rewiten
*/
- protected void displayDirectoryBrowsing(ObjectNode object, Writer writer)
+ private String rewriteUrl(String path) {
+
+ String normalized = path;
+
+ // Replace " " with "%20"
+ while (true) {
+ int index = normalized.indexOf(" ");
+ if (index < 0)
+ break;
+ normalized = normalized.substring(0, index) + "%20"
+ + normalized.substring(index + 1);
+ }
+
+ return normalized;
+
+ }
+
+
+ /**
+ * Check if the conditions specified in the optional If headers are
+ * satisfied.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ * @param resourceInfo File object
+ * @return boolean true if the resource meets all the specified conditions,
+ * and false if any of the conditions is not satisfied, in which case
+ * request processing is stopped
+ */
+ private boolean checkIfHeaders(HttpServletRequest request,
+ HttpServletResponse response,
+ ResourceInfo resourceInfo)
throws IOException {
- // We display a directory browsing page
- resp.setContentType("text/html");
- String host = "http://" + req.getServerName() + ":"
- + req.getServerPort();
- if (req.getPathInfo() != null) {
- host = host + req.getServletPath();
- }
- writer.write("<!doctype html public \"-//w3c//dtd html 4.0"
- + "transitional//en\">\n");
- writer.write("<html><head><title>" + object.getUri()
- + "</title></head>");
- writer.write("<body bgcolor=white>");
- writer.write("<h1>Collection " + object.getUri() + "</h1><hr><p>");
- Enumeration childrenList = object.enumerateChildren();
- while (childrenList.hasMoreElements()) {
- String childUri = (String) childrenList.nextElement();
- writer.write("<a href=\"" + host + childUri + "\">" + childUri
- + "</a><br>");
+
+ String eTag = getETag(resourceInfo, true);
+ long fileLength = resourceInfo.length;
+ long lastModified = resourceInfo.date;
+
+ StringTokenizer commaTokenizer;
+
+ String headerValue;
+
+ // Checking If-Match
+ headerValue = request.getHeader("If-Match");
+ if (headerValue != null) {
+ if (headerValue.indexOf("*") == -1) {
+
+ commaTokenizer = new StringTokenizer(headerValue, ",");
+ boolean conditionSatisfied = false;
+
+ while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+ String currentToken = commaTokenizer.nextToken();
+ if (currentToken.trim().equals(eTag))
+ conditionSatisfied = true;
+ }
+
+ // If none of the given ETags match, 412 Precodition failed is
+ // sent back
+ if (!conditionSatisfied) {
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+
+ }
+ }
+
+ // Checking If-Modified-Since
+ headerValue = request.getHeader("If-Modified-Since");
+ if (headerValue != null) {
+
+ // If an If-None-Match header has been specified, if modified since
+ // is ignored.
+ if (request.getHeader("If-None-Match") == null) {
+
+ Date date = null;
+
+ // Parsing the HTTP Date
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(headerValue);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+
+ if ((date != null)
+ && (lastModified <= (date.getTime() + 1000)) ) {
+ // The entity has not been modified since the date
+ // specified by the client. This is not an error case.
+ response.sendError
+ (HttpServletResponse.SC_NOT_MODIFIED);
+ return false;
+ }
+
+ }
+
+ }
+
+ // Checking If-None-Match
+ headerValue = request.getHeader("If-None-Match");
+ if (headerValue != null) {
+ if (headerValue.indexOf("*") == -1) {
+
+ commaTokenizer = new StringTokenizer(headerValue, ",");
+ boolean conditionSatisfied = false;
+
+ while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+ String currentToken = commaTokenizer.nextToken();
+ if (currentToken.trim().equals(eTag))
+ conditionSatisfied = true;
+ }
+
+ if (conditionSatisfied) {
+
+ // For GET and HEAD, we should respond with
+ // 304 Not Modified.
+ // For every other method, 412 Precondition Failed is sent
+ // back.
+ if ( ("GET".equals(request.getMethod()))
+ || ("HEAD".equals(request.getMethod())) ) {
+ response.sendError
+ (HttpServletResponse.SC_NOT_MODIFIED);
+ return false;
+ } else {
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+ }
+
+ } else {
+ if (resourceInfo.exists()) {
+
+ }
+ }
+ }
+
+ // Checking If-Unmodified-Since
+ headerValue = request.getHeader("If-Unmodified-Since");
+ if (headerValue != null) {
+
+ Date date = null;
+
+ // Parsing the HTTP Date
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(headerValue);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+
+ if ( (date != null) && (lastModified > date.getTime()) ) {
+ // The entity has not been modified since the date
+ // specified by the client. This is not an error case.
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+
}
- writer.write("</body></html>");
+
+ return true;
}
+
+
+ /**
+ * Get the ETag value associated with a file.
+ *
+ * @param resourceInfo File object
+ * @param strong True if we want a strong ETag, in which case a checksum
+ * of the file has to be calculated
+ */
+ private String getETagValue(ResourceInfo resourceInfo, boolean strong) {
+ // FIXME : Compute a strong ETag if requested, using an MD5 digest
+ // of the file contents
+ return resourceInfo.length + "-" + resourceInfo.date;
+ }
+
+
+ /**
+ * Get the ETag associated with a file.
+ *
+ * @param resourceInfo File object
+ * @param strong True if we want a strong ETag, in which case a checksum
+ * of the file has to be calculated
+ */
+ private String getETag(ResourceInfo resourceInfo, boolean strong) {
+ if (strong)
+ return "\"" + getETagValue(resourceInfo, strong) + "\"";
+ else
+ return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param istream The input stream to read from
+ * @param ostream The output stream to write to
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ private void copy(ResourceInfo resourceInfo,
+ InputStream resourceInputStream,
+ ServletOutputStream ostream)
+ throws IOException {
+
+ IOException exception = null;
+
+ InputStream istream = new BufferedInputStream
+ (resourceInputStream, input);
+
+ // Copy the input stream to the output stream
+ exception = copyRange(istream, ostream);
+
+ // Clean up the input and output streams
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ try {
+ ostream.flush();
+ } catch (Throwable t) {
+ ;
+ }
+ try {
+ ostream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The ResourceInfo object
+ * @param ostream The output stream to write to
+ * @param range Range the client wanted to retrieve
+ * @exception IOException if an input/output error occurs
+ */
+ private void copy(ResourceInfo resourceInfo,
+ InputStream resourceInputStream,
+ ServletOutputStream ostream,
+ Range range)
+ throws IOException {
+
+ IOException exception = null;
+
+ InputStream istream =
+ new BufferedInputStream(resourceInputStream, input);
+ exception = copyRange(istream, ostream, range.start, range.end);
+
+ // Clean up the input and output streams
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
+ }
+ try {
+ ostream.flush();
+ } catch (Throwable t) {
+ ;
+ }
+ try {
+ ostream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The ResourceInfo object
+ * @param ostream The output stream to write to
+ * @param ranges Enumeration of the ranges the client wanted to retrieve
+ * @param contentType Content type of the resource
+ * @exception IOException if an input/output error occurs
+ */
+ private void copy(ResourceInfo resourceInfo,
+ InputStream resourceInputStream,
+ ServletOutputStream ostream,
+ Enumeration ranges, String contentType)
+ throws IOException {
+
+ IOException exception = null;
+
+ while ( (exception == null) && (ranges.hasMoreElements()) ) {
+
+ InputStream istream =
+ new BufferedInputStream(resourceInputStream, input);
+
+ Range currentRange = (Range) ranges.nextElement();
+
+ // Writing MIME header.
+ ostream.println("--" + mimeSeparation);
+ if (contentType != null)
+ ostream.println("Content-Type: " + contentType);
+ ostream.println("Content-Range: bytes " + currentRange.start
+ + "-" + currentRange.end + "/"
+ + currentRange.length);
+ ostream.println();
+
+ // Printing content
+ exception = copyRange(istream, ostream, currentRange.start,
+ currentRange.end);
+
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ }
+
+ ostream.print("--" + mimeSeparation + "--");
+
+ // Clean up the output streams
+ try {
+ ostream.flush();
+ } catch (Throwable t) {
+ ;
+ }
+ try {
+ ostream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param istream The input stream to read from
+ * @param ostream The output stream to write to
+ * @return Exception which occured during processing
+ */
+ private IOException copyRange(InputStream istream,
+ ServletOutputStream ostream) {
+
+ // Copy the input stream to the output stream
+ IOException exception = null;
+ byte buffer[] = new byte[input];
+ int len = buffer.length;
+ while (true) {
+ try {
+ len = istream.read(buffer);
+ if (len == -1)
+ break;
+ ostream.write(buffer, 0, len);
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ break;
+ }
+ }
+ return exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param istream The input stream to read from
+ * @param ostream The output stream to write to
+ * @param start Start of the range which will be copied
+ * @param end End of the range which will be copied
+ * @return Exception which occured during processing
+ */
+ private IOException copyRange(InputStream istream,
+ ServletOutputStream ostream,
+ long start, long end) {
+
+ try {
+ istream.skip(start);
+ } catch (IOException e) {
+ return e;
+ }
+
+ IOException exception = null;
+ long bytesToRead = end - start + 1;
+
+ byte buffer[] = new byte[input];
+ int len = buffer.length;
+ while ( (bytesToRead > 0) && (len >= buffer.length)) {
+ try {
+ len = istream.read(buffer);
+ if (bytesToRead >= len) {
+ ostream.write(buffer, 0, len);
+ bytesToRead -= len;
+ } else {
+ ostream.write(buffer, 0, (int) bytesToRead);
+ bytesToRead = 0;
+ }
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ }
+ if (len < buffer.length)
+ break;
+ }
+
+ return exception;
+
+ }
+
+
+ /**
+ * Parse the range header.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ * @return Vector of ranges
+ */
+ private Vector parseRange(HttpServletRequest request,
+ HttpServletResponse response,
+ ResourceInfo resourceInfo)
+ throws IOException {
+
+ // Checking If-Range
+ String headerValue = request.getHeader("If-Range");
+ if (headerValue != null) {
+
+ String eTag = getETag(resourceInfo, true);
+ long lastModified = resourceInfo.date;
+
+ Date date = null;
+
+ // Parsing the HTTP Date
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(headerValue);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+
+ if (date == null) {
+
+ // If the ETag the client gave does not match the entity
+ // etag, then the entire entity is returned.
+ if (!eTag.equals(headerValue.trim()))
+ return null;
+
+ } else {
+
+ // If the timestamp of the entity the client got is older than
+ // the last modification date of the entity, the entire entity
+ // is returned.
+ if (lastModified > (date.getTime() + 1000))
+ return null;
+
+ }
+
+ }
+
+ long fileLength = resourceInfo.length;
+
+ if (fileLength == 0)
+ return null;
+
+ // Retrieving the range header (if any is specified
+ String rangeHeader = request.getHeader("Range");
+
+ if (rangeHeader == null)
+ return null;
+ // bytes is the only range unit supported (and I don't see the point
+ // of adding new ones).
+ if (!rangeHeader.startsWith("bytes")) {
+ response.sendError
+ (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return null;
+ }
+
+ rangeHeader = rangeHeader.substring(6);
+
+ // Vector which will contain all the ranges which are successfully
+ // parsed.
+ Vector result = new Vector();
+ StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");
+
+ // Parsing the range list
+ while (commaTokenizer.hasMoreTokens()) {
+ String rangeDefinition = commaTokenizer.nextToken();
+
+ Range currentRange = new Range();
+ currentRange.length = fileLength;
+
+ int dashPos = rangeDefinition.indexOf('-');
+
+ if (dashPos == -1) {
+ response.sendError
+ (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return null;
+ }
+
+ if (dashPos == 0) {
+
+ try {
+ long offset = Long.parseLong(rangeDefinition);
+ currentRange.start = fileLength + offset;
+ currentRange.end = fileLength - 1;
+ } catch (NumberFormatException e) {
+ response.sendError
+ (HttpServletResponse
+ .SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return null;
+ }
+
+ } else {
+
+ try {
+ currentRange.start = Long.parseLong
+ (rangeDefinition.substring(0, dashPos));
+ if (dashPos < rangeDefinition.length() - 1)
+ currentRange.end = Long.parseLong
+ (rangeDefinition.substring
+ (dashPos + 1, rangeDefinition.length()));
+ else
+ currentRange.end = fileLength - 1;
+ } catch (NumberFormatException e) {
+ response.sendError
+ (HttpServletResponse
+ .SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return null;
+ }
+
+ }
+
+ if (!currentRange.validate()) {
+ response.sendError
+ (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return null;
+ }
+
+ result.addElement(currentRange);
+ }
+
+ return result;
+ }
+
+
+ // ------------------------------------------------------ Range Inner Class
+
+
+ private class Range {
+
+ public long start;
+ public long end;
+ public long length;
+
+ /**
+ * Validate range.
+ */
+ public boolean validate() {
+ return ( (start >= 0) && (end >= 0) && (length > 0)
+ && (start <= end) && (end < length) );
+ }
+
+ }
+
+
+ // ---------------------------------------------- ResourceInfo Inner Class
+
+
+ private class ResourceInfo {
+
+
+ /**
+ * Constructor.
+ *
+ * @param pathname Path name of the file
+ */
+ public ResourceInfo(String path, NodeRevisionDescriptor properties) {
+
+ this.path = path;
+ this.exists = true;
+ this.creationDate = properties.getCreationDateAsDate().getTime();
+ this.date = properties.getLastModifiedAsDate().getTime();
+ this.httpDate = properties.getLastModified();
+ this.length = properties.getContentLength();
+
+ }
+
+
+ public String path;
+ public long creationDate;
+ public String httpDate;
+ public long date;
+ public long length;
+ //public boolean collection;
+ public boolean exists;
+
+
+ /**
+ * Test if the associated resource exists.
+ */
+ public boolean exists() {
+ return exists;
+ }
+
+
+ /**
+ * String representation.
+ */
+ public String toString() {
+ return path;
+ }
+
+
+ }
+
}
1.8 +6 -6 jakarta-slide/src/share/org/apache/slide/webdav/method/PutMethod.java
Index: PutMethod.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/PutMethod.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- PutMethod.java 2000/09/21 22:46:32 1.7
+++ PutMethod.java 2000/09/25 07:24:50 1.8
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/PutMethod.java,v 1.7 2000/09/21 22:46:32 remm Exp $
- * $Revision: 1.7 $
- * $Date: 2000/09/21 22:46:32 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/PutMethod.java,v 1.8 2000/09/25 07:24:50 remm Exp $
+ * $Revision: 1.8 $
+ * $Date: 2000/09/25 07:24:50 $
*
* ====================================================================
*
@@ -168,7 +168,7 @@
// Last modification date
DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
property = new NodeProperty("getlastmodified",
- formatter.format(new Date()),
+ new Date(),
true);
revisionDescriptor.setProperty(property);
@@ -204,7 +204,7 @@
// Creation date
DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
property = new NodeProperty("creationdate",
- formatter.format(new Date()),
+ new Date(),
true);
revisionDescriptor.setProperty(property);
@@ -242,7 +242,7 @@
// Last modification date
property = new NodeProperty
- ("getlastmodified", formatter.format(new Date()), true);
+ ("getlastmodified", new Date(), true);
revisionDescriptor.setProperty(property);
// Etag generation
1.8 +23 -3 jakarta-slide/src/share/org/apache/slide/webdav/method/WebdavMethod.java
Index: WebdavMethod.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/WebdavMethod.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- WebdavMethod.java 2000/09/20 06:06:18 1.7
+++ WebdavMethod.java 2000/09/25 07:24:51 1.8
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/WebdavMethod.java,v 1.7 2000/09/20 06:06:18 remm Exp $
- * $Revision: 1.7 $
- * $Date: 2000/09/20 06:06:18 $
+ * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/webdav/method/WebdavMethod.java,v 1.8 2000/09/25 07:24:51 remm Exp $
+ * $Revision: 1.8 $
+ * $Date: 2000/09/25 07:24:51 $
*
* ====================================================================
*
@@ -436,6 +436,26 @@
}
+ /**
+ * Tests if a resource is a collection.
+ */
+ protected boolean isCollection(NodeRevisionDescriptor revisionDescriptor) {
+
+ boolean result = false;
+
+ if (revisionDescriptor == null)
+ return true;
+
+ NodeProperty property = revisionDescriptor.getProperty("resourcetype");
+
+ if ((property != null)
+ && (property.getValue().equals("<collection/>"))) {
+ result = true;
+ }
+
+ return result;
+
+ }
/**
* Parse WebDAV XML query.
*