1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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 }