KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LockMethod.java,v 1.69.2.4 2004/09/20 08:46:02 ozeigermann Exp $
3  * $Revision: 1.69.2.4 $
4  * $Date: 2004/09/20 08:46:02 $
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.StringWriter JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.util.Date JavaDoc;
30 import java.util.Enumeration JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33
34 import javax.transaction.Transaction JavaDoc;
35
36 import org.apache.slide.common.NamespaceAccessToken;
37 import org.apache.slide.common.NamespaceConfig;
38 import org.apache.slide.common.ServiceAccessException;
39 import org.apache.slide.common.SlideException;
40 import org.apache.slide.content.NodeRevisionContent;
41 import org.apache.slide.content.NodeRevisionDescriptor;
42 import org.apache.slide.content.NodeRevisionDescriptors;
43 import org.apache.slide.content.RevisionAlreadyExistException;
44 import org.apache.slide.content.RevisionDescriptorNotFoundException;
45 import org.apache.slide.event.VetoException;
46 import org.apache.slide.lock.NodeLock;
47 import org.apache.slide.lock.ObjectIsAlreadyLockedException;
48 import org.apache.slide.lock.ObjectLockedException;
49 import org.apache.slide.security.AccessDeniedException;
50 import org.apache.slide.structure.LinkedObjectNotFoundException;
51 import org.apache.slide.structure.ObjectAlreadyExistsException;
52 import org.apache.slide.structure.ObjectNotFoundException;
53 import org.apache.slide.structure.SubjectNode;
54 import org.apache.slide.transaction.ExternalTransactionContext;
55 import org.apache.slide.util.XMLValue;
56 import org.apache.slide.webdav.WebdavException;
57 import org.apache.slide.webdav.WebdavServletConfig;
58 import org.apache.slide.webdav.util.PropertyHelper;
59 import org.apache.slide.webdav.util.WebdavConstants;
60 import org.apache.slide.webdav.util.WebdavStatus;
61 import org.jdom.Element;
62 import org.jdom.JDOMException;
63 import org.jdom.output.XMLOutputter;
64
65 /**
66  * LOCK method.
67  *
68  */

69 public class LockMethod extends AbstractMultistatusResponseMethod implements
70         WebdavConstants, WriteMethod {
71
72     // -------------------------------------------------------------- Constants
73

74     /**
75      * Create a new lock.
76      */

77     private static final int LOCK_CREATION = 0;
78
79     /**
80      * Refresh lock.
81      */

82     private static final int LOCK_REFRESH = 1;
83
84     /**
85      * Maximum and default timeout.
86      */

87     private static final int MAX_TIMEOUT = Integer.MAX_VALUE;
88
89     private static final int DEFAULT_TIMEOUT = MAX_TIMEOUT;
90
91     /**
92      * The default owner if not explicitely specified by the request.
93      */

94     public static final String JavaDoc DEFAULT_LOCK_OWNER = "";
95
96     // ----------------------------------------------------- Instance Variables
97

98     /**
99      * Depth.
100      */

101     private int depth;
102
103     /**
104      * Type of the LOCK method ({@link #LOCK_CREATION}or {@link #LOCK_REFRESH}).
105      */

106     private int lockType;
107
108     /**
109      * Lock duration.
110      */

111     private int lockDuration = DEFAULT_TIMEOUT;
112
113     /**
114      * Lock scope.
115      */

116     private String JavaDoc lockInfo_lockScope;
117
118     /*
119      * Lock type.
120      */

121     private String JavaDoc lockInfo_lockType;
122
123     /**
124      * Lock owner.
125      */

126     private String JavaDoc lockInfo_lockOwner;
127
128     /**
129      * Lock subject.
130      */

131     private String JavaDoc lockInfo_lockSubject;
132
133     /**
134      * The PropertyHelper used by this instance.
135      */

136     protected PropertyHelper propertyHelper = null;
137
138     // ----------------------------------------------------------- Constructors
139

140     /**
141      * Constructor.
142      *
143      * @param token
144      * the token for accessing the namespace
145      * @param config
146      * configuration of the WebDAV servlet
147      */

148     public LockMethod(NamespaceAccessToken token, WebdavServletConfig config) {
149         super(token, config);
150     }
151
152     // ------------------------------------------------------ Protected Methods
153

154     /**
155      * Parse request.
156      *
157      * @exception WebdavException
158      * Does not happen
159      */

160     protected void parseRequest() throws WebdavException {
161
162         propertyHelper = PropertyHelper.getPropertyHelper(slideToken, token,
163                 getConfig());
164         // readRequestContent();
165

166         // Loads the associated object from the store.
167
lockInfo_lockSubject = requestUri;
168         if (lockInfo_lockSubject == null) {
169             lockInfo_lockSubject = "/";
170         }
171
172         depth = requestHeaders.getDepth(INFINITY);
173         if (depth != 0 && depth != INFINITY) {
174             int sc = WebdavStatus.SC_PRECONDITION_FAILED;
175             sendError(sc, "Invalid header Depth: " + depth);
176             throw new WebdavException(sc);
177         }
178
179         lockDuration = requestHeaders.getTimeout(MAX_TIMEOUT);
180
181         if (req.getContentLength() > 0 || isRequestChunked()) {
182             parseLockInfo();
183         } else {
184             lockType = LOCK_REFRESH;
185         }
186
187     }
188
189     /**
190      * Parses the <code>&lt;lockinfo&gt;</code> request content document.
191      *
192      * @throws WebdavException
193      * if parsing the request failed or if the request is not valid.
194      */

195     private void parseLockInfo() throws WebdavException {
196
197         lockType = LOCK_CREATION;
198
199         try {
200             Iterator JavaDoc childrenIterator = parseRequestContent(E_LOCKINFO)
201                     .getChildren().iterator();
202             while (childrenIterator.hasNext()) {
203                 Element currentElement = (Element) childrenIterator.next();
204                 if (E_LOCKSCOPE.equals(currentElement.getName())) {
205                     parseLockScope(currentElement);
206                 } else if (E_LOCKTYPE.equals(currentElement.getName())) {
207                     parseLockType(currentElement);
208                 } else if (E_OWNER.equals(currentElement.getName())) {
209                     parseOwner(currentElement);
210                 }
211             }
212         } catch (JDOMException e) {
213             int statusCode = WebdavStatus.SC_BAD_REQUEST;
214             sendError(statusCode, e);
215             throw new WebdavException(statusCode);
216         } catch (IOException JavaDoc e) {
217             int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
218             sendError(statusCode, e);
219             throw new WebdavException(statusCode);
220         }
221     }
222
223     /**
224      * Parses the <code>&lt;lockscope&gt;</code> part of the request content
225      * document.
226      *
227      * @param lockScopeElement
228      * the <code>&lt;lockscope&gt;</code> to parse.
229      *
230      * @throws JDOMException
231      * if parsing the request failed or if the request is not valid.
232      */

233     private void parseLockScope(Element lockScopeElement) throws JDOMException {
234         if (lockScopeElement == null) {
235             throw new JDOMException("Expected <" + E_LOCKSCOPE + "> element");
236         }
237
238         List JavaDoc children = lockScopeElement.getChildren();
239         if (children.size() != 1) {
240             throw new JDOMException("<" + E_LOCKSCOPE
241                     + "> must have exactly one child element");
242         }
243
244         lockInfo_lockScope = ((Element) children.get(0)).getName();
245         if (!(E_EXCLUSIVE.equals(lockInfo_lockScope)
246                 || E_SHARED.equals(lockInfo_lockScope) || E_LOCAL
247                 .equals(lockInfo_lockScope))) {
248             throw new JDOMException("<" + E_LOCKSCOPE
249                     + "> can only contain one of <" + E_EXCLUSIVE + "> or <"
250                     + E_SHARED + "> or <" + E_LOCAL + ">");
251         }
252     }
253
254     /**
255      * Parses the <code>&lt;locktype&gt;</code> part of the request content
256      * document.
257      *
258      * @param lockTypeElement
259      * the <code>&lt;locktype&gt;</code> to parse.
260      *
261      * @throws JDOMException
262      * if parsing the request failed or if the request is not valid.
263      */

264     private void parseLockType(Element lockTypeElement) throws JDOMException {
265
266         if (lockTypeElement == null) {
267             throw new JDOMException("Expected <" + E_LOCKTYPE + "> element");
268         }
269
270         List JavaDoc children = lockTypeElement.getChildren();
271         if (children.size() != 1) {
272             throw new JDOMException("<" + E_LOCKTYPE
273                     + "> must have exactly one child element");
274         }
275         String JavaDoc lockTypeName = ((Element) children.get(0)).getName();
276         if (!E_WRITE.equals(lockTypeName)
277                 && !E_TRANSACTION.equals(lockTypeName)) {
278             throw new JDOMException(
279                     "Only write and transaction locks are supported");
280         }
281         lockInfo_lockType = ((Element) children.get(0)).getName();
282     }
283
284     /**
285      * Parses the <code>&lt;owner&gt;</code> part of the request content
286      * document.
287      *
288      * @param ownerElement
289      * the <code>&lt;owner&gt;</code> to parse.
290      *
291      * @throws JDOMException
292      * if parsing the request failed or if the request is not valid.
293      */

294     private void parseOwner(Element ownerElement) throws JDOMException {
295
296         if (ownerElement == null) {
297             lockInfo_lockOwner = DEFAULT_LOCK_OWNER;
298             return;
299             // throw new JDOMException("Expected <"+E_OWNER+"> element");
300
}
301
302         StringWriter JavaDoc stringWriter = new StringWriter JavaDoc();
303         XMLOutputter xmlOutputter = new XMLOutputter();
304         try {
305             xmlOutputter.outputElementContent(ownerElement, stringWriter);
306         } catch (IOException JavaDoc e) {
307             // this should not happen since we do no "real" I/O but
308
// only print to a PrintWriter
309
e.printStackTrace();
310         }
311         lockInfo_lockOwner = stringWriter.toString();
312
313         if (lockInfo_lockOwner.length() == 0) {
314             lockInfo_lockOwner = DEFAULT_LOCK_OWNER;
315             //throw new JDOMException("<"+E_OWNER+"> element must not be
316
// empty");
317
}
318     }
319
320     /**
321      * Execute request.
322      *
323      * @exception WebdavException
324      * Unrecoverable error while renewing lock
325      */

326     protected void executeRequest() throws WebdavException {
327
328         // Prevent dirty reads
329
slideToken.setForceStoreEnlistment(true);
330
331         SubjectNode toLockSubject = null;
332         boolean isCollection = isCollection(lockInfo_lockSubject);
333         boolean inheritance = false;
334         Date JavaDoc lockDate = null;
335
336         
337         switch (lockType) {
338
339         case LOCK_CREATION:
340             if (lockInfo_lockType.equals(E_TRANSACTION)) {
341                 try {
342                     NamespaceConfig namespaceConfig = token
343                     .getNamespaceConfig();
344                     toLockSubject = getToLockSubject();
345                     if (lockDate == null)
346                         lockDate = new Date JavaDoc((new Date JavaDoc()).getTime()
347                                 + ((long) lockDuration * 1000L));
348                     NodeLock lockToken = new NodeLock(toLockSubject.getUri(),((SubjectNode)security.getPrincipal(slideToken)).getUri(),
349                             namespaceConfig.getCreateObjectAction().getUri(), lockDate,
350                             inheritance, NodeLock.LOCAL, lockInfo_lockOwner);
351                     token.setTransactionTimeout(lockDuration * 1000);
352                     Transaction JavaDoc transaction = token.getTransactionManager().suspend();
353                     //String txId = lockToken.getLockId();
354
String JavaDoc fullTxId = "<" + S_LOCK_TOKEN + lockToken.getLockId() + ">";
355                     ExternalTransactionContext.registerContext(fullTxId, transaction);
356                     slideToken.setExternalTx();
357                     resp.setHeader("Lock-Token", fullTxId);
358                     showLockDiscoveryInfo(lockToken);
359                 } catch (Exception JavaDoc e) {
360                     int statusCode = getErrorCode(e);
361                     sendError(statusCode, e);
362                     throw new WebdavException(statusCode);
363                 }
364             } else if (lockInfo_lockType.equals(E_WRITE)) {
365                 try {
366                     
367                 if (!checkIfHeaders()) {
368                     return;
369                 }
370                       
371                     NamespaceConfig namespaceConfig = token
372                             .getNamespaceConfig();
373                     toLockSubject = getToLockSubject();
374                     NodeLock lockToken = null;
375
376                     inheritance = (depth != 0);
377                     boolean exclusive = !(lockInfo_lockScope.equals(E_SHARED));
378
379                     if (lockDate == null)
380                         lockDate = new Date JavaDoc((new Date JavaDoc()).getTime()
381                                 + ((long) lockDuration * 1000L));
382
383                     lockToken = new NodeLock(toLockSubject,
384                             (SubjectNode) security.getPrincipal(slideToken),
385                             namespaceConfig.getCreateObjectAction(), lockDate,
386                             inheritance, exclusive, lockInfo_lockOwner);
387                     lock.lock(slideToken, lockToken);
388
389                     // Set the lock-token header
390
// [RFC 2518, 9.5] " The Lock-Token response header is used
391
// with the LOCK method to indicate the lock token created
392
// as
393
// a result of a successful LOCK request to create a new
394
// lock."
395
resp.setHeader("Lock-Token", "<" + S_LOCK_TOKEN
396                             + lockToken.getLockId() + ">");
397
398                     resp.setStatus(WebdavStatus.SC_OK);
399
400                     // The lock token on which the DAV module will have the info
401

402                     showLockDiscoveryInfo(lockToken);
403                 } catch (ObjectIsAlreadyLockedException e) {
404                     if (inheritance
405                             && generateMultiStatusResponse(isCollection, e,
406                                     requestUri)) {
407                         // error is on the resource which we attempted to lock
408
String JavaDoc errorMessage = generateErrorMessage(e);
409                         // Write it on the servlet writer
410
resp.setContentType(TEXT_XML_UTF_8);
411                         resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
412                         try {
413                             resp.getWriter().write(errorMessage);
414                         } catch (IOException JavaDoc ex) {
415                             // Critical error ... Servlet container is dead or
416
// something
417
int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
418                             sendError(statusCode, e);
419                             throw new WebdavException(statusCode);
420                         }
421                     } else {
422                         // Returning 207 on non-collection requests is generally
423
// considered bad. So let's not do it, since this way
424
// makes clients generally behave better.
425
resp.setStatus(WebdavStatus.SC_LOCKED);
426                     }
427                     //
428
// make sure the transaction is aborted
429
// throw any WebDAV exception to indicate the transaction
430
// wants to be aborted
431
//
432
throw new WebdavException(WebdavStatus.SC_ACCEPTED, false);
433                 } catch (Exception JavaDoc e) {
434                     int statusCode = getErrorCode(e);
435                     sendError(statusCode, e);
436                     throw new WebdavException(statusCode);
437                 }
438             }
439             break;
440
441         case LOCK_REFRESH:
442
443             try {
444
445                 Enumeration JavaDoc lockTokens = lock.enumerateLocks(slideToken,
446                         lockInfo_lockSubject, false);
447
448                 NodeLock currentLockToken = null;
449                 Date JavaDoc newExpirationDate = new Date JavaDoc((new Date JavaDoc()).getTime()
450                         + ((long) lockDuration * 1000L));
451                 while (lockTokens.hasMoreElements()) {
452                     currentLockToken = (NodeLock) lockTokens.nextElement();
453                     lock.renew(slideToken, currentLockToken, newExpirationDate);
454                 }
455
456                 showLockDiscoveryInfo(currentLockToken);
457
458             } catch (SlideException e) {
459                 int statusCode = WebdavStatus.SC_PRECONDITION_FAILED;
460                 sendError(statusCode, e);
461                 throw new WebdavException(statusCode);
462             }
463
464             break;
465
466         }
467
468     }
469
470     protected SubjectNode getToLockSubject() throws ObjectAlreadyExistsException, ObjectNotFoundException,
471             AccessDeniedException, RevisionAlreadyExistException, LinkedObjectNotFoundException, ObjectLockedException,
472             ServiceAccessException, VetoException {
473         
474         SubjectNode toLockSubject;
475         try {
476             toLockSubject = (SubjectNode) structure.retrieve(slideToken, lockInfo_lockSubject);
477         } catch (ObjectNotFoundException ex) {
478
479             // Creating a lock null resource
480
toLockSubject = new SubjectNode();
481
482             // Creating new subject
483
structure.create(slideToken, toLockSubject, lockInfo_lockSubject);
484
485             NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(0);
486
487             // Resource type
488
XMLValue lockNull = new XMLValue(new Element(E_LOCKNULL, DNSP));
489             revisionDescriptor.setResourceType(lockNull.toString());
490
491             NodeRevisionContent nrc = new NodeRevisionContent();
492             nrc.setContent(new byte[0]);
493
494             // Creating the revision descriptor
495
content.create(slideToken, lockInfo_lockSubject, revisionDescriptor, nrc);
496         }
497         return toLockSubject;
498     }
499     
500     /**
501      * Get return status based on exception type.
502      */

503     protected int getErrorCode(Exception JavaDoc ex) {
504         try {
505             throw ex;
506         } catch (ObjectNotFoundException e) {
507             return WebdavStatus.SC_PRECONDITION_FAILED;
508         } catch (Exception JavaDoc e) {
509             return super.getErrorCode(e);
510         }
511     }
512
513     /**
514      * Show lockdiscovery info.
515      *
516      * @exception WebdavException
517      * Something is wrong with the servlet container
518      */

519     protected void showLockDiscoveryInfo(NodeLock token) throws WebdavException {
520
521         // Generating XML response
522
org.jdom.Element prop = new org.jdom.Element(E_PROP, DNSP);
523         org.jdom.Element lockdiscovery = new org.jdom.Element(E_LOCKDISCOVERY,
524                 DNSP);
525         prop.addContent(lockdiscovery);
526         XMLValue xmlValue = propertyHelper.computeLockDiscovery(token,
527                 getSlideContextPath());
528         Iterator JavaDoc iterator = xmlValue.iterator();
529         while (iterator.hasNext()) {
530             lockdiscovery.addContent((org.jdom.Element) iterator.next());
531         }
532
533         try {
534             //System.out.println("Query result");
535
//System.out.println(generatedXML.toString());
536
resp.setContentType(TEXT_XML_UTF_8);
537             Writer JavaDoc writer = resp.getWriter();
538             org.jdom.output.Format format = org.jdom.output.Format
539                     .getPrettyFormat();
540             format.setIndent(XML_RESPONSE_INDENT);
541             new org.jdom.output.XMLOutputter(format).output(
542                     new org.jdom.Document(prop), writer);
543             writer.flush();
544         } catch (Exception JavaDoc e) {
545             int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
546             sendError(statusCode, e);
547             throw new WebdavException(statusCode);
548         }
549
550     }
551     
552    private boolean checkIfHeaders() throws AccessDeniedException, LinkedObjectNotFoundException, ServiceAccessException, ObjectLockedException, VetoException, IOException JavaDoc
553    {
554        try {
555            NodeRevisionDescriptors revisionDescriptors =
556                       content.retrieve(slideToken, this.requestUri);
557            // Retrieve latest revision descriptor
558
NodeRevisionDescriptor revisionDescriptor =
559                       content.retrieve(slideToken, revisionDescriptors);
560            if (revisionDescriptor != null) {
561                ResourceInfo resourceInfo =
562                      new ResourceInfo(this.requestUri, revisionDescriptor);
563                return checkIfHeaders(req, resp, resourceInfo);
564            } else {
565                return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
566            }
567        }
568        catch (RevisionDescriptorNotFoundException e) {
569            return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
570        }
571        catch (ObjectNotFoundException e) {
572            return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri));
573        }
574    }
575 }
576
577
Popular Tags