View Javadoc

1   /*
2    * Copyright 2008 Hippo
3    *
4    * Licensed under the Apache License, Version 2.0 (the  "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" 
12   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  package nl.hippo.client.webdav.caching;
17  
18  import java.io.IOException;
19  import java.io.StringReader;
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import nl.hippo.client.api.ClientException;
25  import nl.hippo.client.api.content.Property;
26  import nl.hippo.client.api.event.EventValidity;
27  import nl.hippo.client.api.event.EventValidityImpl;
28  import nl.hippo.client.webdav.WebdavRequest;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.xmlpull.v1.XmlPullParser;
32  import org.xmlpull.v1.XmlPullParserException;
33  import org.xmlpull.v1.XmlPullParserFactory;
34  
35  class EventValidityCalculator {
36  
37      private static final String SCOPE_ELEMENT_NAME = "scope";
38      private static final String HREF_ELEMENT_NAME = "href";
39  
40      private static EventValidityCalculator calculator;
41  
42      private static XmlPullParserFactory factory;
43      static {
44          try {
45              factory = XmlPullParserFactory.newInstance();
46              factory.setNamespaceAware(true);
47          } catch (XmlPullParserException e) {
48              throw new ExceptionInInitializerError("Error while creating xpp pull parser" + e.getMessage());
49          }
50      }
51  
52      static EventValidity[] calculate(WebdavRequest request) throws ClientException {
53          if (request == null) {
54              throw new IllegalArgumentException("request may not be null");
55          }
56          if (request.getPath() == null) {
57              return new EventValidity[0];
58          }
59          if (request.getRequestBody() == null) {
60              return new EventValidityImpl[] { new EventValidityImpl(request.getPath().getFullPath()) };
61          }
62          try {
63              // xmlpullparser is not thread safe: create new parser for each calculation
64              return new EventValidityCalculator(factory.newPullParser()).execute(request);
65          } catch (XmlPullParserException e) {
66              // failed to calculate validity, just return empty
67              return new EventValidity[0];
68          }
69      }
70  
71      private XmlPullParser xpp;
72  
73      private EventValidityCalculator(XmlPullParser xpp) {
74          this.xpp = xpp;
75      }
76  
77      private EventValidity[] execute(WebdavRequest request) throws ClientException {
78          List validities = new ArrayList();
79          try {
80              xpp.setInput(new StringReader(request.getRequestBody()));
81  
82              while (nextElement(SCOPE_ELEMENT_NAME, Property.DAV_NAMESPACE)) {
83                  if (nextElement(HREF_ELEMENT_NAME, Property.DAV_NAMESPACE)) {
84                      xpp.next();
85                      String scope = StringUtils.strip(getText());
86                      if (scope != null) {
87                          scope = StringUtils.stripEnd(scope, "/");
88                          if (scope.startsWith("/")) {
89                              validities.add(scope);
90                          } else {
91                              String validityPath = getValidityPath(request, scope);
92                              validities.add(validityPath);
93                          }
94                      }
95                  }
96                  xpp.nextToken();
97              }
98  
99              if (validities.size() == 0) {
100                 validities.add(request.getPath().getFullPath());
101             }
102             return toArray(validities);
103 
104         } catch (XmlPullParserException e) {
105             throw new ClientException("Error parsing document " + currentPositionString(), e);
106         } catch (IOException e) {
107             throw new ClientException("Error accessing document", e);
108         }
109     }
110 
111     private String getValidityPath(WebdavRequest request, String scope) {
112         String result = request.getPath().getFullPath();
113         if (StringUtils.isNotEmpty(scope)) {
114             result += "/" + scope;
115         }
116         return result;
117     }
118 
119     private boolean nextElement(String name, String namespace) throws XmlPullParserException, IOException {
120         int type = xpp.getEventType();
121         while (type != XmlPullParser.END_DOCUMENT) {
122             type = xpp.next();
123             if (type == XmlPullParser.START_TAG) {
124                 if (verifyName(name) && verifyNamespace(namespace)) {
125                     return true;
126                 }
127             }
128         }
129         return false;
130     }
131 
132     private String getText() throws XmlPullParserException, IOException {
133         int type = xpp.getEventType();
134         while (type != XmlPullParser.TEXT) {
135             if (type == XmlPullParser.START_TAG || type == XmlPullParser.END_DOCUMENT) {
136                 return null;
137             }
138             type = xpp.next();        
139         }
140         if (type == XmlPullParser.TEXT) {
141             return xpp.getText();
142         } else {
143             return null;
144         }
145     }
146 
147     private boolean verifyName(String name) {
148         return xpp.getName().equals(name);
149     }
150 
151     private boolean verifyNamespace(String ns) {
152         if (ns == null || "".equals(ns)) {
153             return xpp.getNamespace().length() == 0;
154         } else {
155             return ns.equals(xpp.getNamespace());
156         }
157     }
158 
159     private EventValidity[] toArray(List list) throws ClientException {
160         int i = 0;
161         EventValidity[] result = new EventValidity[list.size()];
162         Iterator it = list.iterator();
163         while (it.hasNext()) {
164             result[i++] = new EventValidityImpl((String) it.next());
165         }
166         return result;
167     }
168 
169     private String currentPositionString() {
170         StringBuffer buf = new StringBuffer();
171         buf.append("(line ").append(xpp.getLineNumber()).append(", col ").append(xpp.getColumnNumber()).append("): ");
172         if (xpp.getNamespace() == null || "".equals(xpp.getNamespace())) {
173             buf.append("\"").append(xpp.getName()).append("\"");
174         } else {
175             buf.append("\"{").append(xpp.getNamespace()).append("}").append(xpp.getName()).append("\"");
176         }
177         return buf.toString();
178     }
179 }