KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LabelMethod.java,v 1.28 2004/08/02 16:36:02 unico Exp $
3  * $Revision: 1.28 $
4  * $Date: 2004/08/02 16:36: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.util.Enumeration JavaDoc;
28 import java.util.Iterator JavaDoc;
29
30 import org.apache.slide.common.NamespaceAccessToken;
31 import org.apache.slide.common.NestedSlideException;
32 import org.apache.slide.common.ServiceAccessException;
33 import org.apache.slide.common.SlideException;
34 import org.apache.slide.content.NodeProperty;
35 import org.apache.slide.content.NodeRevisionDescriptor;
36 import org.apache.slide.content.NodeRevisionDescriptors;
37 import org.apache.slide.event.EventDispatcher;
38 import org.apache.slide.structure.ObjectNode;
39 import org.apache.slide.util.XMLValue;
40 import org.apache.slide.webdav.WebdavException;
41 import org.apache.slide.webdav.WebdavServletConfig;
42 import org.apache.slide.webdav.event.WebdavEvent;
43 import org.apache.slide.webdav.util.DeltavConstants;
44 import org.apache.slide.webdav.util.LabeledRevisionNotFoundException;
45 import org.apache.slide.webdav.util.PreconditionViolationException;
46 import org.apache.slide.webdav.util.PropertyHelper;
47 import org.apache.slide.webdav.util.VersioningHelper;
48 import org.apache.slide.webdav.util.ViolatedPrecondition;
49 import org.apache.slide.webdav.util.WebdavStatus;
50 import org.apache.slide.webdav.util.WebdavUtils;
51 import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
52 import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
53 import org.apache.slide.webdav.util.resourcekind.ResourceKind;
54 import org.apache.slide.webdav.util.resourcekind.Version;
55 import org.apache.slide.webdav.util.resourcekind.VersionControlled;
56 import org.jdom.Element;
57 import org.jdom.JDOMException;
58
59 /**
60  * LABEL method.
61  *
62  * @version $Revision: 1.28 $
63  *
64  */

65 public class LabelMethod extends AbstractMultistatusResponseMethod implements DeltavConstants, WriteMethod {
66     /**
67      ** String constant for <code>Label missing</code>.
68      **/

69     public static final String JavaDoc LABEL_MISSING = "Label missing";
70     
71     /**
72      * String constant for <code>Request content &lt;label&gt; element must
73      * contain either &lt;add&gt;, &lt;set&gt; or &lt;remove&gt;</code>.
74      */

75     public static final String JavaDoc LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE =
76         "Request content <label> element must contain either <" +
77         E_ADD + ">, <" + E_SET + "> or <" + E_REMOVE + ">";
78     
79     
80     
81     
82     /**
83      * Resource to be written.
84      */

85     private String JavaDoc resourcePath;
86     
87     /**
88      * Indicates if the resource to delete is a collection.
89      */

90     protected boolean isCollection = false;
91     
92     /**
93      * The VersioningHelper used by this instance.
94      */

95     protected VersioningHelper versioningHelper = null;
96     
97     /**
98      * Indicates which label operation to perform:
99      * <code>add</code>, <code>set</code> or <code>remove</code>.
100      */

101     protected String JavaDoc operation = null;
102     
103     /**
104      * The label to add/set/remove.
105      */

106     protected String JavaDoc label = null;
107     
108     /**
109      * The value of the <code>Label</code> header
110      */

111     protected String JavaDoc labelHeader = null;
112     
113     
114     // ----------------------------------------------------------- Constructors
115

116     
117     /**
118      * Constructor.
119      *
120      * @param token the token for accessing the namespace
121      * @param config configuration of the WebDAV servlet
122      */

123     public LabelMethod(NamespaceAccessToken token,
124                        WebdavServletConfig config) {
125         super(token, config);
126     }
127     
128     /**
129      * Parse WebDAV XML query.
130      *
131      * @throws WebdavException
132      */

133     protected void parseRequest() throws WebdavException {
134         // readRequestContent();
135
versioningHelper = VersioningHelper.getVersioningHelper(slideToken,
136                                                                 token,
137                                                                 req,
138                                                                 resp,
139                                                                 config);
140         resourcePath = requestUri;
141         if (resourcePath == null) {
142             resourcePath = "/";
143         }
144         
145         labelHeader = WebdavUtils.fixTomcatHeader(requestHeaders.getLabel(), "UTF-8");
146         
147         try{
148             Element root = parseRequestContent(DeltavConstants.E_LABEL);
149             Element current = root.getChild(DeltavConstants.E_ADD, DNSP);
150             Element operationElement = null;
151             if (current != null) {
152                 operationElement = current;
153             }
154             current = root.getChild(DeltavConstants.E_SET, DNSP);
155             if ( current != null) {
156                 if (operationElement != null) {
157                     throw new JDOMException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
158                 }
159                 operationElement = current;
160             }
161             current = root.getChild(DeltavConstants.E_REMOVE, DNSP);
162             if ( current != null) {
163                 if (operationElement != null) {
164                     throw new JDOMException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
165                 }
166                 operationElement = current;
167             }
168             if (operationElement == null) {
169                 throw new JDOMException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
170             }
171             operation = operationElement.getName();
172             
173             Element labelName = operationElement.getChild(DeltavConstants.E_LABEL_NAME, DNSP);
174             if ( (labelName == null) ||
175                     (labelName.getText() == null) ||
176                     (labelName.getText().length() == 0) ) {
177                 throw new JDOMException(LABEL_MISSING);
178             }
179             label = labelName.getText();
180         }
181         catch (IOException JavaDoc e){
182             int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
183             sendError( statusCode, e );
184             throw new WebdavException( statusCode );
185         }
186         catch (JDOMException e){
187             int statusCode = WebdavStatus.SC_BAD_REQUEST;
188             sendError( statusCode, e );
189             throw new WebdavException( statusCode );
190         }
191     }
192     
193     /**
194      * Execute the request.
195      *
196      * @throws WebdavException
197      * @throws IOException
198      */

199     protected void executeRequest() throws WebdavException, IOException JavaDoc {
200         
201         // Prevent dirty reads
202
slideToken.setForceStoreEnlistment(true);
203         
204         // check lock-null resources
205
try {
206             if (isLockNull(resourcePath)) {
207                 int statusCode = WebdavStatus.SC_NOT_FOUND;
208                 sendError( statusCode, "lock-null resource", new Object JavaDoc[]{resourcePath} );
209                 throw new WebdavException( statusCode );
210             }
211         }
212         catch (ServiceAccessException e) {
213             int statusCode = getErrorCode((Exception JavaDoc)e);
214             sendError( statusCode, e );
215             throw new WebdavException( statusCode );
216         }
217         
218         isCollection = isCollection(resourcePath);
219         try {
220             if ( WebdavEvent.LABEL.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.LABEL, new WebdavEvent(this));
221
222             labelResource(resourcePath);
223         } catch (NestedSlideException nestedSlideException) {
224             // If it's not a collection, we don't want to give a 207,
225
// because it's silly, and it confuses many clients (such as
226
// MS Web Folders).
227
if (generateMultiStatusResponse(isCollection, nestedSlideException, requestUri)) {
228                 String JavaDoc errorMessage = generateErrorMessage(nestedSlideException);
229                 // Write it on the servlet writer
230
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
231                 try {
232                     resp.setContentType(TEXT_XML_UTF_8);
233                     resp.getWriter().write(errorMessage);
234                 } catch(IOException JavaDoc ex) {
235                     // Critical error ... Servlet container is dead or something
236
int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
237                     sendError( statusCode, ex );
238                     throw new WebdavException( statusCode );
239                 }
240             } else {
241                 // Returning 207 on non-collection requests is generally
242
// considered bad. So let's not do it, since this way
243
// makes clients generally behave better.
244
SlideException exception = (SlideException)nestedSlideException.enumerateExceptions().nextElement();
245                 if (exception instanceof PreconditionViolationException) {
246                     try {
247                         sendPreconditionViolation((PreconditionViolationException)exception);
248                     } catch(IOException JavaDoc ex) {
249                         // Critical error ... Servlet container is dead or something
250
int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
251                         sendError( statusCode, ex );
252                         throw new WebdavException( statusCode );
253                     }
254                 }
255                 else {
256                     int statusCode = getErrorCode( exception );
257                     sendError( statusCode, exception );
258                     throw new WebdavException( statusCode );
259                 }
260             }
261             //
262
// make sure the transaction is aborted
263
// throw any WebDAV exception to indicate the transaction wants to be aborted
264
//
265
throw new WebdavException(WebdavStatus.SC_ACCEPTED, false);
266         } catch( SlideException x ) {
267             int statusCode = getErrorCode((SlideException)x);
268             sendError( statusCode, x );
269             throw new WebdavException( statusCode );
270         }
271         finally {
272             resp.setHeader(H_CACHE_CONTROL, NO_CACHE);
273         }
274     }
275     
276     /**
277      * Labels the reource identified by the given <code>resourcePath</code>.
278      * If the resource is a collection and a <code>Depth</code> header is specified
279      * than the request is applied recursivly. If an attempt to label a resource
280      * fails, the corresponding Exception is contained in the thrown
281      * NestedSlideException.
282      *
283      * @param resourcePath the path of the resource to label.
284      *
285      * @throws NestedSlideException, if an attempt to label a resource fails.
286      */

287     protected void labelResource(String JavaDoc resourcePath) throws NestedSlideException {
288         NestedSlideException nestedSlideException = new NestedSlideException(null);
289         try {
290             labelResource(resourcePath, getDepth(), nestedSlideException);
291         }
292         catch (WebdavException e) {
293             nestedSlideException.addException(e);
294         }
295         if ( ! nestedSlideException.isEmpty() ) {
296             throw nestedSlideException;
297         }
298     }
299     
300     /**
301      * Labels the reource identified by the given <code>resourcePath</code>.
302      * If the resource is a collection and the <code>depth</code> > 0
303      * than the request is applied recursivly. If an attempt to label a resource
304      * fails, the corresponding Exception will be added to the given
305      * <code>nestedSlideException</code>.
306      *
307      * @param resourcePath the path of the resource to label.
308      * @param depth the depth to use if the resource is a collection.
309      * @param nestedSlideException the NestedSlideException to add all occurring
310      * Exceptions to.
311      */

312     protected void labelResource(String JavaDoc resourcePath, int depth, NestedSlideException nestedSlideException) {
313         
314         try {
315             
316             if ( ! isCollection(resourcePath) ) {
317                 ViolatedPrecondition violatedPrecondition = getPreconditionViolation(resourcePath);
318                 if (violatedPrecondition != null) {
319                     throw new PreconditionViolationException(violatedPrecondition, resourcePath);
320                 }
321                 
322                 performLabelOperation(resourcePath);
323             }
324             else if (depth > 0) {
325                 
326                 // process children recursivly
327
ObjectNode currentNode = structure.retrieve(slideToken, resourcePath);
328                 Enumeration JavaDoc childrenEnum = structure.getChildren(slideToken, currentNode);
329                 if (childrenEnum != null) {
330                     while (childrenEnum.hasMoreElements()) {
331                         labelResource(((ObjectNode)childrenEnum.nextElement()).getUri(), depth-1, nestedSlideException);
332                     }
333                 }
334             }
335         }
336         catch (SlideException e) {
337             nestedSlideException.addException(e);
338         }
339         catch (JDOMException e) {
340             nestedSlideException.addException(new SlideException(e.getMessage()));
341         }
342     }
343     
344     /**
345      * Perform the LABEL operation means it either adds, sets or removes the label.
346      *
347      * @param resourcePath the resource to add/set/remove the label.
348      *
349      * @throws JDOMException
350      * @throws SlideException
351      */

352     private void performLabelOperation(String JavaDoc resourcePath) throws JDOMException, SlideException {
353         
354         String JavaDoc labelHeader = WebdavUtils.fixTomcatHeader(requestHeaders.getLabel(), "UTF-8");
355         String JavaDoc labeledResourceUri = getResourceUri(resourcePath, labelHeader);
356         NodeRevisionDescriptors revisionDescriptors =
357             content.retrieve( slideToken, labeledResourceUri);
358         NodeRevisionDescriptor revisionDescriptor =
359             content.retrieve( slideToken, revisionDescriptors);
360         ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(token, revisionDescriptors, revisionDescriptor);
361         if (resourceKind instanceof Version) {
362             
363             if (DeltavConstants.E_REMOVE.equals(operation)) {
364                 PropertyHelper.removeElementFromProperty(revisionDescriptor,
365                                                          P_LABEL_NAME_SET,
366                                                          E_LABEL_NAME,
367                                                          label);
368                 content.store(slideToken, revisionDescriptors.getUri(), revisionDescriptor, null);
369             }
370             
371             if (DeltavConstants.E_SET.equals(operation)) {
372                 try {
373                     NodeRevisionDescriptor alreadyLabeledDescriptor =
374                         versioningHelper.retrieveLabeledRevision(revisionDescriptors.getUri(),
375                                                                  label);
376                     PropertyHelper.removeElementFromProperty(alreadyLabeledDescriptor,
377                                                              P_LABEL_NAME_SET,
378                                                              E_LABEL_NAME,
379                                                              label);
380                     content.store(slideToken, revisionDescriptors.getUri(), alreadyLabeledDescriptor, null);
381                 }
382                 catch (LabeledRevisionNotFoundException e) {
383                     // there is no version with the given label so far,
384
// so we can perform the <set> operation without any preparation
385
}
386             }
387             
388             if (DeltavConstants.E_ADD.equals(operation) ||
389                 DeltavConstants.E_SET.equals(operation) ) {
390                 PropertyHelper.addElementToProperty(revisionDescriptor,
391                                                     P_LABEL_NAME_SET,
392                                                     E_LABEL_NAME,
393                                                     label);
394                 content.store(slideToken, revisionDescriptors.getUri(), revisionDescriptor, null);
395             }
396         }
397     }
398     
399     /**
400      * Checks the (DeltaV) preconditions
401      * <ul>
402      * <li>&lt;DAV:must-be-checked-in&gt;</li>
403      * <li>&lt;DAV:must-select-version-in-history&gt;</li>
404      * <li>&lt;DAV:must-be-new-label&gt;</li>
405      * <li>&lt;DAV:label-must-exist&gt;</li>
406      * </ul>
407      *
408      * @param resourcePath the URI of the resource.
409      *
410      * @return the precondition that has been violated (if any).
411      *
412      * @throws SlideException
413      */

414     protected ViolatedPrecondition getPreconditionViolation(String JavaDoc resourcePath) throws SlideException {
415         
416         ViolatedPrecondition violatedPrecondition = null;
417         NodeRevisionDescriptors revisionDescriptors =
418             content.retrieve( slideToken, resourcePath);
419         NodeRevisionDescriptor revisionDescriptor =
420             content.retrieve( slideToken, revisionDescriptors);
421         ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(token, revisionDescriptors, revisionDescriptor);
422         
423         // check <DAV:must-be-checked-in>
424
if ( (resourceKind instanceof VersionControlled) &&
425             !(resourceKind instanceof CheckedInVersionControlled) ) {
426             return new ViolatedPrecondition(DeltavConstants.C_MUST_BE_CHECKED_IN,
427                                             WebdavStatus.SC_CONFLICT);
428         }
429         
430         // check <DAV:must-select-version-in-history>
431
if ( (resourceKind instanceof VersionControlled) &&
432                 (labelHeader != null) ) {
433             try {
434                 versioningHelper.getLabeledResourceUri(resourcePath, labelHeader);
435             }
436             catch (LabeledRevisionNotFoundException e) {
437                 return new ViolatedPrecondition(DeltavConstants.C_MUST_SELECT_VERSION_IN_HISTORY,
438                                                 WebdavStatus.SC_CONFLICT);
439             }
440         }
441         
442         try {
443             String JavaDoc slideResourceUri = getResourceUri(resourcePath, labelHeader);
444             revisionDescriptors =
445                 content.retrieve( slideToken, slideResourceUri);
446             revisionDescriptor =
447                 content.retrieve( slideToken, revisionDescriptors);
448             resourceKind = AbstractResourceKind.determineResourceKind(token, revisionDescriptors, revisionDescriptor);
449             if (resourceKind instanceof Version) {
450                 
451                 // check <DAV:label-must-exist>
452
if (DeltavConstants.E_REMOVE.equals(operation)) {
453                     if ( ! hasLabel(revisionDescriptor, label) ) {
454                         return new ViolatedPrecondition(DeltavConstants.C_LABEL_MUST_EXIST,
455                                                         WebdavStatus.SC_CONFLICT);
456                     }
457                 }
458                 
459                 try {
460                     versioningHelper.retrieveLabeledRevision(revisionDescriptors.getUri(), label);
461                     // check <DAV:must-be-new-label>
462
if (DeltavConstants.E_ADD.equals(operation)) {
463                         return new ViolatedPrecondition(DeltavConstants.C_MUST_BE_NEW_LABEL,
464                                                         WebdavStatus.SC_CONFLICT);
465                     }
466                 }
467                 catch (LabeledRevisionNotFoundException e) {}
468             }
469         }
470         catch (LabeledRevisionNotFoundException e) {
471             // check <DAV:label-must-exist>
472
if (DeltavConstants.E_REMOVE.equals(operation)) {
473                 return new ViolatedPrecondition(DeltavConstants.C_LABEL_MUST_EXIST,
474                                                 WebdavStatus.SC_CONFLICT);
475             }
476         }
477         
478         return violatedPrecondition;
479     }
480     
481     
482     /**
483      * Returns the value of the <code>Depth</code> header. If not specified,
484      * <code>0</code> is used as default.
485      *
486      * @return the value of the <code>Depth</code> header.
487      */

488     private int getDepth() throws WebdavException {
489         return requestHeaders.getDepth(0);
490     }
491     
492     /**
493      * Returns <code>true</code> if the given <code>revisionDescriptor</code>
494      * has a <code>&lt;label-name-set&gt;</code> property that contains a
495      * <code>&lt;label-name&gt;</code> element with the given <code>label</code>.
496      *
497      * @param revisionDescriptor the NodeRevisionDescriptor to check.
498      * @param label the label to look for.
499      *
500      * @return <code>true</code>, if the label was found.
501      */

502     protected boolean hasLabel(NodeRevisionDescriptor revisionDescriptor, String JavaDoc label) {
503         
504         boolean containsLabel = false;
505         NodeProperty labelNameSetProperty = revisionDescriptor.getProperty(DeltavConstants.P_LABEL_NAME_SET);
506         if ( (labelNameSetProperty != null) && (labelNameSetProperty.getValue() != null) ) {
507             try {
508                 XMLValue xmlValue = new XMLValue(labelNameSetProperty.getValue().toString());
509                 Iterator JavaDoc iterator = xmlValue.iterator();
510                 while ( !containsLabel && iterator.hasNext()) {
511                     containsLabel = label.equals(((Element)iterator.next()).getText());
512                 }
513             }
514             catch (JDOMException e) {}
515             catch (IllegalArgumentException JavaDoc e) {}
516         }
517         
518         return containsLabel;
519     }
520     
521     /**
522      * Returns the Uri of the resource identified by the given <code>resourcePath</code>
523      * and the given <code>label</code>. If the <code>label</code> is <code>null</code>
524      * and the resource is a VCR, the associated VR is returned.
525      *
526      * @param resourcePath the path of the resource.
527      * @param label the label (may be <code>null</code>).
528      *
529      * @return the Uri of the resource identified by the given <code>resourcePath</code>
530      * and the given <code>label</code>.
531      *
532      * @throws SlideException
533      */

534     protected String JavaDoc getResourceUri(String JavaDoc resourcePath, String JavaDoc label) throws SlideException {
535         
536         String JavaDoc labeledResourceUri = versioningHelper.getLabeledResourceUri(resourcePath,
537                                                                            label);
538         NodeRevisionDescriptors revisionDescriptors =
539             content.retrieve( slideToken,labeledResourceUri);
540         NodeRevisionDescriptor revisionDescriptor =
541             content.retrieve( slideToken, revisionDescriptors);
542         ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(token, revisionDescriptors, revisionDescriptor);
543         if (resourceKind instanceof VersionControlled) {
544             labeledResourceUri = versioningHelper.getUriOfAssociatedVR(resourcePath);
545         }
546         
547         return labeledResourceUri;
548     }
549     
550 }
551
552
553
Popular Tags