1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.resource;
20
21 import java.io.BufferedInputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.net.MalformedURLException;
30 import java.net.URL;
31 import java.util.Map;
32 import java.util.concurrent.ConcurrentHashMap;
33 import javax.faces.FacesException;
34 import javax.faces.application.Resource;
35 import javax.faces.context.FacesContext;
36 import org.apache.myfaces.application.ResourceHandlerImpl;
37 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
38 import org.apache.myfaces.shared.resource.ResourceLoader;
39 import org.apache.myfaces.shared.resource.ResourceLoaderWrapper;
40 import org.apache.myfaces.shared.resource.ResourceMeta;
41 import org.apache.myfaces.shared.util.WebConfigParamUtils;
42
43
44
45
46
47
48
49
50 public class TempDirFileCacheResourceLoader extends ResourceLoaderWrapper
51 {
52
53
54
55
56
57
58 @JSFWebConfigParam(since="2.1.11", expectedValues="true, false", defaultValue="false")
59 public final static String INIT_PARAM_TEMPORAL_RESOURCEHANDLER_CACHE_ENABLED =
60 "org.apache.myfaces.TEMPORAL_RESOURCEHANDLER_CACHE_ENABLED";
61 public final static boolean INIT_PARAM_TEMPORAL_RESOURCEHANDLER_CACHE_ENABLED_DEFAULT = false;
62
63 public final static String TEMP_FILES_LOCK_MAP = "oam.rh.TEMP_FILES_LOCK_MAP";
64
65
66
67
68 private static final String TEMP_FOLDER_BASE_DIR = "oam-rh-cache/";
69
70
71
72
73 private static final String TEMP_FILE_SUFFIX = ".tmp";
74
75 private ResourceLoader delegate;
76
77 private volatile File _tempDir;
78
79 private int _resourceBufferSize = -1;
80
81 public TempDirFileCacheResourceLoader(ResourceLoader delegate)
82 {
83 this.delegate = delegate;
84 initialize();
85 }
86
87 public static boolean isValidCreateTemporalFiles(FacesContext facesContext)
88 {
89 if (WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(),
90 INIT_PARAM_TEMPORAL_RESOURCEHANDLER_CACHE_ENABLED,
91 INIT_PARAM_TEMPORAL_RESOURCEHANDLER_CACHE_ENABLED_DEFAULT))
92 {
93
94 try
95 {
96 Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
97 File tempdir = (File) applicationMap.get("javax.servlet.context.tempdir");
98 File imagesDir = new File(tempdir, TEMP_FOLDER_BASE_DIR);
99 if (!imagesDir.exists())
100 {
101 imagesDir.mkdirs();
102 }
103 return true;
104 }
105 catch (Exception e)
106 {
107 return false;
108 }
109 }
110 else
111 {
112 return false;
113 }
114 }
115
116 protected void initialize()
117 {
118
119 FacesContext facesContext = FacesContext.getCurrentInstance();
120
121
122 Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
123 File tempdir = (File) applicationMap.get("javax.servlet.context.tempdir");
124 File imagesDir = new File(tempdir, TEMP_FOLDER_BASE_DIR);
125 if (!imagesDir.exists())
126 {
127 imagesDir.mkdirs();
128 }
129 else
130 {
131
132 deleteDir(imagesDir);
133 imagesDir.mkdirs();
134 }
135 _tempDir = imagesDir;
136
137
138 Map<String, FileProducer> temporalFilesLockMap = new ConcurrentHashMap<String, FileProducer>();
139 facesContext.getExternalContext().getApplicationMap().put(TEMP_FILES_LOCK_MAP, temporalFilesLockMap);
140 }
141
142 private static boolean deleteDir(File dir)
143 {
144 if (dir.isDirectory())
145 {
146 String[] children = dir.list();
147 for (int i = 0; i < children.length; i++)
148 {
149 boolean success = deleteDir(new File(dir, children[i]));
150 if (!success)
151 {
152 return false;
153 }
154 }
155 }
156 return dir.delete();
157 }
158
159 @Override
160 public URL getResourceURL(ResourceMeta resourceMeta)
161 {
162 FacesContext facesContext = FacesContext.getCurrentInstance();
163
164 if (resourceExists(resourceMeta))
165 {
166 File file = createOrGetTempFile(facesContext, resourceMeta);
167
168 try
169 {
170 return file.toURL();
171 }
172 catch (MalformedURLException e)
173 {
174 throw new FacesException(e);
175 }
176 }
177 else
178 {
179 return null;
180 }
181 }
182
183 public InputStream getResourceInputStream(ResourceMeta resourceMeta, Resource resource)
184 {
185 FacesContext facesContext = FacesContext.getCurrentInstance();
186
187 if (resourceExists(resourceMeta))
188 {
189 File file = createOrGetTempFile(facesContext, resourceMeta);
190
191 try
192 {
193 return new BufferedInputStream(new FileInputStream(file));
194 }
195 catch (FileNotFoundException e)
196 {
197 throw new FacesException(e);
198 }
199 }
200 else
201 {
202 return null;
203 }
204 }
205
206 @Override
207 public InputStream getResourceInputStream(ResourceMeta resourceMeta)
208 {
209 return getResourceInputStream(resourceMeta, null);
210 }
211
212 @Override
213 public boolean resourceExists(ResourceMeta resourceMeta)
214 {
215 return super.resourceExists(resourceMeta);
216 }
217
218 @SuppressWarnings("unchecked")
219 private File createOrGetTempFile(FacesContext facesContext, ResourceMeta resourceMeta)
220 {
221 String identifier = resourceMeta.getResourceIdentifier();
222 File file = getTemporalFile(resourceMeta);
223 if (!file.exists())
224 {
225 Map<String, FileProducer> map = (Map<String, FileProducer>)
226 facesContext.getExternalContext().getApplicationMap().get(TEMP_FILES_LOCK_MAP);
227
228 FileProducer creator = map.get(identifier);
229
230 if (creator == null)
231 {
232 synchronized(this)
233 {
234 creator = map.get(identifier);
235
236 if (creator == null)
237 {
238 creator = new FileProducer();
239 map.put(identifier, creator);
240 }
241 }
242 }
243
244 if (!creator.isCreated())
245 {
246 creator.createFile(facesContext, resourceMeta, file, this);
247 }
248 }
249 return file;
250 }
251
252 private File getTemporalFile(ResourceMeta resourceMeta)
253 {
254 return new File(_tempDir, resourceMeta.getResourceIdentifier() + TEMP_FILE_SUFFIX);
255 }
256
257
258
259
260
261
262
263 protected void createTemporalFileVersion(FacesContext facesContext, ResourceMeta resourceMeta, File target)
264 {
265 target.mkdirs();
266 target.delete();
267
268 InputStream inputStream = null;
269 FileOutputStream fileOutputStream;
270 try
271 {
272
273
274
275
276
277
278
279
280
281
282 inputStream = getWrapped().getResourceInputStream(resourceMeta);
283
284 fileOutputStream = new FileOutputStream(target);
285 byte[] buffer = new byte[this.getResourceBufferSize()];
286
287 pipeBytes(inputStream, fileOutputStream, buffer);
288 }
289 catch (FileNotFoundException e)
290 {
291 throw new FacesException("Unexpected exception while create file:", e);
292 }
293 catch (IOException e)
294 {
295 throw new FacesException("Unexpected exception while create file:", e);
296 }
297 finally
298 {
299 if (inputStream != null)
300 {
301 try
302 {
303 inputStream.close();
304 }
305 catch (IOException e)
306 {
307
308 }
309 }
310 }
311 }
312
313
314
315
316
317 private static void pipeBytes(InputStream in, OutputStream out, byte[] buffer) throws IOException
318 {
319 int length;
320
321 while ((length = (in.read(buffer))) >= 0)
322 {
323 out.write(buffer, 0, length);
324 }
325 }
326
327 public static class FileProducer
328 {
329
330 public volatile boolean created = false;
331
332 public FileProducer()
333 {
334 super();
335 }
336
337 public boolean isCreated()
338 {
339 return created;
340 }
341
342 public synchronized void createFile(FacesContext facesContext,
343 ResourceMeta resourceMeta, File file, TempDirFileCacheResourceLoader loader)
344 {
345 if (!created)
346 {
347 loader.createTemporalFileVersion(facesContext, resourceMeta, file);
348 created = true;
349 }
350 }
351 }
352
353 protected int getResourceBufferSize()
354 {
355 if (_resourceBufferSize == -1)
356 {
357 _resourceBufferSize = WebConfigParamUtils.getIntegerInitParameter(
358 FacesContext.getCurrentInstance().getExternalContext(),
359 ResourceHandlerImpl.INIT_PARAM_RESOURCE_BUFFER_SIZE,
360 ResourceHandlerImpl.INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT);
361 }
362 return _resourceBufferSize;
363 }
364
365 public ResourceLoader getWrapped()
366 {
367 return delegate;
368 }
369 }