1
2
3
4 package org.rcfaces.core.internal.version;
5
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.UnsupportedEncodingException;
9 import java.net.URL;
10 import java.net.URLConnection;
11 import java.security.MessageDigest;
12 import java.util.Arrays;
13
14 import javax.faces.FacesException;
15 import javax.faces.context.ExternalContext;
16 import javax.faces.context.FacesContext;
17 import javax.servlet.RequestDispatcher;
18 import javax.servlet.ServletContext;
19 import javax.servlet.ServletRequest;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.rcfaces.core.internal.Constants;
26 import org.rcfaces.core.internal.lang.ByteBufferOutputStream;
27 import org.rcfaces.core.internal.lang.StringAppender;
28 import org.rcfaces.core.internal.util.Base64;
29 import org.rcfaces.core.internal.util.IncludeHttpServletRequest;
30 import org.rcfaces.core.internal.util.IncludeHttpServletResponse;
31 import org.rcfaces.core.internal.util.MessageDigestSelector;
32
33
34
35
36
37
38 public class HashCodeTools {
39 private static final String REVISION = "$Revision: 1.6 $";
40
41 private static final Log LOG = LogFactory.getLog(HashCodeTools.class);
42
43 private static final String DEFAULT_CHARSET = "UTF-8";
44
45 private static final int INITIAL_BUFFER_SIZE = 8000;
46
47 public static final String computeURLFormat(FacesContext facesContext,
48 String url, Object content, int maxHashCodeSize) {
49
50 String hash = compute(facesContext, url, content, maxHashCodeSize);
51 if (hash == null) {
52 return null;
53 }
54
55 return hash.replace('+', '.').replace('/', ':');
56 }
57
58 public static final String compute(FacesContext facesContext, String url,
59 Object content, int maxHashCodeSize) {
60
61 byte buffer[] = null;
62 if (content instanceof URL) {
63 buffer = loadContentFromURL((URL) content);
64
65 } else if (content instanceof String) {
66 try {
67 buffer = ((String) content).getBytes("UTF-8");
68
69 } catch (UnsupportedEncodingException e) {
70 throw new FacesException(e);
71 }
72
73 } else if (content instanceof StringAppender) {
74 try {
75 buffer = ((StringAppender) content).getBytes("UTF-8");
76
77 } catch (UnsupportedEncodingException e) {
78 throw new FacesException(e);
79 }
80
81 } else if (content instanceof byte[]) {
82 buffer = (byte[]) content;
83
84 } else if (content instanceof InputStream) {
85 ByteBufferOutputStream bos = new ByteBufferOutputStream(
86 INITIAL_BUFFER_SIZE);
87
88 InputStream ins = (InputStream) content;
89
90 try {
91 byte buf[] = new byte[INITIAL_BUFFER_SIZE];
92 for (;;) {
93 int ret = ins.read(buf);
94 if (ret < 1) {
95 break;
96 }
97
98 bos.write(buf, 0, ret);
99 }
100
101 } catch (IOException ex) {
102 LOG.error("Can not read content of stream.", ex);
103 return null;
104 }
105
106 bos.close();
107
108 buffer = bos.toByteArray();
109
110 } else if (content == null) {
111 buffer = loadContentFromPath(facesContext, url);
112 }
113
114 if (buffer == null) {
115 LOG.error("Can not get content of buffer url='" + url
116 + "' content='" + content + "'.");
117 return null;
118 }
119
120 if (LOG.isDebugEnabled()) {
121 LOG
122 .debug("Compute HashCode of buffer (size="
123 + buffer.length
124 + ") using '"
125 + Arrays
126 .asList(Constants.RESOURCE_VERSION_DIGEST_ALGORITHMS)
127 + " algorithm (maxHashCodeSize=" + maxHashCodeSize
128 + ")");
129 }
130
131 MessageDigest messageDigest = MessageDigestSelector
132 .getInstance(Constants.RESOURCE_VERSION_DIGEST_ALGORITHMS);
133
134 byte digest[] = messageDigest.digest(buffer);
135
136 String etag = Base64.encodeBytes(digest, Base64.DONT_BREAK_LINES);
137
138 if (maxHashCodeSize == 0) {
139 maxHashCodeSize = Constants.VERSIONED_URI_HASHCODE_MAX_SIZE;
140 }
141 if (maxHashCodeSize > 0 && etag.length() > maxHashCodeSize) {
142 etag = etag.substring(0, maxHashCodeSize);
143 }
144
145 if (LOG.isDebugEnabled()) {
146 LOG.debug("Compute ETag from url '" + url + "' = '" + etag + "'.");
147 }
148
149 etag += ":" + buffer.length;
150
151 return etag;
152 }
153
154 private static byte[] loadContentFromURL(URL content) {
155 URLConnection connection;
156 try {
157 connection = content.openConnection();
158 } catch (IOException ex) {
159 LOG.error("Can not open connection of '" + content + "'.", ex);
160 return null;
161 }
162
163 int length = connection.getContentLength();
164 if (length < 1) {
165 length = 8000;
166 }
167
168 InputStream ins;
169 try {
170 ins = connection.getInputStream();
171
172 } catch (IOException ex) {
173 LOG.error("Can not get input stream of '" + content + "'.", ex);
174 return null;
175 }
176 try {
177 ByteBufferOutputStream out = new ByteBufferOutputStream(length);
178 byte buf[] = new byte[INITIAL_BUFFER_SIZE];
179 for (;;) {
180 int ret = ins.read(buf);
181 if (ret < 1) {
182 break;
183 }
184
185 out.write(buf, 0, ret);
186 }
187
188 byte b[] = out.toByteArray();
189
190 if (LOG.isDebugEnabled()) {
191 LOG.debug("Read content of url '" + content + "' (" + b.length
192 + " bytes).");
193 }
194
195 return b;
196
197 } catch (IOException ex) {
198 LOG.error("Can not get read content of '" + content + "'.", ex);
199 return null;
200
201 } finally {
202 try {
203 ins.close();
204 } catch (IOException e) {
205 LOG.error(e);
206 }
207 }
208 }
209
210 private static byte[] loadContentFromPath(FacesContext facesContext,
211 String url) {
212
213 ExternalContext externalContext = facesContext.getExternalContext();
214
215 ServletContext servletContext = (ServletContext) externalContext
216 .getContext();
217 HttpServletRequest servletRequest = (HttpServletRequest) externalContext
218 .getRequest();
219 HttpServletResponse servletResponse = (HttpServletResponse) externalContext
220 .getResponse();
221
222 if (LOG.isDebugEnabled()) {
223 LOG.debug("Compute ETag from url '" + url + "'.");
224 }
225
226 if (url.startsWith("/") == false) {
227 url = "/" + url;
228 }
229
230 RequestDispatcher requestDispatcher = servletContext
231 .getRequestDispatcher(url);
232 if (requestDispatcher == null) {
233 LOG.error("Can not find dispatcher for url '" + url + "'.");
234
235 return null;
236 }
237
238 ByteBufferOutputStream outputStream = new ByteBufferOutputStream(
239 INITIAL_BUFFER_SIZE);
240
241 ServletRequest request = new IncludeHttpServletRequest(servletRequest);
242 IncludeHttpServletResponse response = IncludeHttpServletResponse
243 .create(servletResponse, outputStream, DEFAULT_CHARSET);
244
245 try {
246 requestDispatcher.include(request, response);
247
248 } catch (Throwable e) {
249 LOG.error("Can not include url '" + url
250 + "' to compute ETag value.", e);
251
252 return null;
253 }
254
255 if (response.getStatus() != HttpServletResponse.SC_OK) {
256
257 if (LOG.isDebugEnabled()) {
258 LOG.debug("Invalid response status for url '" + url + "'.");
259 }
260
261 return null;
262 }
263
264 return outputStream.toByteArray();
265 }
266 }