KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > webdav > impl > CachedPropertiesManager


1 package com.ibm.webdav.impl;
2
3 /*
4  * (C) Copyright IBM Corp. 2000 All rights reserved.
5  *
6  * The program is provided "AS IS" without any warranty express or
7  * implied, including the warranty of non-infringement and the implied
8  * warranties of merchantibility and fitness for a particular purpose.
9  * IBM will not be liable for any damages suffered by you as a result
10  * of using the Program. In no event will IBM be liable for any
11  * special, indirect or consequential damages or lost profits even if
12  * IBM has been advised of the possibility of their occurrence. IBM
13  * will not be liable for any third party claims against you.
14  *
15  * Portions Copyright (C) Simulacra Media Ltd, 2004.
16  */

17 import java.io.*;
18 import java.util.*;
19
20 import javax.xml.parsers.*;
21
22 import org.w3c.dom.*;
23
24 import com.ibm.webdav.*;
25
26
27 /** CachedPropertiesManager implements the Properties interface by loading
28  * all properties on an initial request, and then accessing from the
29  * cache to satisfy more specific requests. This implementation is
30  * appropriate in those situations where reading all the properties
31  * is just as efficient as reading one. CachedProperties is abstract
32  * because it relies on specific subclasses to support the actual
33  * reading and writing of the properties.
34  * @author Jim Amsden <jamsden@us.ibm.com>
35  */

36 public abstract class CachedPropertiesManager implements PropertiesManager {
37     private static final int set = 0;
38     private static final int remove = 1;
39     protected ResourceImpl resource = null;
40
41     /** The default constructor.
42     */

43     public CachedPropertiesManager() {
44     }
45
46     /** Create a properties manager for the given resource and its
47     * namespace manager.
48     * @param resource the resource whose properties are to be managed
49     * @param namespaceManager its namespace manager
50     */

51     public CachedPropertiesManager(ResourceImpl resource,
52                                    com.ibm.webdav.impl.NamespaceManager namespaceManager) {
53         initialize(resource, namespaceManager);
54     }
55
56     /** Delete all properties for the managed resource
57     * @exception IOException
58     * @exception com.ibm.webdav.WebDAVException
59     */

60     public abstract void deleteProperties() throws WebDAVException;
61
62     /** Get all the properties of this resource.
63     * This implementation stores properties in an XML document containing a properties
64     * root element. The properties file name is derived from the URI by adding the extension
65     * PropertiesManager.propertiesSuffix. This applies to collections as well as other resources.
66     * <p>
67     * Since the properties are stored in a file, and all methods that query and
68     * update the properties must read the XML file into memory and parse it,
69     * many of the other property methods are implemented by calling this method.
70     * Subclasses of ResourceImpl may want to use other techniques depending on
71     * how the properties are stored.
72     * </p>
73     * @return a MultiStatus containing response elements with prop elements
74     * containing the properties and their statuses.
75     * @exception com.ibm.webdav.WebDAVException
76     */

77     public MultiStatus getProperties()
78                               throws WebDAVException {
79         Document propertiesDocument = resource.loadProperties();
80
81         // create a MultiStatus to hold the results
82
MultiStatus results = new MultiStatus();
83
84         // create a response element to hold the properties for this resource
85
PropertyResponse response = null;
86         String JavaDoc urlstring;
87
88         if (false) {
89             // I consider this to be the more correct way and the
90
// way used in the examples in the spec... but it is
91
// redundant and creates the possibility of the two
92
// redundant parts being out of synch.
93
urlstring = resource.getURL().toString();
94         } else {
95             // this is the way that mod_dav and a few others do it. This
96
// way also makes it easier to debug clients even if
97
// redirecting through a dedicated proxy. Without this
98
// it's inconvenient to debug IE5. It gets confused if
99
// the host:port (if provided) don't match who it thinks
100
// it's connecting to.
101
urlstring = resource.getURL().getFile();
102         }
103
104         response = new PropertyResponse(urlstring);
105
106         // add the properties to the response
107
NodeList properties = propertiesDocument.getDocumentElement()
108                                                 .getChildNodes();
109         Node temp = null;
110
111         for (int i = 0; i < properties.getLength(); i++) {
112             temp = properties.item(i);
113
114             // Skip ignorable TXText elements
115
if (!(temp.getNodeType() == Node.ELEMENT_NODE)) {
116                 continue;
117             }
118
119             Element property = (Element) temp;
120             PropertyName pn = new PropertyName(property);
121             response.addProperty(pn, property, WebDAVStatus.SC_OK);
122         }
123
124         results.addResponse(response);
125
126         return results;
127     }
128
129     /** Get the named properties for this resource and (potentially) its children.
130     *
131     * @param names an arrary of property names to retrieve
132     * @return a MultiStatus of PropertyResponses
133     * @exception com.ibm.webdav.WebDAVException
134     */

135     public MultiStatus getProperties(PropertyName[] names)
136                               throws WebDAVException {
137         MultiStatus multiStatus = resource.getProperties(resource.getContext());
138         MultiStatus newMultiStatus = new MultiStatus();
139
140         Enumeration responses = multiStatus.getResponses();
141
142         while (responses.hasMoreElements()) {
143             PropertyResponse response = (PropertyResponse) responses.nextElement();
144             PropertyResponse newResponse = new PropertyResponse(
145                                                    response.getResource());
146             newResponse.setDescription(response.getDescription());
147             newMultiStatus.addResponse(newResponse);
148
149             Hashtable properties = (Hashtable) response.getPropertiesByPropName();
150
151             //Hashtable newProperties = (Hashtable) newResponse.getProperties();
152
for (int i = 0; i < names.length; i++) {
153                 if (properties.containsKey(names[i])) {
154                     PropertyValue srcval = response.getProperty(names[i]);
155                     newResponse.setProperty(names[i], srcval);
156
157                     //newProperties.put(names[i], properties.get(names[i]));
158
} else {
159                     Document factory = null;
160
161                     try {
162                         factory = DocumentBuilderFactory.newInstance()
163                                                         .newDocumentBuilder()
164                                                         .newDocument();
165                     } catch (Exception JavaDoc e) {
166                         throw new WebDAVException(WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
167                                                   e.getMessage());
168                     }
169
170                     // we'll create an xml element with no value because that's
171
// what webdav will need to return for most methods... even if the
172
// property doesn't exist. That's because the
173
// distinction between a propertyname and propertyvalue
174
// is fuzzy in WebDAV xml. A property name is
175
// essentially an empty property value because
176
// all property values have their property
177
// name stuck on.
178
// if we decide to set reviewStatus to null instead (as
179
// we did previously, then the code for MultiStatus.asXML()
180
// needs to be updated to expect null values.
181
// (jlc 990520)
182
Element elTm = factory.createElementNS("X",
183                                                            "X:" +
184                                                            names[i].getLocal());
185
186                     elTm.setAttribute("xmlns:X", names[i].getNamespace());
187
188                     newResponse.addProperty(names[i], elTm,
189                                             WebDAVStatus.SC_NOT_FOUND);
190                 }
191             }
192         }
193
194         return newMultiStatus;
195     }
196
197     /** Get the names of all properties for this resource. This implementation
198     * reads all the properties and then extracts their names.
199     *
200     * @return a MultiStatus of PropertyResponses
201     * (PropertyValue.value is always null, PropertyValue.status contains the status)
202     * @exception com.ibm.webdav.WebDAVException
203     */

204     public MultiStatus getPropertyNames() throws WebDAVException {
205         MultiStatus multiStatus = resource.getProperties(resource.getContext());
206         Enumeration responses = multiStatus.getResponses();
207
208         // we have the result, but all of the properties in our structure contain
209
// values. We don't want to include values. Just names. The following
210
// code strips out the content of these elements.
211
while (responses.hasMoreElements()) {
212             PropertyResponse response = (PropertyResponse) responses.nextElement();
213             Dictionary properties = response.getPropertiesByPropName();
214             Enumeration keys = properties.keys();
215
216             while (keys.hasMoreElements()) {
217                 PropertyName key = (PropertyName) keys.nextElement();
218                 Element value = (Element) response.getProperty(key).getValue();
219                 response.setProperty(key,
220                                      new PropertyValue(
221                                              (Element) value.cloneNode(false),
222                                              WebDAVStatus.SC_OK));
223             }
224         }
225
226         return multiStatus;
227     }
228
229     /** Initialize this properties manager.
230     * @param resource the resource whose properties are to be managed
231     * @param namespaceManager its namespace manager
232     */

233     public void initialize(ResourceImpl resource,
234                            com.ibm.webdav.impl.NamespaceManager namespaceManager) {
235         this.resource = resource;
236     }
237
238     /** Is a property live, i.e., has semantics supported by the server?
239     * @param propertyName the name of the property to check
240     * @return true if the named property is live on this server
241     */

242     public boolean isLive(String JavaDoc propertyName) {
243         return propertyName.equals("creationdate") ||
244                    propertyName.equals("getcontentlength") ||
245                    propertyName.equals("getlastmodified") ||
246                    propertyName.equals("lockdiscovery") ||
247                    propertyName.equals("getcontenttype") ||
248                    propertyName.equals("resourcetype") ||
249                    propertyName.equals("supportedlock") ||
250                  propertyName.equals("DAV:creationdate") ||
251                propertyName.equals("DAV:getcontentlength") ||
252                propertyName.equals("DAV:getlastmodified") ||
253                propertyName.equals("DAV:lockdiscovery") ||
254                propertyName.equals("DAV:getcontenttype") ||
255                propertyName.equals("DAV:resourcetype") ||
256                propertyName.equals("DAV:supportedlock");
257     }
258
259     /** Load properties from their persistent store.
260     * @return an XML document containing a properties element.
261     * @exception com.ibm.webdav.WebDAVException
262     */

263     public abstract Document loadProperties() throws WebDAVException;
264
265
266     /** Remove the live DAV properties from the properties document that
267     * do not need to be saved. There is no reason to save them as long
268     * as they are recalculated each time the properties are loaded. This
269     * method removes the ones that are repository specific.
270     * @param propertiesDocument the XML document containing the properties. Elements
271     * are removed from this document that don't need to be saved.
272     */

273     public abstract void removeLiveProperties(Document propertiesDocument);
274
275     /** Save the properties to the persistent store.
276     * @param propertiesDocument an XML document containing a properties element.
277     * @exception com.ibm.webdav.WebDAVException
278     */

279     public abstract void saveProperties(Document propertiesDocument)
280                                  throws WebDAVException;
281
282     /** Edit the properties of a resource. The updates must refer to a Document containing a WebDAV
283     * propertyupdates element as the document root.
284     *
285     * @param updates an XML Document containing propertyupdate elements
286     * @return the result of making the updates
287     * describing the edits to be made.
288     * @exception com.ibm.webdav.WebDAVException
289     */

290     public MultiStatus setProperties(Document propertyUpdates)
291                               throws WebDAVException {
292         // create a MultiStatus to hold the results. It will hold a MethodResponse
293
// for each update, and one for the method as a whole
294
MultiStatus multiStatus = new MultiStatus();
295         boolean errorsOccurred = false;
296
297         // first, load the properties so they can be edited
298
Document propertiesDocument = resource.loadProperties();
299         Element properties = (Element) propertiesDocument.getDocumentElement();
300
301         // be sure the updates have at least one update
302
Element propertyupdate = (Element) propertyUpdates.getDocumentElement();
303         String JavaDoc tagName = propertyupdate.getNamespaceURI() +
304                          propertyupdate.getLocalName();
305
306         if (!tagName.equals("DAV:propertyupdate")) {
307             throw new WebDAVException(WebDAVStatus.SC_UNPROCESSABLE_ENTITY,
308                                       "missing propertyupdate element");
309         }
310
311         NodeList updates = propertyupdate.getChildNodes();
312
313         if (updates.getLength() == 0) {
314             throw new WebDAVException(WebDAVStatus.SC_UNPROCESSABLE_ENTITY,
315                                       "no updates in request");
316         }
317
318         Vector propsGood = new Vector(); // a list of properties that
319

320         // were patched correctly or would have been if another
321
// property hadn't gone bad.
322
// apply the updates
323
Node temp = null;
324
325         for (int i = 0; i < updates.getLength(); i++) {
326             temp = updates.item(i);
327
328             // skip any ignorable TXText elements
329
if (!(temp.getNodeType() == Node.ELEMENT_NODE)) {
330                 continue;
331             }
332
333             Element update = (Element) temp;
334             int updateCommand = -1;
335             tagName = update.getNamespaceURI() + update.getLocalName();
336
337             if (tagName.equals("DAV:set")) {
338                 updateCommand = set;
339             } else if (tagName.equals("DAV:remove")) {
340                 updateCommand = remove;
341             } else {
342                 throw new WebDAVException(WebDAVStatus.SC_UNPROCESSABLE_ENTITY,
343                                           update.getTagName() +
344                                           " is not a valid property update request");
345             }
346
347             // iterate through the props in the set or remove element and update the
348
// properties as directed
349
Element prop = (Element) update.getElementsByTagNameNS("DAV:",
350                                                                    "prop")
351                                            .item(0);
352
353             if (prop == null) {
354                 throw new WebDAVException(WebDAVStatus.SC_UNPROCESSABLE_ENTITY,
355                                           "no propeprties in update request");
356             }
357
358             NodeList propsToUpdate = prop.getChildNodes();
359
360             for (int j = 0; j < propsToUpdate.getLength(); j++) {
361                 temp = propsToUpdate.item(j);
362
363                 // skip any TXText elements??
364
if (!(temp.getNodeType() == Node.ELEMENT_NODE)) {
365                     continue;
366                 }
367
368                 Element propToUpdate = (Element) temp;
369
370                 // find the property in the properties element
371
Element property = null;
372                 PropertyName propertyName = new PropertyName(propToUpdate);
373
374                 if (((Element) propToUpdate).getNamespaceURI() != null) {
375                     property = (Element) properties.getElementsByTagNameNS(
376                                                  propToUpdate.getNamespaceURI(),
377                                                  propToUpdate.getLocalName())
378                                                    .item(0);
379                 } else {
380                     property = (Element) properties.getElementsByTagName(
381                                                  propToUpdate.getTagName())
382                                                    .item(0);
383                 }
384
385                 boolean liveone = isLive(propertyName.asExpandedString());
386
387                 if (liveone) {
388                     errorsOccurred = true;
389
390                     PropertyResponse response = new PropertyResponse(
391                                                         resource.getURL()
392                                                                 .toString());
393                     response.addProperty(propertyName, propToUpdate,
394                                          WebDAVStatus.SC_FORBIDDEN);
395                     multiStatus.addResponse(response);
396                 }
397
398                 // do the update
399
if (updateCommand == set) {
400                     if (property != null) {
401                         try {
402                             properties.removeChild(property);
403                         } catch (DOMException exc) {
404                         }
405                     }
406
407                     if (!liveone) {
408                         // I don't think we're allowed to update live properties
409
// here. Doing so effects the cache. A case in
410
// point is the lockdiscoveryproperty. properties
411
// is actually the properites cache "document" of this
412
// resource. Even though we don't "save" the request
413
// if it includes live properties, we don't remove
414
// it from the cache after we'd set it here, so it
415
// can affect other queries. (jlc 991002)
416
properties.appendChild(propertiesDocument.importNode(
417                                                        propToUpdate, true));
418
419                         propsGood.addElement(propToUpdate);
420                     }
421                 } else if (updateCommand == remove) {
422                     try {
423                         if (property != null) {
424                             properties.removeChild(property);
425                             propsGood.addElement(propToUpdate);
426                         }
427                     } catch (DOMException exc) {
428                     }
429                 }
430             }
431         }
432
433         {
434             Enumeration els = propsGood.elements();
435
436             for (; els.hasMoreElements();) {
437                 Object JavaDoc ob1 = els.nextElement();
438                 Element elProp = (Element) ob1;
439                 PropertyName pn = new PropertyName(elProp);
440                 PropertyResponse response = new PropertyResponse(
441                                                     resource.getURL()
442                                                             .toString());
443                 response.addProperty(pn, (Element) elProp.cloneNode(false),
444                                      (errorsOccurred
445                                       ? WebDAVStatus.SC_FAILED_DEPENDENCY
446                                       : WebDAVStatus.SC_OK));
447
448
449                 // todo: add code for responsedescription
450
multiStatus.addResponse(response);
451             }
452         }
453
454         // write out the properties
455
if (!errorsOccurred) {
456             resource.saveProperties(propertiesDocument);
457         }
458
459         return multiStatus;
460     }
461
462     /** Set a property of a resource to a value.
463     *
464     * @param name the property name
465     * @param value the property value
466     * @exception com.ibm.webdav.WebDAVException
467     */

468     public void setProperty(String JavaDoc name, Element value)
469                      throws WebDAVException {
470         // load the properties
471
Document propertiesDocument = resource.loadProperties();
472         Element properties = propertiesDocument.getDocumentElement();
473         String JavaDoc ns = value.getNamespaceURI();
474         
475         Element property = null;
476         if(ns == null) {
477             property = (Element) ((Element) properties).getElementsByTagName(
478                                                          value.getTagName()).item(0);
479         } else {
480             property = (Element)properties.getElementsByTagNameNS(ns, value.getLocalName()).item(0);
481         }
482         
483
484         if (property != null) {
485             try {
486                 properties.removeChild(property);
487             } catch (DOMException exc) {
488             }
489         }
490
491         properties.appendChild(propertiesDocument.importNode(value, true));
492
493
494         // write out the properties
495
resource.saveProperties(propertiesDocument);
496     }
497
498     /** Update the live properties that are unique to the
499     * repository implementation.
500     * @param document the XML document containing the properties
501     * @exception com.ibm.webdav.WebDAVException
502     */

503     public abstract void updateLiveProperties(Document document)
504                                        throws WebDAVException;
505 }
Popular Tags