View Javadoc

1   /*
2    * Copyright 2007 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;
17  
18  import java.io.ByteArrayInputStream;
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.UnsupportedEncodingException;
23  import java.util.Map;
24  
25  import javax.xml.transform.stream.StreamResult;
26  import javax.xml.transform.stream.StreamSource;
27  
28  import nl.hippo.client.api.ClientException;
29  import nl.hippo.client.api.content.RawResponse;
30  import nl.hippo.client.api.service.NOPCachingService;
31  import nl.hippo.client.webdav.caching.WebdavCacheHandler;
32  import nl.hippo.client.webdav.utils.Converters;
33  import nl.hippo.client.webdav.utils.Interpolation;
34  import nl.hippo.client.webdav.utils.XslTransformer;
35  
36  import org.apache.commons.lang.builder.EqualsBuilder;
37  import org.apache.commons.lang.builder.HashCodeBuilder;
38  import org.xml.sax.helpers.DefaultHandler;
39  
40  /**
41   * Result class returned by the execute() method of WebdavMethod.
42   * <p>
43   * Implemented as a Value Object meaning:
44   * <ul>
45   * <li> The identity of an instance is solely based on it's property values:
46   * instances with equal values are interchangable. </li>
47   * <li> Instances are threadsafe over multiple threads running concurrently, and
48   * may be used multiple times in a given session. </li>
49   * </ul>
50   */
51  public class WebdavResponse implements RawResponse {
52  
53      private static final long serialVersionUID = 1L;
54  
55      /**
56       * The response is stored as a byte[] and not as a Stream.
57       * 
58       * Partly because the original response stream returned by HttpClient is an
59       * AutoCloseInputStream which does what the name imlies and can only be read
60       * once. (see comment in Search.PatchedSearchMethod)
61       * 
62       * Partly because byte arrays are probably easier to cache than streams.
63       * 
64       * TODO: Think about a streaming WebdavResponse implementation for large
65       * binary content (movies etc). This probably either means exposing the
66       * commons-httpclient internal AutoCloseInputStream class or something with
67       * PipedInput- and -OutputStreams.
68       */
69      private byte[] responseAsBytes;
70  
71      /**
72       * The Http response code (207, 404, etc.)
73       */
74      private int responseCode;
75  
76      private WebdavRequest request;
77  
78      public WebdavResponse() {
79          // Nothing to do
80      }
81  
82      public WebdavResponse(int responseCode) {
83          this.responseCode = responseCode;
84      }
85  
86      public WebdavResponse(byte[] responseAsBytes) {
87          this.responseCode = 200;
88          this.responseAsBytes = responseAsBytes;
89      }
90  
91      public WebdavResponse(int responseCode, byte[] responseAsBytes, WebdavRequest request) {
92          this.responseCode = responseCode;
93          this.responseAsBytes = responseAsBytes;
94          this.request = request;
95      }
96  
97      public boolean isValid() {
98          return responseCode >= 200 && responseCode <= 299;
99      }
100     
101     public boolean isDocumentNotFound() {
102         return responseCode == 404;
103     }
104 
105     /**
106      * Returns the Http response code (207, 404, etc.)
107      * 
108      * @return The Http response code (207, 404, etc.)
109      */
110     public int getResponseCode() {
111         return responseCode;
112     }
113 
114     public WebdavRequest getRequest() {
115         return request;
116     }
117 
118     public byte[] getResponseAsBytes() {
119         return responseAsBytes;
120     }
121 
122     public InputStream getResponseAsStream() {
123         return Converters.bytes2Stream(responseAsBytes);
124     }
125 
126     public String getResponseAsString(String encoding) throws ClientException {
127         try {
128             return Converters.bytes2String(responseAsBytes, encoding);
129         } catch (UnsupportedEncodingException e) {
130             throw new ClientException("Unsupported encoding.", e);
131         }
132     }
133 
134     public String getResponseAsPrettyPrintedString(String encoding) throws ClientException {
135         try {
136             return Converters.bytes2PrettyPrintedString(responseAsBytes, encoding);
137         } catch (IOException e) {
138             throw new ClientException("Exception while prettyprinting response.", e);
139         }
140     }
141 
142     public org.w3c.dom.Document getResponseAsDom() throws ClientException {
143         return Converters.bytes2Dom(responseAsBytes);
144     }
145 
146     public void streamResponseToSaxContentHandler(DefaultHandler handler) throws ClientException {
147         Converters.bytes2SaxContentHandler(responseAsBytes, handler);
148     }
149     
150     public WebdavResponse transform(WebdavResponse xsl) throws ClientException {
151         return transform(xsl, new WebdavCacheHandler(new NOPCachingService()));
152     }
153 
154     public WebdavResponse transform(WebdavResponse xsl, WebdavCacheHandler cache) throws ClientException {
155         if (responseAsBytes == null) {
156             WebdavLogger.log.warn("Cannot transform empty response");
157             return this;
158         }
159         WebdavResponse transformedResponse = null;
160         if (request != null) {
161             transformedResponse = cache.getWebdavResponse(request.transformedVariant());
162         }
163         if (transformedResponse == null) {
164             if (WebdavLogger.log.isDebugEnabled()) {
165                 WebdavLogger.log.debug("Xsl transform");
166             }
167             StreamSource source = new StreamSource(new ByteArrayInputStream(responseAsBytes));
168             StreamResult target = new StreamResult(new ByteArrayOutputStream());
169             XslTransformer.transform(xsl, source, target);
170 
171             byte[] transformedContent = ((ByteArrayOutputStream) target.getOutputStream()).toByteArray();
172 
173             if (request != null) {
174                 WebdavRequest transformedRequest = request.transformedVariant();
175                 transformedResponse = new WebdavResponse(responseCode, transformedContent, transformedRequest);
176                 cache.store(transformedResponse);
177             } else {
178                 transformedResponse = new WebdavResponse(transformedContent);
179             }
180         }
181         return transformedResponse;
182     }
183 
184     public WebdavResponse interpolate(Map params) {
185         WebdavResponse result;
186         try {
187             String content = getResponseAsString("UTF-8");
188             String interpolatedContent = Interpolation.interpolate(content, params);
189             result = new WebdavResponse(responseCode, interpolatedContent.getBytes(), request);
190         } catch (ClientException e) {
191             result = this;
192         }
193         return result;
194     }
195 
196     public String toString() {
197         String result;
198         try {
199             result = getResponseAsString("UTF-8");
200         } catch (ClientException e) {
201             result = "Exception while converting response to String";
202         }
203         return result;
204     }
205 
206     public boolean equals(Object obj) {
207         boolean eq;
208         if (obj == null) {
209             eq = false;
210         } else if (!(obj instanceof WebdavResponse)) {
211             eq = false;
212         } else if (this == obj) {
213             eq = true;
214         } else {
215             WebdavResponse rhs = (WebdavResponse) obj;
216             eq = new EqualsBuilder().append(getResponseCode(), rhs.getResponseCode()).append(getResponseAsBytes(),
217                     rhs.getResponseAsBytes()).isEquals();
218         }
219         return eq;
220     }
221 
222     public int hashCode() {
223         int hash = new HashCodeBuilder(37, 93).append(getResponseCode()).append(getResponseAsBytes()).toHashCode();
224         return hash;
225     }
226 
227 }