View Javadoc

1   /*
2    * $Id: ContentAdapterFactory.java,v 1.3.4.1 2010/12/10 10:31:13 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.content;
5   
6   import java.io.ByteArrayInputStream;
7   import java.io.File;
8   import java.io.FileInputStream;
9   import java.io.FileNotFoundException;
10  import java.io.IOException;
11  import java.io.InputStream;
12  import java.io.Serializable;
13  import java.net.FileNameMap;
14  import java.net.URLConnection;
15  import java.security.MessageDigest;
16  import java.util.HashMap;
17  import java.util.Map;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  import org.rcfaces.core.internal.Constants;
22  import org.rcfaces.core.internal.contentStorage.AbstractResolvedContent;
23  import org.rcfaces.core.internal.contentStorage.IResolvedContent;
24  import org.rcfaces.core.internal.lang.StringAppender;
25  import org.rcfaces.core.internal.util.Base64;
26  import org.rcfaces.core.internal.util.MessageDigestSelector;
27  import org.rcfaces.core.lang.IAdapterFactory;
28  
29  /**
30   * 
31   * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
32   * @version $Revision: 1.3.4.1 $ $Date: 2010/12/10 10:31:13 $
33   */
34  public class ContentAdapterFactory implements IAdapterFactory {
35      private static final String REVISION = "$Revision: 1.3.4.1 $";
36  
37      private static final Log LOG = LogFactory
38              .getLog(ContentAdapterFactory.class);
39  
40      private static final String TEMP_PREFIX = "contentAdapter_";
41  
42      protected static final Map suffixByMimeType = new HashMap(8);
43  
44      protected static final FileNameMap fileNameMap = URLConnection
45              .getFileNameMap();
46  
47      private static final long startTimeMillis = System.currentTimeMillis();
48  
49      private final Object tempFileCounterLock = new Object();
50  
51      private long tempFileCounter;
52  
53      public Object getAdapter(Object adaptableObject, Class adapterType,
54              Object parameter) {
55  
56          return null;
57      }
58  
59      public static String getSuffixByMimeType(String contentType) {
60          return (String) suffixByMimeType.get(contentType.toLowerCase());
61      }
62  
63      public Class[] getAdapterList() {
64          return new Class[] { IResolvedContent.class };
65      }
66  
67      public File createTempFile(String contentType, String suffix)
68              throws IOException {
69          File file = null;
70  
71          File tempFolder = getTempFolder();
72          if (tempFolder != null) {
73  
74              for (;;) {
75                  long id;
76                  synchronized (tempFileCounterLock) {
77                      id = tempFileCounter++;
78                  }
79  
80                  file = new File(tempFolder, getTempPrefix() + startTimeMillis
81                          + "_" + id + "." + suffix);
82  
83                  if (file.createNewFile()) {
84                      break;
85                  }
86              }
87          }
88  
89          if (file == null) {
90              file = File.createTempFile(getTempPrefix(), "." + suffix);
91          }
92  
93          file.deleteOnExit();
94  
95          return file;
96      }
97  
98      protected String getTempPrefix() {
99          return TEMP_PREFIX;
100     }
101 
102     protected File getTempFolder() {
103         return null;
104     }
105 
106     /**
107      * 
108      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
109      * @version $Revision: 1.3.4.1 $ $Date: 2010/12/10 10:31:13 $
110      */
111     protected class FileResolvedContent extends AbstractResolvedContent
112             implements Serializable {
113         private static final String REVISION = "$Revision: 1.3.4.1 $";
114 
115         private static final long serialVersionUID = 2045867975901327708L;
116 
117         private final String contentType;
118 
119         private final String suffix;
120 
121         private final int length;
122 
123         private final long lastModificationDate;
124 
125         private final String specifiedResourceKey;
126 
127         private String etag;
128 
129         private String hashCode;
130 
131         private byte fileSerialized[];
132 
133         private transient File file;
134 
135         public FileResolvedContent(String contentType, String suffix,
136                 File file, String specifiedResourceKey, long lastModifiedDate) {
137             this.file = file;
138             this.contentType = contentType;
139             this.suffix = suffix;
140             this.specifiedResourceKey = specifiedResourceKey;
141 
142             this.length = (int) file.length();
143             this.lastModificationDate = lastModifiedDate;
144 
145             if (Constants.ETAG_SUPPORT || Constants.HASH_SUPPORT) {
146                 computeHashCodes();
147             }
148         }
149 
150         public String getContentType() {
151             return contentType;
152         }
153 
154         public String getURLSuffix() {
155             return suffix;
156         }
157 
158         public String getResourceKey() {
159             if (specifiedResourceKey == null) {
160                 return specifiedResourceKey;
161             }
162 
163             return super.getResourceKey();
164         }
165 
166         public InputStream getInputStream() throws IOException {
167             if (fileSerialized != null) {
168                 return new ByteArrayInputStream(fileSerialized);
169             }
170 
171             return new FileInputStream(file);
172         }
173 
174         public long getModificationDate() {
175             return lastModificationDate;
176         }
177 
178         public int getLength() {
179             return length;
180         }
181 
182         public String getETag() {
183             return etag;
184         }
185 
186         public String getHash() {
187             return hashCode;
188         }
189 
190         protected void finalize() throws Throwable {
191             if (file != null) {
192                 try {
193                     file.delete();
194                     file = null;
195 
196                 } catch (Throwable ex) {
197                     LOG.error("Can not delete file '" + file + "'.", ex);
198                 }
199             }
200             super.finalize();
201         }
202 
203         protected void computeHashCodes() {
204             MessageDigest etagMessageDigest = null;
205             MessageDigest hashMessageDigest = null;
206 
207             if (Constants.ETAG_SUPPORT) {
208                 etagMessageDigest = MessageDigestSelector
209                         .getInstance(Constants.ETAG_DIGEST_ALGORITHMS);
210             }
211 
212             if (Constants.HASH_SUPPORT) {
213                 hashMessageDigest = MessageDigestSelector
214                         .getInstance(Constants.HASH_DIGEST_ALGORITHMS);
215             }
216 
217             if (hashMessageDigest == null && etagMessageDigest == null) {
218                 return;
219             }
220 
221             FileInputStream fileInputStream;
222             try {
223                 fileInputStream = new FileInputStream(file);
224 
225             } catch (FileNotFoundException e) {
226                 LOG.error("Can not compute Etag and Hashcode for file '" + file
227                         + "'." + e);
228                 return;
229             }
230 
231             try {
232                 byte buffer[] = new byte[4096];
233 
234                 for (;;) {
235                     int ret = fileInputStream.read(buffer);
236                     if (ret < 1) {
237                         break;
238                     }
239 
240                     if (etagMessageDigest != null) {
241                         etagMessageDigest.update(buffer, 0, ret);
242                     }
243 
244                     if (hashMessageDigest != null) {
245                         hashMessageDigest.update(buffer, 0, ret);
246                     }
247                 }
248 
249                 if (etagMessageDigest != null) {
250                     byte etagDigest[] = etagMessageDigest.digest();
251 
252                     StringAppender sb = new StringAppender(
253                             etagDigest.length * 2 + 16);
254                     sb.append("\"rcfaces:");
255                     for (int i = 0; i < etagDigest.length; i++) {
256                         int v = etagDigest[i] & 0xff;
257                         if (v < 16) {
258                             sb.append('0');
259                         }
260                         sb.append(Integer.toHexString(v));
261                     }
262 
263                     sb.append(':');
264                     sb.append(Integer.toHexString(length));
265 
266                     sb.append('\"');
267                     etag = sb.toString();
268 
269                     if (LOG.isDebugEnabled()) {
270                         LOG.debug("Etag for file '" + file + "' = " + etag);
271                     }
272                 }
273 
274                 if (hashMessageDigest != null) {
275                     byte hashDigest[] = hashMessageDigest.digest();
276 
277                     hashCode = Base64.encodeBytes(hashDigest,
278                             Base64.DONT_BREAK_LINES);
279 
280                     if (LOG.isDebugEnabled()) {
281                         LOG.debug("Hashcode for file '" + file + "' = "
282                                 + hashCode);
283                     }
284                 }
285 
286             } catch (IOException e) {
287                 LOG.error("Can not compute Etag and Hashcode for file '" + file
288                         + "'.", e);
289 
290             } finally {
291                 try {
292                     fileInputStream.close();
293 
294                 } catch (IOException e) {
295                     LOG.error(e);
296                 }
297             }
298         }
299 
300         private void writeObject(java.io.ObjectOutputStream s)
301                 throws java.io.IOException {
302 
303             if (file != null) {
304                 fileSerialized = new byte[length];
305 
306                 FileInputStream fin = new FileInputStream(file);
307                 try {
308                     fin.read(fileSerialized);
309 
310                 } catch (IOException ex) {
311                     LOG.error(ex);
312 
313                 } finally {
314                     try {
315                         fin.close();
316 
317                     } catch (IOException ex) {
318                         LOG.error(ex);
319                     }
320                 }
321 
322                 file = null;
323             }
324 
325             s.defaultWriteObject();
326         }
327     }
328 }