KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropFindMethod.java,v 1.105.2.1 2004/09/17 15:39:34 luetzkendorf Exp $
3  * $Revision: 1.105.2.1 $
4  * $Date: 2004/09/17 15:39:34 $
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;
27 import java.util.Enumeration;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Stack;
31
32 import org.apache.slide.common.NamespaceAccessToken;
33 import org.apache.slide.common.PropertyParseException;
34 import org.apache.slide.common.RequestedProperties;
35 import org.apache.slide.common.RequestedPropertiesImpl;
36 import org.apache.slide.common.RequestedProperty;
37 import org.apache.slide.common.ServiceAccessException;
38 import org.apache.slide.common.SlideException;
39 import org.apache.slide.common.SlideToken;
40 import org.apache.slide.common.SlideTokenWrapper;
41 import org.apache.slide.common.UriPath;
42 import org.apache.slide.content.NodeRevisionDescriptor;
43 import org.apache.slide.content.NodeRevisionDescriptors;
44 import org.apache.slide.content.RevisionDescriptorNotFoundException;
45 import org.apache.slide.event.EventDispatcher;
46 import org.apache.slide.security.AccessDeniedException;
47 import org.apache.slide.structure.ObjectNode;
48 import org.apache.slide.structure.StructureException;
49 import org.apache.slide.util.Configuration;
50 import org.apache.slide.webdav.WebdavException;
51 import org.apache.slide.webdav.WebdavServletConfig;
52 import org.apache.slide.webdav.event.WebdavEvent;
53 import org.apache.slide.webdav.util.AclConstants;
54 import org.apache.slide.webdav.util.DeltavConstants;
55 import org.apache.slide.webdav.util.LabeledRevisionNotFoundException;
56 import org.apache.slide.webdav.util.PropertyRetrieverImpl;
57 import org.apache.slide.webdav.util.UnlockListenerImpl;
58 import org.apache.slide.webdav.util.VersioningHelper;
59 import org.apache.slide.webdav.util.WebdavStatus;
60 import org.apache.slide.webdav.util.WebdavUtils;
61 import org.jdom.Document;
62 import org.jdom.Element;
63 import org.jdom.JDOMException;
64 import org.jdom.Namespace;
65 import org.jdom.input.SAXBuilder;
66 import org.jdom.output.XMLOutputter;
67
68 /**
69  * PROPFIND method.
70  *
71  */

72 public class PropFindMethod extends AbstractWebdavMethod implements DeltavConstants, AclConstants, ReadMethod {
73     
74     /**
75      * Specify a property mask.
76      */

77     protected static final int FIND_BY_PROPERTY = 0;
78     
79     
80     /**
81      * Display all properties.
82      */

83     protected static final int FIND_ALL_PROP = 1;
84     
85     
86     /**
87      * Return property names.
88      */

89     protected static final int FIND_PROPERTY_NAMES = 2;
90     
91     // ----------------------------------------------------- Instance Variables
92

93     
94     /**
95      * Depth.
96      */

97     protected int depth;
98     
99     
100     /**
101      * Type of the PROPFIND method.
102      */

103     protected int propFindType;
104     
105     /** if true, an ALL_PROP request will include computed props */
106     protected boolean extendedAllprop = false;
107     
108     
109     
110     /**
111      ** The SAXBuilder used to create JDOM Documents.
112      **/

113     protected static SAXBuilder saxBuilder = null;
114     
115     /**
116      * The list of requested properties.
117      */

118     protected RequestedProperties requestedProperties = null;
119     
120     
121     /**
122      * Resource to be retrieved.
123      */

124     protected String resourcePath;
125     
126     /**
127      * The VersioningHelper used by this instance.
128      */

129     protected VersioningHelper versioningHelper = null;
130     
131     /**
132      * The value of the <code>Label</code> header.
133      */

134     protected String labelHeader = null;
135     
136     /**
137      * If set <code>true</code>, instead of creating the complete response document
138      * in memory and then sending it to the client, available parts of the response
139      * are send immediatly in order to reduce the memory footprint.
140      */

141     protected boolean outputOptimized = true;
142     
143     // ----------------------------------------------------------- Constructors
144

145     
146     /**
147      * Constructor.
148      *
149      * @param token the token for accessing the namespace
150      * @param config configuration of the WebDAV servlet
151      */

152     public PropFindMethod(NamespaceAccessToken token,
153                           WebdavServletConfig config) {
154         super(token, config);
155     }
156     
157     
158     // ------------------------------------------------------ Protected Methods
159

160     
161     /**
162      * Parse the request.
163      *
164      * @exception WebdavException Bad request
165      */

166     protected void parseRequest() throws WebdavException {
167         
168         versioningHelper = VersioningHelper.getVersioningHelper(
169             slideToken, token, req, resp, getConfig() );
170         // readRequestContent();
171

172         depth = INFINITY;
173         propFindType = FIND_ALL_PROP;
174         extendedAllprop = getBooleanInitParameter( "extendedAllprop" );
175         outputOptimized = getBooleanInitParameter( "optimizePropfindOutput" );
176         
177         resourcePath = requestUri;
178         if (resourcePath == null) {
179             resourcePath = "/";
180         }
181         
182         labelHeader = WebdavUtils.fixTomcatHeader(requestHeaders.getLabel(), "UTF-8");
183         
184         retrieveDepth();
185         
186         if (req.getContentLength() == 0) {
187             requestedProperties = new RequestedPropertiesImpl();
188             requestedProperties.setIsAllProp(true);
189             propFindType = FIND_ALL_PROP;
190         }
191         else {
192             
193             try {
194                 
195                 Element element = parseRequestContent(E_PROPFIND);
196                 try {
197                     element = (Element)element.getChildren().get(0);
198                 }
199                 catch (Exception e) {
200                     int statusCode = WebdavStatus.SC_BAD_REQUEST;
201                     sendError( statusCode, getClass().getName()+".missingRootElementChildren", new Object[]{"DAV:"+E_PROPFIND} );
202                     throw new WebdavException( statusCode );
203                 }
204                 
205                 if (element.getName().equalsIgnoreCase(E_PROPNAME)){
206                     propFindType = FIND_PROPERTY_NAMES;
207                 }
208                 else if ( element.getName().equalsIgnoreCase(E_PROP) ) {
209                     requestedProperties = new RequestedPropertiesImpl(element);
210                     propFindType = FIND_BY_PROPERTY;
211                 }
212                 else if ( element.getName().equalsIgnoreCase(E_ALLPROP) ) {
213                     requestedProperties = new RequestedPropertiesImpl(element);
214                     propFindType = FIND_ALL_PROP;
215                 }
216                 else {
217                     int statusCode = WebdavStatus.SC_BAD_REQUEST;
218                     sendError( statusCode, getClass().getName()+".invalidChildOfRootElement", new Object[]{element.getNamespace()+":"+element.getName(),"DAV:"+E_PROPFIND} );
219                     throw new WebdavException( statusCode );
220                 }
221                 
222             }
223             catch (JDOMException e){
224                 int statusCode = WebdavStatus.SC_BAD_REQUEST;
225                 sendError( statusCode, e );
226                 throw new WebdavException( statusCode );
227             }
228             catch (PropertyParseException e){
229                 int statusCode = WebdavStatus.SC_BAD_REQUEST;
230                 sendError( statusCode, e );
231                 throw new WebdavException( statusCode );
232             }
233             catch (IOException e){
234                 int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
235                 sendError( statusCode, e );
236                 throw new WebdavException( statusCode );
237             }
238         }
239     }
240     
241     /**
242      * Retrieves the <code>Depth</code> header from the request.
243      */

244     private void retrieveDepth() throws WebdavException {
245         depth = requestHeaders.getDepth(INFINITY);
246         
247         // limit tree browsing a bit
248
if (depth > getConfig().getDepthLimit()) {
249             depth = getConfig().getDepthLimit();
250         }
251     }
252     
253     
254     
255     /**
256      * Execute the request.
257      *
258      * @exception WebdavException
259      */

260     protected void executeRequest() throws IOException, WebdavException {
261         
262         resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
263         
264         // Loads the associated object from the store.
265

266         // Get the object from Data.
267
ObjectNode resource = null;
268         
269         try {
270             if ( WebdavEvent.PROPFIND.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.PROPFIND, new WebdavEvent(this));
271             resource = structure.retrieve(slideToken, resourcePath);
272         } catch (StructureException e) {
273             int statusCode = WebdavStatus.SC_NOT_FOUND;
274             sendError( statusCode, e );
275             throw new WebdavException( statusCode );
276         } catch (Exception e) {
277             int statusCode = getErrorCode( e );
278             sendError( statusCode, e );
279             throw new WebdavException( statusCode );
280         }
281         
282         resp.setContentType(TEXT_XML_UTF_8);
283         
284         // Create multistatus object
285
Element multistatusElement = new Element(E_MULTISTATUS, DNSP);
286         org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
287         format.setIndent(XML_RESPONSE_INDENT);
288         XMLOutputter xmlOutputter = new XMLOutputter(format);
289         
290         if (resource != null) {
291             if (depth == 0) {
292                 multistatusElement.addContent(getPropertiesOfObject(resource.getUri()));
293                 xmlOutputter.output(new Document(multistatusElement), resp.getWriter());
294             } else {
295                 // The stack always contains the object of the current level
296
Stack stack = new Stack();
297                 stack.push(resource);
298                 
299                 // Stack of the objects one level below
300
Stack stackBelow = new Stack();
301                 
302                 StringBuffer buffer = new StringBuffer();
303                 if (outputOptimized) {
304                     
305                     resp.getWriter().write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
306                     resp.getWriter().write("\n");
307                     String namespacePrefix = multistatusElement.getNamespacePrefix();
308                     if ( (namespacePrefix != null) && (namespacePrefix.length() == 0) ) {
309                         namespacePrefix = null;
310                     }
311                     String namespaceUri = multistatusElement.getNamespaceURI();
312                     if ( (namespaceUri != null) && (namespaceUri.length() == 0) ) {
313                         namespaceUri = null;
314                     }
315                     buffer.append("<");
316                     buffer.append(multistatusElement.getQualifiedName());
317                     if (namespaceUri != null) {
318                         buffer.append(" xmlns");
319                         if (namespacePrefix != null) {
320                             buffer.append(":");
321                             buffer.append(namespacePrefix);
322                         }
323                         buffer.append("=\"");
324                         buffer.append(namespaceUri);
325                         buffer.append("\"");
326                     }
327                     buffer.append(">");
328                     resp.getWriter().write(buffer.toString());
329                     resp.getWriter().write("\n");
330                 }
331                 
332                 while ((!stack.isEmpty()) && (depth >= 0)) {
333                     
334                     ObjectNode cur = (ObjectNode) stack.pop();
335                     Element response = getPropertiesOfObject(cur.getUri());
336                     if (outputOptimized) {
337                         xmlOutputter.output(response, resp.getWriter());
338                     }
339                     else {
340                         multistatusElement.addContent(response);
341                     }
342                     
343                     if (depth > 0) {
344                         
345                         Enumeration enum = null;
346                         
347                         try {
348                             enum = structure.getChildren(slideToken, cur);
349                         } catch (Exception e) {
350                             int statusCode = getErrorCode( e );
351                             sendError( statusCode, e );
352                             throw new WebdavException( statusCode );
353                         }
354                         
355                         while (enum.hasMoreElements()) {
356                             // PROPFIND must not list Lock-Null resources that
357
// are timed out
358
ObjectNode node = (ObjectNode)enum.nextElement();
359                             UnlockListenerImpl listener = new UnlockListenerImpl(
360                                     slideToken, token, config, req, resp);
361                             try {
362                                 lock.clearExpiredLocks(slideToken, node.getUri(), listener);
363                                 if (!listener.isRemovedLockResource(node.getUri())) {
364                                     stackBelow.push(node);
365                                 }
366                             } catch (SlideException e) { /* ignore */}
367                         }
368                         
369                     }
370                     
371                     if (stack.isEmpty()) {
372                         depth--;
373                         stack = stackBelow;
374                         stackBelow = new Stack();
375                     }
376                     
377                 }
378                 
379                 if (outputOptimized) {
380                     resp.getWriter().write("\n");
381                     buffer.setLength(0);
382                     buffer.append("</");
383                     buffer.append(multistatusElement.getQualifiedName());
384                     buffer.append(">");
385                     resp.getWriter().write(buffer.toString());
386                     resp.getWriter().write("\n");
387                 }
388                 else {
389                     xmlOutputter.output(new Document(multistatusElement), resp.getWriter());
390                 }
391             }
392         }
393         
394     }
395     
396     
397     /**
398      * Return the properties of an object as a <code>&lt;response&gt;</code>.
399      *
400      * @param resourceUri the slide URI of the resource.
401      *
402      * @return the <code>&lt;response&gt;</code> Element.
403      *
404      * @exception WebdavException
405      */

406     protected Element getPropertiesOfObject(String resourceUri)
407         throws WebdavException {
408         
409         SlideToken lightSToken = new SlideTokenWrapper(slideToken);
410         lightSToken.setForceLock(false);
411         
412         // evaluate "Label" header
413
if (Configuration.useVersionControl()) {
414             try {
415                 resourceUri = versioningHelper.getLabeledResourceUri(resourceUri, labelHeader);
416             }
417             catch (LabeledRevisionNotFoundException e) {
418                 return getErrorResponse(resourceUri,
419                                         WebdavStatus.SC_CONFLICT,
420                                         DeltavConstants.C_MUST_SELECT_VERSION_IN_HISTORY);
421             }
422             catch( RevisionDescriptorNotFoundException x ) {
423             }
424             catch (SlideException e) {
425                 return getErrorResponse(resourceUri, getErrorCode(e), null);
426             }
427         }
428         
429         ObjectNode object = null;
430         try {
431             object = structure.retrieve(lightSToken, resourceUri);
432         }
433         catch (SlideException e) {
434             return getErrorResponse(resourceUri, getErrorCode(e), null);
435         }
436         
437         Element responseElement = new Element(E_RESPONSE, DNSP);
438         
439         String status = new String(HTTP_VERSION + WebdavStatus.SC_OK + " "
440                                        + WebdavStatus.getStatusText
441                                        (WebdavStatus.SC_OK));
442         NodeRevisionDescriptors revisionDescriptors = null;
443         NodeRevisionDescriptor revisionDescriptor = null;
444         
445         //boolean isCollection = false;
446

447 // NodeLock objectLockToken = null;
448

449         try {
450             Element hrefElement = new Element(E_HREF, DNSP);
451             
452             //VersioningHelper vHelp = VersioningHelper.getVersioningHelper(
453
// lightSToken, token, req, resp, getConfig() );
454
String resourcePath = object.getUri();
455             
456             revisionDescriptors =
457                 content.retrieve(lightSToken, resourcePath);
458             
459             try {
460                 revisionDescriptor = content.retrieve(lightSToken,
461                                                       revisionDescriptors);
462                 
463                 //isCollection = WebdavUtils.isCollection(revisionDescriptor);
464

465                 hrefElement.setText(
466                     WebdavUtils.getAbsolutePath(object.getUri(), req,
467                                                 getConfig()));
468                 
469             } catch (RevisionDescriptorNotFoundException e) {
470                 
471                 // The object doesn't have any revision, we create a dummy
472
// NodeRevisionDescriptor object
473
//isCollection = true;
474
revisionDescriptor = new NodeRevisionDescriptor(0);
475                 
476                 if (!Configuration.useBinding(token.getUri(lightSToken, object.getUri()).getStore())) {
477                     revisionDescriptor.setName(new UriPath(object.getUri()).lastSegment());
478                 }
479                 
480                 hrefElement.setText(
481                     WebdavUtils.getAbsolutePath(object.getUri(), req,
482                                                 getConfig()));
483             }
484             
485             responseElement.addContent(hrefElement);
486             
487 // Enumeration lockTokens = lock.enumerateLocks(lightSToken, object.getUri(), true);
488

489 // if (lockTokens.hasMoreElements()) {
490
// objectLockToken = (NodeLock) lockTokens.nextElement();
491
// }
492

493         } catch (AccessDeniedException e) {
494             if (revisionDescriptor == null) {
495                 revisionDescriptor = new NodeRevisionDescriptor(0);
496             }
497         } catch (Exception e) {
498             int statusCode = getErrorCode( e );
499             sendError( statusCode, e );
500             throw new WebdavException( statusCode );
501         }
502
503         PropertyRetrieverImpl propertyRetriever = new PropertyRetrieverImpl(token, lightSToken, getConfig());
504
505         switch (propFindType) {
506             case FIND_ALL_PROP :
507             case FIND_BY_PROPERTY :
508                 try {
509                     List propstatList= propertyRetriever.getPropertiesOfObject(requestedProperties, revisionDescriptors, revisionDescriptor, getSlideContextPath(), extendedAllprop);
510                     Iterator iterator = propstatList.iterator();
511                     while (iterator.hasNext()) {
512                         responseElement.addContent((Element)iterator.next());
513                     }
514                 } catch (ServiceAccessException e) {
515                     int statusCode = WebdavStatus.SC_FORBIDDEN;
516                     sendError( statusCode, e );
517                     throw new WebdavException( statusCode );
518                 } catch (Exception e) {
519                     int statusCode = getErrorCode( e );
520                     sendError( statusCode, e );
521                     throw new WebdavException( statusCode );
522                 }
523                 break;
524             case FIND_PROPERTY_NAMES :
525
526                 try {
527                     status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
528                                             + " " + WebdavStatus.getStatusText
529                                             (WebdavStatus.SC_OK));
530
531                     Element propstatElement = new Element(E_PROPSTAT, DNSP);
532                     Element propElement = new Element(E_PROP, DNSP);
533                     RequestedProperties propnames =
534                         propertyRetriever.getAllPropertyNames(object.getUri(), true);
535                     Iterator iterator = propnames.getRequestedProperties();
536                     while (iterator.hasNext()) {
537                         RequestedProperty p = (RequestedProperty)iterator.next();
538                         Namespace nsp = DNSP.getURI().equals(p.getNamespace())
539                             ? DNSP
540                             : Namespace.getNamespace(p.getNamespace());
541                         propElement.addContent(new Element(p.getName(), nsp));
542                     }
543                     Element statusElement = new Element(E_STATUS, DNSP);
544                     statusElement.setText(status);
545                     propstatElement.addContent(propElement);
546                     propstatElement.addContent(statusElement);
547                     responseElement.addContent(propstatElement);
548                 }
549                 catch (ServiceAccessException e) {
550                     int statusCode = WebdavStatus.SC_FORBIDDEN;
551                     sendError( statusCode, e );
552                     throw new WebdavException( statusCode );
553                 }
554                 catch (Exception e) {
555                     int statusCode = getErrorCode( e );
556                     sendError( statusCode, e );
557                     throw new WebdavException( statusCode );
558                 }
559                 break;
560         }
561
562         return responseElement;
563     }
564
565     /**
566      * Returns the appropriate <code>&lt;response&gt;</code> due to the given
567      * <code>exception</code> to the <code>generatedXML</code>
568      *
569      * @param resourcePath the URI of the request to display in the
570      * <code>&lt;href&gt;</code> element.
571      * @param errorCode the HTTP error code.
572      * @param condition the condition that has been violated.
573      */

574     private Element getErrorResponse(String resourcePath, int errorCode, String condition) {
575         
576         Element response = new Element(E_RESPONSE, DNSP);
577         
578         Element href = new Element(E_HREF, DNSP);
579         href.setText(HTTP_PROTOCOL +
580                          req.getServerName()+ ":" +
581                          req.getServerPort() +
582                          getSlideContextPath() +
583                          resourcePath);
584         response.addContent(href);
585         Element propStat = new Element(E_PROPSTAT, DNSP);
586         response.addContent(propStat);
587         
588         Element status = new Element(E_STATUS, DNSP);
589         status.setText(HTTP_VERSION + " " + errorCode + " " + WebdavStatus.getStatusText(errorCode));
590         propStat.addContent(status);
591         
592         if (condition != null) {
593             Element responseDescriptiont = new Element(E_RESPONSEDESCRIPTION, DNSP);
594             Element errorElement = new Element(E_ERROR, DNSP);
595             responseDescriptiont.addContent(errorElement);
596             Element conditionElement = new Element(condition, DNSP);
597             errorElement.addContent(conditionElement);
598             propStat.addContent(responseDescriptiont);
599         }
600         return response;
601     }
602 }
603
604
605
606
607
608
609
610
611
612
Popular Tags