View Javadoc

1   /*
2    * $Id: HashCodeTools.java,v 1.6 2010/08/10 14:02:30 oeuillot Exp $
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   * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
36   * @version $Revision: 1.6 $ $Date: 2010/08/10 14:02:30 $
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             // Erreur !
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 }