KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > webdav > method > AbstractWebdavMethod


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java,v 1.43.2.10 2004/11/30 07:05:53 masonjm Exp $
3  * $Revision: 1.43.2.10 $
4  * $Date: 2004/11/30 07:05:53 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2002 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */

23
24 package org.apache.slide.webdav.method;
25
26 import java.io.IOException JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.io.StringWriter JavaDoc;
29 import java.text.ParseException JavaDoc;
30 import java.text.SimpleDateFormat JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.Date JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Locale JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39
40 import javax.servlet.http.HttpServletRequest JavaDoc;
41 import javax.servlet.http.HttpServletResponse JavaDoc;
42 import javax.transaction.SystemException JavaDoc;
43 import javax.transaction.Transaction JavaDoc;
44
45 import org.apache.commons.transaction.locking.GenericLock;
46 import org.apache.commons.transaction.locking.MultiLevelLock;
47 import org.apache.commons.transaction.util.PrintWriterLogger;
48
49 import org.apache.slide.authenticate.CredentialsToken;
50 import org.apache.slide.common.Domain;
51 import org.apache.slide.common.NamespaceAccessToken;
52 import org.apache.slide.common.NestedSlideException;
53 import org.apache.slide.common.ServiceAccessException;
54 import org.apache.slide.common.SlideException;
55 import org.apache.slide.common.SlideToken;
56 import org.apache.slide.content.Content;
57 import org.apache.slide.content.NodeProperty;
58 import org.apache.slide.content.NodeRevisionContent;
59 import org.apache.slide.content.NodeRevisionDescriptor;
60 import org.apache.slide.content.NodeRevisionDescriptors;
61 import org.apache.slide.content.NodeProperty.NamespaceCache;
62 import org.apache.slide.lock.Lock;
63 import org.apache.slide.lock.NodeLock;
64 import org.apache.slide.macro.Macro;
65 import org.apache.slide.search.Search;
66 import org.apache.slide.security.Security;
67 import org.apache.slide.structure.ObjectNode;
68 import org.apache.slide.structure.ObjectNotFoundException;
69 import org.apache.slide.structure.Structure;
70 import org.apache.slide.transaction.ExternalTransactionContext;
71 import org.apache.slide.util.Messages;
72 import org.apache.slide.util.XMLValue;
73 import org.apache.slide.util.logger.Logger;
74 import org.apache.slide.webdav.WebdavException;
75 import org.apache.slide.webdav.WebdavMethod;
76 import org.apache.slide.webdav.WebdavServletConfig;
77 import org.apache.slide.webdav.util.BindConstants;
78 import org.apache.slide.webdav.util.DeltavConstants;
79 import org.apache.slide.webdav.util.NotificationConstants;
80 import org.apache.slide.webdav.util.PreconditionViolationException;
81 import org.apache.slide.webdav.util.TransactionConstants;
82 import org.apache.slide.webdav.util.UnlockListenerImpl;
83 import org.apache.slide.webdav.util.UriHandler;
84 import org.apache.slide.webdav.util.ViolatedPrecondition;
85 import org.apache.slide.webdav.util.WebdavConstants;
86 import org.apache.slide.webdav.util.WebdavStatus;
87 import org.apache.slide.webdav.util.WebdavUtils;
88 import org.jdom.Document;
89 import org.jdom.Element;
90 import org.jdom.JDOMException;
91 import org.jdom.Namespace;
92 import org.jdom.input.SAXBuilder;
93 import org.jdom.output.XMLOutputter;
94
95 /**
96  * WebDAV method.
97  *
98  */

99 public abstract class AbstractWebdavMethod
100     implements WebdavMethod, WebdavConstants, DeltavConstants, BindConstants, NotificationConstants, TransactionConstants {
101
102
103     // -------------------------------------------------------------- Constants
104

105     /**
106      * String constant for <code>no-cache</code>.
107      */

108     protected static final String JavaDoc NO_CACHE = "no-cache";
109
110     /**
111      * String constant for <code>http://</code>.
112      */

113     public static final String JavaDoc HTTP_PROTOCOL = "http://";
114
115     /**
116      * String constant for <code>HTTP/1.1</code>.
117      */

118     public static final String JavaDoc HTTP_VERSION = "HTTP/1.1";
119
120     /**
121      * String constant for <code>text/xml</code>.
122      */

123     public static final String JavaDoc TEXT_XML = "text/xml";
124
125     /**
126      * String constant for <code>text/xml; charset="UTF-8"</code>.
127      */

128     public static final String JavaDoc TEXT_XML_UTF_8 = "text/xml; charset=\"UTF-8\"";
129
130     /**
131      * The indent to use in the XML response.
132      */

133     public static final String JavaDoc XML_RESPONSE_INDENT = " ";
134
135     private static final String JavaDoc LOG_CHANNEL =
136         AbstractWebdavMethod.class.getName();
137
138     // public static final String PRINCIPAL =
139
// "org.apache.slide.webdav.method.principal";
140

141     public static final int INFINITY = Integer.MAX_VALUE;
142     
143     protected static final Namespace DNSP = NamespaceCache.DEFAULT_NAMESPACE;
144     
145     /**
146      * The set of SimpleDateFormat formats to use in getDateHeader().
147      */

148     protected static final SimpleDateFormat JavaDoc formats[] = {
149         new SimpleDateFormat JavaDoc("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
150             new SimpleDateFormat JavaDoc("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
151             new SimpleDateFormat JavaDoc("EEE MMMM d HH:mm:ss yyyy", Locale.US)
152     };
153
154     // create global read/write lock to allow for deadlock-free access
155
private static final MultiLevelLock GLOBAL_LOCK = new GenericLock("global", 2, new PrintWriterLogger(
156             new PrintWriter JavaDoc(System.out), LOG_CHANNEL, false));
157     
158     // ----------------------------------------------------- Instance Variables
159

160
161     /**
162      * Requested Slide-Uri.
163      */

164     protected String JavaDoc requestUri;
165
166
167     /**
168      * Servlet request.
169      */

170     protected HttpServletRequest JavaDoc req;
171
172
173     /**
174      * Servlet response.
175      */

176     protected HttpServletResponse JavaDoc resp;
177
178
179     /**
180      * Configuration.
181      */

182     protected WebdavServletConfig config;
183     
184     protected String JavaDoc slideContextPath;
185
186
187     /**
188      * Request body.
189      */

190     protected String JavaDoc requestBody;
191
192
193     /**
194      * Namespace access token.
195      */

196     protected NamespaceAccessToken token;
197
198
199     /**
200      * Structure helper.
201      */

202     protected Structure structure;
203
204
205     /**
206      * Content helper.
207      */

208     protected Content content;
209
210
211     /**
212      * Security helper.
213      */

214     protected Security security;
215
216
217     /**
218      * Lock helper.
219      */

220     protected Lock lock;
221
222
223     /** wam
224      * Search helper.
225      */

226     protected Search search;
227
228
229     /**
230      * Macro helper.
231      */

232     protected Macro macro;
233
234
235     /**
236      * Slide token.
237      */

238     protected SlideToken slideToken;
239
240     /**
241      * The request content (XML) Document.
242      */

243     private Document requestContentDocument = null;
244
245     /**
246      * Indicates if the request content has already been parsed.
247      */

248     private boolean isRequestContentParsed = false;
249
250     /**
251      * Request headers
252      */

253     protected RequestHeaders requestHeaders = new RequestHeaders();
254
255     // -------------------------------------------------- Static Initialization
256

257
258 // static {
259
//
260
// // Load the MD5 helper used to calculate signatures.
261
// try {
262
// md5Helper = MessageDigest.getInstance("MD5");
263
// } catch (NoSuchAlgorithmException e) {
264
// System.out.println(e.toString());
265
// throw new IllegalStateException();
266
// }
267
// }
268

269     
270     // ----------------------------------------------------------- Constructors
271

272     
273     /**
274      * Constructor.
275      *
276      * @param token the token for accessing the namespace
277      * @param config configuration of the WebDAV servlet
278      */

279     public AbstractWebdavMethod(NamespaceAccessToken token,
280                                 WebdavServletConfig config) {
281         
282         this.config = config;
283         this.token = token;
284         
285         // initialize helpers
286
structure = token.getStructureHelper();
287         content = token.getContentHelper();
288         security = token.getSecurityHelper();
289         lock = token.getLockHelper();
290         macro = token.getMacroHelper();
291     }
292     
293     
294     // -------------------------------------------- WebdavMethod Implementation
295

296     
297     /**
298      * Exceute method.
299      *
300      * @exception WebdavException
301      */

302     public void run(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc resp)
303         throws WebdavException {
304         
305         // XXX this is a pretty ugly spot and way to set this
306
// TODO find a better solution
307
UriHandler.setGloballyUseHistoryCollectionHack(useHistoryCollectionHack());
308         
309         this.req = req;
310         this.resp = resp;
311         this.slideToken = WebdavUtils.getSlideToken(req);
312         String JavaDoc forceLowercaseLogin = token.getNamespaceConfig().getParameter("force-lowercase-login");
313         if ("true".equals(forceLowercaseLogin)) {
314             String JavaDoc name = slideToken.getCredentialsToken().getPrincipal().getName().toLowerCase();
315             slideToken.setCredentialsToken(new CredentialsToken(name));
316         }
317         
318         this.requestUri = WebdavUtils.getRelativePath(req, config);
319         this.slideContextPath = req.getContextPath();
320         if (!this.config.isDefaultServlet()) {
321             this.slideContextPath += req.getServletPath();
322         }
323         
324         // TODO this is a workaround to pass the slideContextPath to the search
325
// implementation
326
slideToken.addParameter("slideContextPath", this.slideContextPath);
327         
328         parseRequestHeaders();
329         
330         boolean transactionIsStarted = false;
331         boolean globalLockObtained = false;
332         String JavaDoc txId = null;
333         try {
334             parseRequest();
335             
336             ExternalTransactionContext externalTransaction = null;
337             
338             txId = requestHeaders.getTxId();
339             if (txId != null) {
340                 externalTransaction = ExternalTransactionContext.lookupContext(txId);
341                 if (externalTransaction != null) {
342                     Domain.log("Using external transaction " + txId, LOG_CHANNEL, Logger.INFO);
343                     slideToken.setExternalTx();
344                     // pure reads must be guaranteed to be inside transaction as well
345
slideToken.setForceStoreEnlistment(true);
346                     Transaction JavaDoc tx = externalTransaction.getTransaction();
347                     token.getTransactionManager().resume(tx);
348                     transactionIsStarted = true;
349                 }
350             }
351             
352             if (!slideToken.isExternalTransaction()) {
353                 token.begin();
354                 transactionIsStarted = true;
355                 if (txForAllRequests()) {
356                     slideToken.setForceStoreEnlistment(true);
357                 }
358
359                 if (this instanceof ReadMethod) {
360                     assureGlobalReadLock();
361                 } else if (this instanceof WriteMethod) {
362                     assureGlobalWriteLock();
363                 }
364                 globalLockObtained = true;
365             }
366
367             // Was this call made to finalize a transaction?
368
boolean isEndofTransactionxUnlock = false;
369             if (this instanceof UnlockMethod)
370             {
371                 UnlockMethod meth = (UnlockMethod)this;
372                 if (meth.getCommand() != UnlockMethod.NO_TRANSACTION)
373                     isEndofTransactionxUnlock = true;
374             }
375
376             /*
377              * Check for object existence and cleanup locks only if we're not
378              * unlocking as part of finalizing a transaction. Otherwise we
379              * are making calls to the store that require a transaction to
380              * be in process while we're trying to commit or abort it the
381              * current transaction.
382              */

383             if (!isEndofTransactionxUnlock)
384             {
385                 try {
386                     // retrive to check it exists, otherwise it can't have locks
387
structure.retrieve(slideToken, requestUri);
388                     // clear expired lock-tokens
389
UnlockListenerImpl listener = new UnlockListenerImpl(slideToken, token, config, req, resp);
390                     lock.clearExpiredLocks(slideToken, requestUri, listener);
391                 
392                     if (listener.getUnlockCount() > 0) {
393                         // If we have have cleared any lock or any lock-null resource in
394
// the previous step we commit this changes, otherwise they will
395
// be lost if executeRequest() exits with an exception (e.g.
396
// because of Not Found 404)
397
token.commit();
398                         token.begin();
399                     }
400                 } catch (ObjectNotFoundException e) {
401                     // ignore, it can't have locks
402
}
403             }
404             
405             executeRequest();
406             
407             if (!slideToken.isExternalTransaction() && transactionIsStarted) {
408                 token.commit();
409                 transactionIsStarted = false;
410             }
411         } catch (WebdavException ex) {
412             // Ignore the WebDav Exception and assume that the response code
413
// is already set.
414
} catch (SlideException ex) {
415             int statusCode = getErrorCode( ex );
416             sendError( statusCode, ex );
417             // do not throw exception as the response code has already been set,
418
// otherwise the servlet will log this as an error and issue a stack trace
419
// throw new WebdavException( statusCode );
420
} catch (Exception JavaDoc ex) {
421             token.getLogger().log(ex,LOG_CHANNEL,Logger.ERROR);
422             int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
423             sendError( statusCode, ex );
424             throw new WebdavException( statusCode );
425         } finally {
426             if (!slideToken.isExternalTransaction() && transactionIsStarted) {
427                 // Something went wrong, we are here and the TA is still open
428
try {
429                     token.rollback();
430                 } catch (Exception JavaDoc e) {
431                    // TODO
432
e.printStackTrace();
433                 }
434             }
435             if (slideToken.isExternalTransaction()) {
436                 Transaction JavaDoc transaction;
437                 try {
438                     if (token.getStatus() == javax.transaction.Status.STATUS_ACTIVE) {
439                         transaction = token.getTransactionManager().suspend();
440                         if (transaction != null) {
441                             ExternalTransactionContext.registerContext(txId, transaction);
442                         }
443                     }
444                 } catch (SystemException JavaDoc e) {
445                     // TODO Auto-generated catch block
446
e.printStackTrace();
447                 }
448             }
449             if (globalLockObtained) {
450                 releaseGlobalLock();
451             }
452         }
453     }
454
455     // --------------------------------------------------------- Public Methods
456

457
458     /**
459      * Returns the configuration of the WebdavServlet.
460      *
461      * @return WebdavServletConfig
462      */

463     public WebdavServletConfig getConfig() {
464
465         return config;
466     }
467
468
469     /**
470      * Return an absolute URL path (absolute in the HTTP sense) based on a Slide
471      * path.
472      */

473     public String JavaDoc getFullPath(String JavaDoc slidePath) {
474        return WebdavUtils.getAbsolutePath(slidePath, req, getConfig());
475     }
476
477
478     /**
479      * Returns a Slide path based on an absolute URL
480      * (absolute in the HTTP sense)
481      */

482     public String JavaDoc getSlidePath(String JavaDoc fullpath) {
483         return WebdavUtils.getSlidePath(fullpath, getSlideContextPath());
484     }
485     
486     public String JavaDoc getSlideContextPath() {
487         return this.slideContextPath;
488     }
489     
490     // ------------------------------------------------------ Protected Methods
491

492     /**
493      * Read request contents.
494      *
495      * @param req Request object handed out by the servlet container
496      * @return char[] Array of char which contains the body of the request
497      */

498     protected void readRequestContent() {
499         
500         if (req.getContentLength() == 0)
501             return;
502         
503         // TODO : Modify this and make it chunking aware
504

505         try {
506             requestBody = new String JavaDoc(NodeRevisionContent.read(req.getInputStream()),
507                                      getEncodingString(req.getCharacterEncoding()));
508         }
509         catch (Exception JavaDoc e) {
510             token.getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
511         }
512     }
513     
514     
515     
516     /**
517      * Translate the encoding string into a proper Java encoding String.
518      */

519     public static String JavaDoc getEncodingString(String JavaDoc httpEncoding) {
520         String JavaDoc result = httpEncoding;
521         if (result == null) result = System.getProperty("file.encoding");
522         if (result.startsWith("\"")) result = result.substring(1, result.length());
523         if (result.endsWith("\"")) result = result.substring(0, result.length()-1);
524         return result;
525     }
526     
527     
528     /**
529      * Method parseHeaders
530      *
531      */

532     private void parseRequestHeaders() throws WebdavException {
533         requestHeaders.parse();
534     }
535     
536     /**
537      * Test if a resource given by a path is a collection
538      */

539     protected boolean isCollection(String JavaDoc path) {
540         return WebdavUtils.isCollection(token, slideToken, path);
541     }
542     
543     /**
544      * Test whether the resource given by lowerNode is a descendant of the
545      * resource given by upperNode
546      *
547      * @param lowerNode an ObjectNode
548      * @param upperNode an ObjectNode
549      *
550      * @return true, if lowerNode is below upperNode in the namespace
551      * @throws ServiceAccessException
552      *
553      */

554     protected boolean isDescendant( ObjectNode lowerNode, ObjectNode upperNode ) throws ServiceAccessException {
555         if (lowerNode.getUuri().equals(upperNode.getUuri())) {
556             return true;
557         }
558         if (upperNode.hasBinding(lowerNode)) {
559             return true;
560         }
561         
562         NodeRevisionDescriptors lowerNrds = null;
563         NodeRevisionDescriptor lowerNrd = null;
564         try {
565             lowerNrds = content.retrieve(slideToken, lowerNode.getUri());
566             lowerNrd = content.retrieve(slideToken, lowerNrds);
567             
568             NodeProperty psProp = lowerNrd.getProperty(P_PARENT_SET);
569             XMLValue xv = new XMLValue( String.valueOf(psProp.getValue()) );
570             Iterator JavaDoc i = xv.getList().iterator();
571             while (i.hasNext()) {
572                 // iterate over parent elements
573
Element pElm = (Element)i.next();
574                 String JavaDoc hrPath = pElm.getChild( E_HREF, DNSP ).getText();
575                 ObjectNode hrNode = structure.retrieve( slideToken, hrPath );
576                 return isDescendant( hrNode, upperNode );
577             }
578         } catch (ServiceAccessException e) {
579             throw e;
580         } catch (Exception JavaDoc e) {}
581         
582         return false;
583     }
584     
585     protected boolean isRequestChunked() {
586         String JavaDoc te = req.getHeader("Transfer-Encoding");
587         if (te == null) return false;
588         return te.indexOf("chunked") != -1;
589     }
590     
591     /**
592      * Parse WebDAV XML query.
593      *
594      * @exception WebdavException
595      */

596     protected abstract void parseRequest()
597         throws WebdavException;
598     
599     
600     
601     /**
602      * Returns the request content (XML) Document.
603      *
604      * @return the request content (XML) Document.
605      */

606     protected Document getRequestContent() {
607         return requestContentDocument;
608     }
609     
610     //--
611

612     /**
613      * precondition: sourceUri != null
614      */

615     protected String JavaDoc parseUri(String JavaDoc uri) throws WebdavException { // TODO: better name
616
int protocolIndex = uri.indexOf("://");
617         if (protocolIndex >= 0) {
618             // if the Destination URL contains the protocol, we can safely
619
// trim everything upto the first "/" character after "://"
620
int firstSeparator =
621                 uri.indexOf("/", protocolIndex + 4);
622             if (firstSeparator < 0) {
623                 uri = "/";
624             } else {
625                 uri = uri.substring(firstSeparator);
626             }
627         } else {
628             String JavaDoc hostName = req.getServerName();
629             if ((hostName != null) && (uri.startsWith(hostName))) {
630                 uri = uri.substring(hostName.length());
631             }
632             
633             int portIndex = uri.indexOf(":");
634             if (portIndex >= 0) {
635                 uri = uri.substring(portIndex);
636             }
637             
638             if (uri.startsWith(":")) {
639                 int firstSeparator = uri.indexOf("/");
640                 if (firstSeparator < 0) {
641                     uri = "/";
642                 } else {
643                     uri = uri.substring(firstSeparator);
644                 }
645             }
646         }
647         
648         // headers are "ISO-8859-1" encoded [not any more with TC 4.1.18
649
// destinationUri = WebdavUtils.decodeURL(WebdavUtils.fixTomcatURL(destinationUri, "ISO-8859-1"));
650
uri = WebdavUtils.decodeURL(uri);
651         
652         String JavaDoc contextPath = req.getContextPath();
653         if ((contextPath != null) && (uri.startsWith(contextPath))) {
654             uri = uri.substring(contextPath.length());
655         }
656         
657         String JavaDoc pathInfo = req.getPathInfo();
658         if (pathInfo != null) {
659             String JavaDoc servletPath = req.getServletPath();
660             if ((servletPath != null) && (uri.startsWith(servletPath))) {
661                 uri = uri.substring(servletPath.length());
662             }
663         }
664         uri = getConfig().getScope() + uri;
665         
666         return uri;
667     }
668     
669     protected Element parseRequestContent(String JavaDoc rootName) throws JDOMException, IOException JavaDoc {
670         Document document;
671         Element root;
672         
673         document = parseRequestContent();
674         if (document == null) {
675             throw new JDOMException("Request content missing");
676         }
677         root = document.getRootElement();
678         if( root == null || !root.getName().equals(rootName) ) {
679             Domain.warn( "Root element must be "+rootName );
680             throw new JDOMException("Root element must be <"+rootName+">");
681         }
682         return root;
683     }
684     
685     /**
686      * Parses the request content (XML) Document.
687      *
688      * @return the request content (XML) Document.
689      *
690      * @throws IOException if an I/O error occurred.
691      * @throws JDOMException if parsing the document failed.
692      */

693     protected Document parseRequestContent() throws JDOMException, IOException JavaDoc {
694         
695         if (isRequestContentParsed) {
696             return requestContentDocument;
697         }
698                 
699         if (req.getContentLength() == 0 || req.getContentLength() == -1) {
700             return requestContentDocument;
701         }
702         
703         try {
704             requestContentDocument = new SAXBuilder().build(req.getInputStream());
705             isRequestContentParsed = true;
706         }
707         catch (JDOMException e) {
708             if (e.getCause() instanceof IOException JavaDoc) {
709                 throw (IOException JavaDoc)e.getCause();
710             }
711             else {
712                 throw e;
713             }
714         }
715         
716         return requestContentDocument;
717     }
718     
719     
720     /**
721      * Generate XML response.
722      *
723      * @exception WebdavException
724      */

725     protected abstract void executeRequest()
726         throws WebdavException, IOException JavaDoc;
727     
728     
729     /**
730      * Simulate MS IIS5 ?
731      *
732      * @return boolean
733      */

734     protected boolean isMsProprietarySupport() {
735         return (token.getNamespaceConfig().getParameter("ms") != null);
736     }
737
738     /**
739      * Sends a precondition vilolation response.
740      *
741      * @param pve the ProconditionViolationException that describes the violated
742      * precondition.
743      */

744     protected void sendPreconditionViolation(PreconditionViolationException pve) throws IOException JavaDoc {
745         
746         if (pve != null) {
747             
748             ViolatedPrecondition violatedPrecondition = pve.getViolatedPrecondition();
749             
750             int statusCode = violatedPrecondition.getStatusCode();
751             printStackTrace( pve, statusCode );
752             String JavaDoc statusText = WebdavStatus.getStatusText(statusCode);
753             if (violatedPrecondition.getExplanation() != null) {
754                 statusText = statusText+": "+violatedPrecondition.getExplanation();
755             }
756             resp.setStatus(statusCode, statusText);
757
758             resp.setContentType(TEXT_XML_UTF_8);
759
760             org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
761             format.setIndent(XML_RESPONSE_INDENT);
762             new XMLOutputter(format).
763                 output(new Document(MethodUtil.getPreconditionViolationError(pve.getViolatedPrecondition())), resp.getWriter());
764         }
765     }
766     
767     // -------------------------------------------------------- Private Methods
768

769     
770     /**
771      * Get return status based on exception type.
772      */

773     protected int getErrorCode(Throwable JavaDoc ex) {
774         return WebdavUtils.getErrorCode(ex);
775     }
776     
777     
778     /**
779      * Get return status based on exception type.
780      */

781     protected int getErrorCode(SlideException ex) {
782         return WebdavUtils.getErrorCode(ex);
783     }
784     
785     
786     
787     /**
788      * Get return status based on exception type.
789      */

790     protected int getErrorCode(ServiceAccessException ex) {
791         return WebdavUtils.getErrorCode(ex);
792     }
793     
794     
795     /**
796      * Returns the value of a boolean init parameter of the servlet.
797      * Default value: false.
798      */

799     protected boolean getBooleanInitParameter( String JavaDoc name ) {
800         return "true".equalsIgnoreCase( getConfig().getInitParameter(name) );
801     }
802
803     /**
804      * Checks whether the hack that restricts the size of collections in
805      * the history collection is configured to be used.
806      */

807     protected boolean useHistoryCollectionHack() {
808         return "true".equalsIgnoreCase(token.getNamespaceConfig().getParameter("history-collection-hack"));
809     }
810
811     /**
812      * Checks whether all requests shall be done inside of transactions.
813      */

814     protected boolean txForAllRequests() {
815         return "true".equalsIgnoreCase(token.getNamespaceConfig().getParameter("all-methods-in-transactions"));
816     }
817
818     /**
819      * Checks if Slide is configured to allow at most a single write request at a time.
820      * @return <code>true</code> if there can be at most one write request at a time
821      */

822     protected boolean isSequentialWrite() {
823         String JavaDoc sm = token.getNamespaceConfig().getParameter("sequential-mode");
824         return ("write".equalsIgnoreCase(sm) || "full".equalsIgnoreCase(sm));
825     }
826     
827     /**
828      * Checks if Slide is configured to allow reads while write requests are being executed.
829      * @return <code>true</code> if reads are disallowed during writes
830      */

831     protected boolean isSequentialRead() {
832         return "full".equalsIgnoreCase(token.getNamespaceConfig().getParameter("sequential-mode"));
833     }
834     
835     protected void assureGlobalReadLock() {
836         if (isSequentialRead()) {
837             try {
838                 GLOBAL_LOCK.acquire(this, 1, true, true, Long.MAX_VALUE);
839             } catch (InterruptedException JavaDoc e) {
840             }
841         }
842     }
843     
844     protected void assureGlobalWriteLock() {
845         if (isSequentialWrite()) {
846             try {
847                 GLOBAL_LOCK.acquire(this, 2, true, true, Long.MAX_VALUE);
848             } catch (InterruptedException JavaDoc e) {
849             }
850         }
851     }
852     
853     protected void releaseGlobalLock() {
854         GLOBAL_LOCK.release(this);
855     }
856
857    /**
858      * Returns the value of an integer init parameter of the servlet.
859      * Default value: -1.
860      */

861     protected int getIntInitParameter( String JavaDoc name ) {
862         int result = -1;
863         try {
864             result = Integer.parseInt( getConfig().getInitParameter(name) );
865         }
866         catch( NumberFormatException JavaDoc x ) {};
867         return result;
868     }
869     
870     /**
871      * Error handling routine
872      */

873     protected void sendError( int statusCode ) {
874         try { resp.sendError( statusCode ); } catch( Throwable JavaDoc x ) {};
875     }
876     
877     /**
878      * Error handling routine
879      */

880     protected void sendError( int statusCode, String JavaDoc message ) {
881         String JavaDoc statusText =
882             WebdavStatus.getStatusText(statusCode)+
883             (message != null
884                  ? ": "+Messages.format( message, (Object JavaDoc)null )
885                  : "");
886         try { resp.sendError( statusCode, statusText ); } catch( Throwable JavaDoc x ) {};
887     }
888     
889     /**
890      * Error handling routine
891      */

892     protected void sendError( int statusCode, String JavaDoc message, Object JavaDoc[] args ) {
893         String JavaDoc statusText =
894             WebdavStatus.getStatusText(statusCode)+": "+
895             Messages.format( message, args );
896         try { resp.sendError( statusCode, statusText ); } catch( Throwable JavaDoc x ) {};
897     }
898     
899     /**
900      * Error handling routine
901      */

902     protected void sendError( int statusCode, Throwable JavaDoc t ) {
903         printStackTrace( t, statusCode );
904         String JavaDoc explanation = (t == null || t.getMessage() == null || "".equals(t.getMessage())
905                                   ? Messages.format(t.getClass().getName(), (Object JavaDoc)null)
906                                   : t.getMessage()
907                              );
908         String JavaDoc statusText =
909             WebdavStatus.getStatusText(statusCode)+": "+explanation;
910         try { resp.sendError( statusCode, statusText ); } catch( Throwable JavaDoc x ) {};
911     }
912     
913     /**
914      * Prints the stack trace of the given exception if the specified status code
915      * is greater-or-equal the value of the servlet init-parameter printStackTrace.
916      * If the init-parameter is not specified, stack traces are printed for status
917      * codes >= 500.
918      */

919     protected void printStackTrace( Throwable JavaDoc x, int statusCode ) {
920         int printStackTraceFrom = getIntInitParameter( "printStackTrace" );
921         if( printStackTraceFrom < 0 )
922             printStackTraceFrom = 500;
923         if( statusCode >= printStackTraceFrom )
924             x.printStackTrace();
925     }
926     
927     
928     /**
929      * Generate status text.
930      *
931      * @param parentElement the parent Element to append to.
932      * @param href Slide-Uri of the object
933      * @param statusCode HTTP status code of the error
934      */

935     protected void generateStatusText(Element parentElement, String JavaDoc href, int statusCode) {
936         
937         Element hrefElement = new Element(E_HREF, DNSP);
938         parentElement.addContent(hrefElement);
939         hrefElement.setText(getFullPath(href));
940         Element statusElement = new Element(E_STATUS, DNSP);
941         parentElement.addContent(statusElement);
942         statusElement.setText("HTTP/1.1 " + statusCode + " "
943                                   + WebdavStatus.getStatusText(statusCode));
944     }
945     
946     /**
947      * Generate an XML error message.
948      *
949      * @param macroException Nested exception
950      * @return String XML message
951      */

952     protected String JavaDoc generateErrorMessage
953         (NestedSlideException nestedException) {
954         
955         Element multistatus = new Element(E_MULTISTATUS, DNSP);
956         
957         Enumeration JavaDoc nestedExceptionsList =
958             nestedException.enumerateExceptions();
959         while (nestedExceptionsList.hasMoreElements()) {
960             
961             Element response = new Element(E_RESPONSE, DNSP);
962             multistatus.addContent(response);
963             SlideException ex =
964                 (SlideException) nestedExceptionsList.nextElement();
965             generateStatusText(response, MethodUtil.getErrorMessage(ex),
966                                getErrorCode(ex));
967             if (ex instanceof PreconditionViolationException) {
968                 response.addContent(MethodUtil.getPreconditionViolationResponseDescription((PreconditionViolationException)ex));
969             }
970             
971         }
972         
973         StringWriter JavaDoc stringWriter = new StringWriter JavaDoc();
974         try {
975             new XMLOutputter().output(multistatus, stringWriter);
976         }
977         catch (IOException JavaDoc e) {
978             Domain.log(e);
979         }
980         return stringWriter.toString();
981         
982     }
983     
984     protected boolean exists( String JavaDoc uriStr ) throws SlideException {
985         boolean destinationExists = true;
986         
987         try {
988             content.retrieve(slideToken, uriStr);
989         }
990         catch (ObjectNotFoundException x) {
991             destinationExists = false;
992         }
993         return destinationExists;
994     }
995     
996     protected boolean isLocked( String JavaDoc uriStr ) throws ServiceAccessException {
997         // use a non-blocking slide token.
998
boolean isLocked = false;
999         try {
1000            Enumeration JavaDoc locks = lock.enumerateLocks (slideToken, uriStr, false);
1001            while (locks.hasMoreElements()) {
1002                if (lock.isLocked(slideToken,(NodeLock) locks.nextElement(),false)) {
1003                    isLocked = true;
1004                }
1005            }
1006        }
1007        catch (ServiceAccessException x) {
1008            throw x;
1009        }
1010        catch (SlideException x) {
1011            // ignore silently
1012
}
1013        return isLocked;
1014    }
1015    
1016    protected boolean isLockNull( String JavaDoc uriStr ) throws ServiceAccessException {
1017        boolean isLockNull = false;
1018        try {
1019            NodeRevisionDescriptor nrd =
1020                content.retrieve(slideToken, content.retrieve(slideToken, uriStr));
1021            isLockNull = isLockNull( nrd );
1022        }
1023        catch (ServiceAccessException x) {
1024            throw x;
1025        }
1026        catch (SlideException x) {
1027            // ignore silently
1028
}
1029        return isLockNull;
1030    }
1031    
1032    protected boolean isLockNull( NodeRevisionDescriptor nrd ) {
1033        return nrd.propertyValueContains(P_RESOURCETYPE, E_LOCKNULL);
1034    }
1035    
1036    protected boolean isAutoVersionControl(String JavaDoc resourcePath) {
1037        return new Boolean JavaDoc(Domain.getParameter(I_AUTO_VERSION_CONTROL,
1038                                               I_AUTO_VERSION_CONTROL_DEFAULT,
1039                                               token.getUri(slideToken, resourcePath).getStore()))
1040            .booleanValue();
1041    }
1042    
1043    protected boolean isExcludedForVersionControl(String JavaDoc resourcePath) {
1044        String JavaDoc versionControlExcludePaths =
1045            Domain.getParameter(I_VERSIONCONTROL_EXCLUDEPATH,
1046                                I_VERSIONCONTROL_EXCLUDEPATH_DEFAULT,
1047                                token.getUri(slideToken, resourcePath).getStore());
1048        if (versionControlExcludePaths != null && versionControlExcludePaths.length() > 0) {
1049            StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(versionControlExcludePaths, ";");
1050            while (st.hasMoreTokens()) {
1051                if (isExcluded(resourcePath, st.nextToken())) {
1052                    return true;
1053                }
1054            }
1055        }
1056        return false;
1057    }
1058    
1059    private boolean isExcluded(String JavaDoc resourcePath, String JavaDoc excludePath) {
1060        UriHandler uh = UriHandler.getUriHandler(resourcePath);
1061        if (excludePath != null && excludePath.length() > 0) {
1062            UriHandler exUh = UriHandler.getUriHandler(excludePath);
1063            if (exUh.isAncestorOf(uh)) {
1064                return true;
1065            }
1066        }
1067        return false;
1068    }
1069    
1070    /**
1071     * Check if the conditions specified in the optional If headers are
1072     * satisfied.
1073     *
1074     * @param request The servlet request we are processing
1075     * @param response The servlet response we are creating
1076     * @param resourceInfo File object
1077     * @return boolean true if the resource meets all the specified conditions,
1078     * and false if any of the conditions is not satisfied, in which case
1079     * request processing is stopped
1080     */

1081    protected boolean checkIfHeaders(HttpServletRequest JavaDoc request,
1082                                     HttpServletResponse JavaDoc response,
1083                                     ResourceInfo resourceInfo)
1084        throws IOException JavaDoc
1085    {
1086        // the ETag without apostrophes ("), we use apostrophes as delimiters
1087
// to because some clients provide If header with out apostrophes
1088
String JavaDoc eTag = getETagValue(resourceInfo, true);
1089        long lastModified = resourceInfo.date;
1090        
1091        StringTokenizer JavaDoc commaTokenizer;
1092        
1093        String JavaDoc headerValue;
1094        
1095        // Checking If-Match
1096
headerValue = request.getHeader("If-Match");
1097        if (headerValue != null) {
1098            if (headerValue.indexOf("*") == -1) {
1099                
1100                commaTokenizer = new StringTokenizer JavaDoc(headerValue, ", \"");
1101                boolean matchingTagFound = false;
1102                
1103                while (!matchingTagFound && commaTokenizer.hasMoreTokens()) {
1104                    matchingTagFound = commaTokenizer.nextToken().equals(eTag);
1105                }
1106                
1107                // If none of the given ETags match, 412 Precodition failed is
1108
// sent back
1109
if (!matchingTagFound) {
1110                    response.sendError(
1111                            HttpServletResponse.SC_PRECONDITION_FAILED);
1112                    return false;
1113                }
1114            } else {
1115                if (!resourceInfo.exists()) {
1116                    response.sendError(
1117                            HttpServletResponse.SC_PRECONDITION_FAILED);
1118                    return false;
1119                }
1120            }
1121        }
1122        
1123        // Checking If-Modified-Since
1124
headerValue = request.getHeader("If-Modified-Since");
1125        if (headerValue != null) {
1126            
1127            // If an If-None-Match header has been specified, if modified since
1128
// is ignored.
1129
if (request.getHeader("If-None-Match") == null) {
1130                Date JavaDoc date = parseHttpDate(headerValue);
1131                
1132                if ((date != null)
1133                    && (lastModified <= (date.getTime() + 1000)) ) {
1134                    // The entity has not been modified since the date
1135
// specified by the client. This is not an error case.
1136
response.sendError
1137                        (HttpServletResponse.SC_NOT_MODIFIED);
1138                    return false;
1139                }
1140            }
1141        }
1142        
1143        // Checking If-None-Match
1144
headerValue = request.getHeader("If-None-Match");
1145        if (headerValue != null) {
1146            if (headerValue.indexOf("*") == -1) {
1147                
1148                commaTokenizer = new StringTokenizer JavaDoc(headerValue, ", \"");
1149                while (commaTokenizer.hasMoreTokens()) {
1150                    if (commaTokenizer.nextToken().equals(eTag)) {
1151                        // For GET and HEAD, we respond with 304 Not Modified.
1152
// For every other method, 412 Precondition Failed
1153
if ( ("GET".equals(request.getMethod()))
1154                            || ("HEAD".equals(request.getMethod())) )
1155                        {
1156                            response.sendError(
1157                                    HttpServletResponse.SC_NOT_MODIFIED);
1158                            return false;
1159                        } else {
1160                            response.sendError(
1161                                    HttpServletResponse.SC_PRECONDITION_FAILED);
1162                            return false;
1163                        }
1164                    }
1165                }
1166            } else {
1167                if (resourceInfo.exists()) {
1168                    response.sendError(
1169                            HttpServletResponse.SC_PRECONDITION_FAILED);
1170                    return false;
1171                }
1172            }
1173        }
1174        
1175        // Checking If-Unmodified-Since
1176
headerValue = request.getHeader("If-Unmodified-Since");
1177        if (headerValue != null) {
1178            Date JavaDoc date = parseHttpDate(headerValue);
1179            
1180            if ( (date != null) && (lastModified > date.getTime()) ) {
1181                // The entity has not been modified since the date
1182
// specified by the client. This is not an error case.
1183
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
1184                return false;
1185            }
1186        }
1187        return true;
1188    }
1189    
1190    /**
1191     * Parses the date string given as one of the {@link #formats}.
1192     * If the date does not fit any of these formats it returns <code>null</code>.
1193     *
1194     * @param headerValue date string from and HTTP header (e.g. If-Modified)
1195     * @return a Date representing the date given of <code>null</code> if
1196     * the string has no valid format.
1197     */

1198    protected Date JavaDoc parseHttpDate(String JavaDoc headerValue) {
1199        Date JavaDoc date = null;
1200        
1201        // Parsing the HTTP Date
1202
for (int i = 0; (date == null) && (i < formats.length); i++) {
1203            try {
1204                synchronized (formats[i]) {
1205                    date = formats[i].parse(headerValue);
1206                }
1207            } catch (ParseException JavaDoc e) {
1208                // ignore the invalid format and try the next
1209
}
1210        }
1211        return date;
1212    }
1213
1214
1215    /**
1216     * Get the ETag value associated with a file.
1217     *
1218     * @param resourceInfo File object
1219     * @param strong True if we want a strong ETag, in which case a checksum
1220     * of the file has to be calculated
1221     */

1222    protected String JavaDoc getETagValue(ResourceInfo resourceInfo, boolean strong) {
1223        // FIXME : Compute a strong ETag if requested, using an MD5 digest
1224
// of the file contents
1225
if (resourceInfo.exists()) {
1226            return resourceInfo.etag;
1227        }
1228        else {
1229            return resourceInfo.length + "-" + resourceInfo.date;
1230        }
1231    }
1232    
1233    
1234    /**
1235     * Get the ETag associated with a file.
1236     *
1237     * @param resourceInfo File object
1238     * @param strong True if we want a strong ETag, in which case a checksum
1239     * of the file has to be calculated
1240     */

1241    protected String JavaDoc getETag(ResourceInfo resourceInfo, boolean strong) {
1242        if (strong)
1243            return "\"" + getETagValue(resourceInfo, strong) + "\"";
1244        else
1245            return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
1246    }
1247    
1248    protected class ResourceInfo {
1249        
1250        /**
1251         * Constructor.
1252         *
1253         * @param path Path name of the resource
1254         */

1255        public ResourceInfo(String JavaDoc path, NodeRevisionDescriptor properties) {
1256            
1257            this.path = path;
1258            this.exists = true;
1259            this.creationDate = properties.getCreationDateAsDate().getTime();
1260            this.date = properties.getLastModifiedAsDate().getTime();
1261            this.httpDate = properties.getLastModified();
1262            this.length = properties.getContentLength();
1263            this.etag = properties.getETag();
1264            
1265        }
1266        /**
1267         * Creates a ResourceInfo for a non existing resource.
1268         * @param path Path of the resource
1269         */

1270        public ResourceInfo(String JavaDoc path) {
1271            this.path = path;
1272            this.exists = false;
1273            this.length = 0;
1274            this.date = System.currentTimeMillis();
1275        }
1276        
1277        
1278        public String JavaDoc path;
1279        public long creationDate;
1280        public String JavaDoc httpDate;
1281        public long date;
1282        public long length;
1283        public String JavaDoc etag;
1284        //public boolean collection;
1285
public boolean exists;
1286        
1287        
1288        /**
1289         * Test if the associated resource exists.
1290         */

1291        public boolean exists() {
1292            return exists;
1293        }
1294        
1295        
1296        /**
1297         * String representation.
1298         */

1299        public String JavaDoc toString() {
1300            return path;
1301        }
1302        
1303        
1304    }
1305    
1306    protected class RequestHeaders {
1307        private static final int
1308            ST_UNDEFINED = 0,
1309            ST_INVALID = 1,
1310            ST_DEFINED = 2;
1311        
1312        // raw headers
1313
private String JavaDoc hIfStr;
1314        private String JavaDoc hLockTokenStr;
1315        private String JavaDoc hDepthStr;
1316        private String JavaDoc hDestinationStr;
1317        private String JavaDoc hOverwriteStr;
1318        private String JavaDoc hTimeoutStr;
1319        private String JavaDoc hLabelStr;
1320        private String JavaDoc hNotificationTypeStr;
1321        private String JavaDoc hCallbackStr;
1322        private String JavaDoc hSubscriptionIdStr;
1323        private String JavaDoc hNotificationDelayStr;
1324        private String JavaDoc hSubscriptionLifetimeStr;
1325        private String JavaDoc hTxIdStr;
1326        private String JavaDoc hTxMethodStr;
1327        private String JavaDoc hContentTypeStr;
1328
1329        // parsed headers
1330
private List JavaDoc hIf;
1331        private String JavaDoc hLockToken;
1332        private int hDepth;
1333        private String JavaDoc hDestination;
1334        private boolean hOverwrite;
1335        private int hTimeout;
1336        private String JavaDoc hLabel;
1337        private String JavaDoc hNotificationType;
1338        private String JavaDoc hCallback;
1339        private int []hSubscriptionId;
1340        private int hNotificationDelay;
1341        private int hSubscriptionLifetime;
1342        private String JavaDoc hTxId;
1343        private String JavaDoc hTxMethod;
1344        private String JavaDoc hContentType;
1345
1346        // states
1347
private int stIf = ST_UNDEFINED;
1348        private int stLockToken = ST_UNDEFINED;
1349        private int stDepth = ST_UNDEFINED;
1350        private int stDestination = ST_UNDEFINED;
1351        private int stOverwrite = ST_UNDEFINED;
1352        private int stTimeout = ST_UNDEFINED;
1353        private int stLabel = ST_UNDEFINED;
1354        private int stNotificationType = ST_UNDEFINED;
1355        private int stCallback = ST_UNDEFINED;
1356        private int stSubscriptionId = ST_UNDEFINED;
1357        private int stNotificationDelay = ST_UNDEFINED;
1358        private int stSubscriptionLifetime = ST_UNDEFINED;
1359        private int stTxId = ST_UNDEFINED;
1360        private int stTxMethod= ST_UNDEFINED;
1361        private int stContentType = ST_UNDEFINED;
1362
1363        protected RequestHeaders() {
1364        }
1365        
1366        protected boolean isDefined( String JavaDoc header ) {
1367            return req.getHeader(header) != null;
1368        }
1369        
1370        protected List JavaDoc getIf() throws WebdavException {
1371            if (stIf == ST_UNDEFINED) {
1372                return Collections.EMPTY_LIST;
1373            }
1374            else if (stIf == ST_INVALID) {
1375                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1376                sendError( sc, "Invalid header If: "+hIfStr );
1377                throw new WebdavException( sc );
1378            }
1379            else {
1380                return hIf;
1381            }
1382        }
1383        
1384        protected String JavaDoc getLockToken() throws WebdavException {
1385            if (stLockToken == ST_UNDEFINED) {
1386                return null;
1387            }
1388            else if (stLockToken == ST_INVALID) {
1389                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1390                sendError( sc, "Invalid header LockToken: "+hLockTokenStr );
1391                throw new WebdavException( sc );
1392            }
1393            else {
1394                return hLockToken;
1395            }
1396        }
1397        
1398        protected int getDepth( int defaultValue ) throws WebdavException {
1399            if (stDepth == ST_UNDEFINED) {
1400                return defaultValue;
1401            }
1402            else if (stDepth == ST_INVALID) {
1403                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1404                sendError( sc, "Invalid header Depth: "+hDepthStr );
1405                throw new WebdavException( sc );
1406            }
1407            else {
1408                return hDepth;
1409            }
1410        }
1411        
1412        protected String JavaDoc getDestination() throws WebdavException {
1413            if (stDestination == ST_UNDEFINED) {
1414                return null;
1415            }
1416            else if (stDestination == ST_INVALID) {
1417                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1418                sendError( sc, "Invalid header Destination: "+hDestinationStr );
1419                throw new WebdavException( sc );
1420            }
1421            else {
1422                return hDestination;
1423            }
1424        }
1425        
1426        protected boolean getOverwrite( boolean defaultValue ) throws WebdavException {
1427            if (stOverwrite == ST_UNDEFINED) {
1428                return defaultValue;
1429            }
1430            else if (stOverwrite == ST_INVALID) {
1431                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1432                sendError( sc, "Invalid header Overwrite: "+hOverwriteStr );
1433                throw new WebdavException( sc );
1434            }
1435            else {
1436                return hOverwrite;
1437            }
1438        }
1439        
1440        protected String JavaDoc getLabel() throws WebdavException {
1441            if (stLabel == ST_UNDEFINED) {
1442                return null;
1443            }
1444            else if (stLabel == ST_INVALID) {
1445                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1446                sendError( sc, "Invalid header Label: "+hLabelStr );
1447                throw new WebdavException( sc );
1448            }
1449            else {
1450                return hLabel;
1451            }
1452        }
1453        
1454        protected int getTimeout( int defaultValue) throws WebdavException {
1455            if (stTimeout == ST_UNDEFINED) {
1456                return defaultValue;
1457            }
1458            else if (stTimeout == ST_INVALID) {
1459                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1460                sendError( sc, "Invalid header Timeout: "+hTimeoutStr );
1461                throw new WebdavException( sc );
1462            }
1463            else {
1464                return hTimeout;
1465            }
1466        }
1467
1468        protected String JavaDoc getNotificationType() throws WebdavException {
1469            if (stNotificationType == ST_UNDEFINED) {
1470                return null;
1471            } else if (stNotificationType == ST_INVALID) {
1472                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1473                sendError( sc, "Invalid notification type: "+hNotificationTypeStr );
1474                throw new WebdavException( sc );
1475            }
1476            else {
1477                return hNotificationType;
1478            }
1479        }
1480
1481        protected int []getSubscriptionId() throws WebdavException {
1482            if (stSubscriptionId == ST_UNDEFINED) {
1483                return new int[0];
1484            } else if (stSubscriptionId == ST_INVALID) {
1485                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1486                sendError( sc, "Invalid subscription ID: "+hSubscriptionIdStr );
1487                throw new WebdavException( sc );
1488            }
1489            else {
1490                return hSubscriptionId;
1491            }
1492        }
1493
1494        protected String JavaDoc getCallback() throws WebdavException {
1495            if (stCallback == ST_UNDEFINED) {
1496                return null;
1497            } else if (stCallback == ST_INVALID) {
1498                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1499                sendError( sc, "Invalid callback: "+hCallbackStr );
1500                throw new WebdavException( sc );
1501            }
1502            else {
1503                return hCallback;
1504            }
1505        }
1506
1507        protected int getNotificationDelay( int defaultValue ) throws WebdavException {
1508            if (stNotificationDelay == ST_UNDEFINED) {
1509                return defaultValue;
1510            }
1511            else if (stNotificationDelay == ST_INVALID) {
1512                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1513                sendError( sc, "Invalid notification delay: "+hNotificationDelayStr );
1514                throw new WebdavException( sc );
1515            }
1516            else {
1517                return hNotificationDelay;
1518            }
1519        }
1520
1521        protected int getSubscriptionLifetime( int defaultValue ) throws WebdavException {
1522            if (stSubscriptionLifetime == ST_UNDEFINED) {
1523                return defaultValue;
1524            }
1525            else if (stSubscriptionLifetime == ST_INVALID) {
1526                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1527                sendError( sc, "Invalid subscription lifetime: "+hSubscriptionLifetimeStr );
1528                throw new WebdavException( sc );
1529            }
1530            else {
1531                return hSubscriptionLifetime;
1532            }
1533        }
1534
1535        protected String JavaDoc getTxId() throws WebdavException {
1536            if (stTxId == ST_UNDEFINED) {
1537                return null;
1538            } else if (stTxId == ST_INVALID) {
1539                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1540                sendError( sc, "Invalid transaction id: "+hTxIdStr );
1541                throw new WebdavException( sc );
1542            }
1543            else {
1544                return hTxId;
1545            }
1546        }
1547
1548        protected String JavaDoc getTxMethod() throws WebdavException {
1549            if (stTxMethod == ST_UNDEFINED) {
1550                return null;
1551            } else if (stTxMethod == ST_INVALID) {
1552                int sc = WebdavStatus.SC_PRECONDITION_FAILED;
1553                sendError( sc, "Invalid transaction method: "+hTxMethodStr );
1554                throw new WebdavException( sc );
1555            }
1556            else {
1557                return hTxMethod;
1558            }
1559        }
1560        
1561        protected String JavaDoc getContentType() {
1562           if (stContentType == ST_UNDEFINED) {
1563              return null;
1564           } else {
1565              return hContentType;
1566           }
1567        }
1568
1569        protected void parse() {
1570            // TransactionId header
1571
hTxIdStr = req.getHeader(H_TRANSACTION);
1572            if (hTxIdStr != null) {
1573                stTxId = ST_DEFINED;
1574                try {
1575                    hTxId = hTxIdStr;
1576                } catch (Exception JavaDoc e) {
1577                    stTxId = ST_INVALID;
1578                }
1579            }
1580
1581            // TransactionMethod header
1582
hTxMethodStr = req.getHeader(H_TRANSACTION_METHOD);
1583            if (hTxMethodStr != null) {
1584                stTxMethod = ST_DEFINED;
1585                try {
1586                    hTxMethod = hTxMethodStr;
1587                } catch (Exception JavaDoc e) {
1588                    stTxMethod = ST_INVALID;
1589                }
1590            }
1591
1592            // NotificationType header
1593
hNotificationTypeStr = req.getHeader(H_NOTIFICATION_TYPE);
1594            if (hNotificationTypeStr != null) {
1595                stNotificationType = ST_DEFINED;
1596                try {
1597                    hNotificationType = hNotificationTypeStr;
1598                } catch (Exception JavaDoc e) {
1599                    stNotificationType = ST_INVALID;
1600                }
1601            }
1602
1603            // NotificationDelay header
1604
hNotificationDelayStr = req.getHeader(H_NOTIFICATION_DELAY);
1605            if (hNotificationDelayStr != null) {
1606                stNotificationDelay = ST_DEFINED;
1607                try {
1608                    hNotificationDelay = Integer.parseInt(hNotificationDelayStr);
1609                } catch (Exception JavaDoc e) {
1610                    stNotificationDelay = ST_INVALID;
1611                }
1612            }
1613
1614            // SubscriptionLifetime header
1615
hSubscriptionLifetimeStr = req.getHeader(H_SUBSCRIPTION_LIFETIME);
1616            if (hSubscriptionLifetimeStr != null) {
1617                stSubscriptionLifetime = ST_DEFINED;
1618                try {
1619                    hSubscriptionLifetime = Integer.parseInt(hSubscriptionLifetimeStr);
1620                } catch (Exception JavaDoc e) {
1621                    stSubscriptionLifetime = ST_INVALID;
1622                }
1623            }
1624
1625            // SubscriptionID header
1626
hSubscriptionIdStr = req.getHeader(H_SUBSCRIPTION_ID);
1627            if (hSubscriptionIdStr != null) {
1628                stSubscriptionId = ST_DEFINED;
1629                try {
1630                    StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(hSubscriptionIdStr, ",");
1631                    hSubscriptionId = new int[tokenizer.countTokens()];
1632                    int i = 0;
1633                    while ( tokenizer.hasMoreTokens() ) {
1634                        hSubscriptionId[i] = Integer.parseInt(tokenizer.nextToken().trim());
1635                        i++;
1636                    }
1637                } catch (Exception JavaDoc e) {
1638                    stSubscriptionId = ST_INVALID;
1639                }
1640            }
1641
1642            // Call back header
1643
hCallbackStr = req.getHeader(H_CALL_BACK);
1644            if (hCallbackStr != null) {
1645                stCallback = ST_DEFINED;
1646                try {
1647                    hCallback = hCallbackStr;
1648                } catch (Exception JavaDoc e) {
1649                    stCallback = ST_INVALID;
1650                }
1651            }
1652
1653            // If header
1654
hIfStr = req.getHeader(H_IF);
1655            if (hIfStr != null) {
1656                stIf = ST_DEFINED;
1657                try {
1658                    hIf = extractLockTokens(hIfStr);
1659                }
1660                catch (Exception JavaDoc e) {
1661                    stIf = ST_INVALID;
1662                }
1663            }
1664            
1665            // Lock-Token header
1666
hLockTokenStr = req.getHeader(H_LOCK_TOKEN);
1667            if (hLockTokenStr != null) {
1668                stLockToken = ST_DEFINED;
1669                try {
1670                    List JavaDoc tl = extractLockTokens(hLockTokenStr);
1671                    hLockToken = (String JavaDoc)tl.get(0);
1672                }
1673                catch (Exception JavaDoc e) {
1674                    stLockToken = ST_INVALID;
1675                }
1676            }
1677            
1678            // Depth header
1679
hDepthStr = req.getHeader(H_DEPTH);
1680            if (hDepthStr != null) {
1681                stDepth = ST_DEFINED;
1682                if ("0".equals(hDepthStr)) {
1683                    hDepth = 0;
1684                }
1685                else if ("1".equals(hDepthStr)) {
1686                    hDepth = 1;
1687                }
1688                else if ("infinity".equalsIgnoreCase(hDepthStr)) {
1689                    hDepth = INFINITY;
1690                }
1691                else {
1692                    stDepth = ST_INVALID;
1693                    hDepth = Integer.parseInt(hDepthStr);
1694                }
1695            }
1696            
1697            // Destination header
1698
hDestinationStr = req.getHeader(H_DESTINATION);
1699            if (hDestinationStr != null) {
1700                stDestination = ST_DEFINED;
1701                hDestination = hDestinationStr;
1702            }
1703            
1704            // Overwrite header
1705
String JavaDoc hOverwriteStr = req.getHeader(H_OVERWRITE);
1706            if (hOverwriteStr != null) {
1707                stOverwrite = ST_DEFINED;
1708                if ("T".equalsIgnoreCase(hOverwriteStr)) {
1709                    hOverwrite = true;
1710                }
1711                else if ("F".equalsIgnoreCase(hOverwriteStr)) {
1712                    hOverwrite = false;
1713                }
1714                else {
1715                    stOverwrite = ST_INVALID;
1716                }
1717            }
1718            
1719            // Timeout header
1720
hTimeoutStr = req.getHeader(H_TIMEOUT);
1721            if (hTimeoutStr != null) {
1722                stTimeout = ST_DEFINED;
1723                try {
1724                    hTimeout = extractLockDuration( hTimeoutStr );
1725                }
1726                catch (Exception JavaDoc e) {
1727                    stTimeout = ST_INVALID;
1728                }
1729            }
1730            
1731            // Label header
1732
hLabelStr = req.getHeader(H_LABEL);
1733            if (hLabelStr != null) {
1734                stLabel = ST_DEFINED;
1735                hLabel = hLabelStr;
1736            }
1737            
1738            // Content-Type header
1739
hContentTypeStr = req.getHeader(H_CONTENT_TYPE);
1740            if (hContentTypeStr != null) {
1741               stContentType = ST_DEFINED;
1742               hContentType = hContentTypeStr;
1743            }
1744            
1745        }
1746        
1747        private List JavaDoc extractLockTokens(String JavaDoc hStr) {
1748            List JavaDoc result = new ArrayList JavaDoc();
1749            int pos = hStr.indexOf(S_LOCK_TOKEN);
1750            int endPos = -1;
1751            int offset = S_LOCK_TOKEN.length();
1752            String JavaDoc lockToken = null;
1753            
1754            while (pos != -1) {
1755                
1756                endPos = hStr.indexOf('>', pos + offset);
1757                if (endPos == -1) {
1758                    lockToken = hStr;
1759                    endPos = hStr.length();
1760                } else {
1761                    lockToken = hStr.substring(pos + offset, endPos);
1762                }
1763                
1764                //System.out.println("Lock Token found :-" + lockToken + "-");
1765
slideToken.addLockToken(lockToken);
1766                result.add( lockToken );
1767                pos = hStr.indexOf(S_LOCK_TOKEN, endPos);
1768            }
1769            return result;
1770        }
1771        
1772        private int extractLockDuration(String JavaDoc hStr) {
1773            int result;
1774            int firstCommaPos = hStr.indexOf(',');
1775            if (firstCommaPos != -1) {
1776                hStr = hStr.substring(0, firstCommaPos);
1777            }
1778            if (hStr.startsWith("Second-")) {
1779                result = Integer.parseInt(hStr.substring("Second-".length()));
1780            } else {
1781                if (hStr.equalsIgnoreCase("Infinite")) {
1782                    result = INFINITY;
1783                } else {
1784                    result = Integer.parseInt(hStr);
1785                }
1786            }
1787            return result;
1788        }
1789    }
1790}
Popular Tags