ResourceConverterCacheImpl extends GenericCacheImpl<ResourceConverterCacheImpl.CacheEntry> implements Serializable, IResourceConverterCache { @Override public IResource convert(String key, IResource source) throws IOException { final String sourceMethod = "getInputStream"; final boolean isTraceLogging = log.isLoggable(Level.FINER); if (isTraceLogging) { log.entering(sourceClass, sourceMethod, new Object[] { key, source }); } IResource result = null; String filename = null; File cacheFile = null; URI referenceUri = null; CacheEntry tryCacheEntry = (CacheEntry) get(key); File cacheDir = aggregator.getCacheManager().getCacheDir(); if (tryCacheEntry != null) { referenceUri = tryCacheEntry.referenceUri; filename = tryCacheEntry.filename; if (filename != null && referenceUri != null) { cacheFile = new File(cacheDir, filename); if (source != null && Math.abs(source.lastModified() - cacheFile.lastModified()) >= 1000) { cacheMap.remove(key, tryCacheEntry); aggregator.getCacheManager().deleteFileDelayed(cacheFile.getName()); } else { result = fileResourceFactory.newResource(cacheFile.toURI()); result.setReferenceURI(referenceUri); log.exiting(sourceClass, sourceMethod, result); return result; } } } CacheEntry newCacheEntry = new CacheEntry(); CacheEntry oldCacheEntry = (CacheEntry) cacheMap.putIfAbsent(key, newCacheEntry); final CacheEntry cacheEntry = oldCacheEntry != null ? oldCacheEntry : newCacheEntry; synchronized (cacheEntry) { if (cacheEntry.ex != null) { throw cacheEntry.ex; } if (cacheEntry.filename != null) { cacheFile = new File(cacheDir, cacheEntry.filename); referenceUri = cacheEntry.referenceUri; } else if (source != null) { try { String path = source.getPath(); int idx = path.lastIndexOf("/"); String fname = (idx != -1) ? path.substring(idx + 1) : path; cacheFile = File.createTempFile(prefix, "." + fname + suffix, cacheDir); converter.generateCacheContent(source, cacheFile); cacheFile.setLastModified(source.lastModified()); cacheEntry.filename = cacheFile.getName(); referenceUri = cacheEntry.referenceUri = source.getReferenceURI(); } catch (Throwable t) { cacheEntry.ex = (t instanceof IOException) ? (IOException) t : new IOException(t); cacheMap.remove(key, cacheEntry); if (cacheFile != null) { aggregator.getCacheManager().deleteFileDelayed(cacheFile.getName()); } throw cacheEntry.ex; } } } if (cacheFile != null) { result = fileResourceFactory.newResource(cacheFile.toURI()); result.setReferenceURI(referenceUri); } if (isTraceLogging) { log.exiting(sourceClass, sourceClass, result); } return result; } ResourceConverterCacheImpl(IConverter converter, String prefix, String suffix); IConverter getConverter(); String getPrefix(); String getSuffix(); @Override IResource convert(String key, IResource source); @Override void setAggregator(IAggregator aggregator); @Override IGenericCache newInstance();  }
@Test public void testConvert() throws Throwable { final Mutable<CountDownLatch> mutableLatch = new MutableObject<CountDownLatch>(); @SuppressWarnings("serial") IConverter testConverter = new IConverter() { @Override public void generateCacheContent(IResource source, File cacheFile) throws IOException { InputStream in = source.getInputStream(); CountDownLatch latch = mutableLatch.getValue(); if (latch != null) { try { latch.await(); } catch (InterruptedException e) { throw new IOException(e); } } String content; try { content = IOUtils.toString(in); } finally { IOUtils.closeQuietly(in);; } FileUtils.write(cacheFile, content.toUpperCase()); } }; final ResourceConverterCacheImpl impl = new ResourceConverterCacheImpl(testConverter, "foo", "bar"); assertSame(testConverter, impl.getConverter()); assertSame("foo", impl.getPrefix()); assertSame("bar", impl.getSuffix()); final Mutable<String> deleteFileName = new MutableObject<String>(); IAggregatorExtension mockExt = createMock(IAggregatorExtension.class); IAggregator mockAggregator = createMock(IAggregator.class); ICacheManager mockCacheMgr = createMock(ICacheManager.class); expect(mockExt.getInstance()).andReturn(new FileResourceFactory()).anyTimes(); expect(mockExt.getAttribute("scheme")).andReturn("file").anyTimes(); expect(mockAggregator.getCacheManager()).andReturn(mockCacheMgr).anyTimes(); expect(mockAggregator.getExtensions(IResourceFactoryExtensionPoint.ID)).andReturn(Arrays.asList(new IAggregatorExtension[]{mockExt})); expect(mockCacheMgr.getCacheDir()).andReturn(cacheDir).anyTimes(); mockCacheMgr.deleteFileDelayed(isA(String.class)); expectLastCall().andAnswer(new IAnswer<Void>() { @Override public Void answer() throws Throwable { deleteFileName.setValue((String)getCurrentArguments()[0]); return null; } }).anyTimes(); replay(mockAggregator, mockCacheMgr, mockExt); impl.setAggregator(mockAggregator); long lastmod = new Date().getTime() - 10000; IResource source = new StringResource("Hello world", new URI("/test/resource.txt"), lastmod); IResource result = impl.convert("testResource", source); assertEquals("HELLO WORLD", FileUtils.readFileToString(new File(result.getURI()))); File cacheFile = new File(result.getURI()); assertTrue(Math.abs(lastmod - cacheFile.lastModified()) < 1000); assertNull(deleteFileName.getValue()); assertEquals(new URI("/test/resource.txt"), result.getReferenceURI()); URI uri = result.getURI(); result = impl.convert("testResource", source); assertEquals(uri, result.getURI()); assertTrue(Math.abs(lastmod - cacheFile.lastModified()) < 1000); assertNull(deleteFileName.getValue()); source = new StringResource("Hello world 2", new URI("/test/resource.txt"), lastmod); result = impl.convert("testResource", source); assertEquals(uri, result.getURI()); assertEquals("HELLO WORLD", FileUtils.readFileToString(new File(result.getURI()))); assertTrue(Math.abs(lastmod - cacheFile.lastModified()) < 1000); assertNull(deleteFileName.getValue()); lastmod += 10000; source = new StringResource("Hello world 2", new URI("/test/resource.txt"), lastmod); result = impl.convert("testResource", source); assertFalse(uri.equals(result.getURI())); assertEquals("HELLO WORLD 2", FileUtils.readFileToString(new File(result.getURI()))); assertEquals(deleteFileName.getValue(), cacheFile.getName()); cacheFile = new File(result.getURI()); assertTrue(Math.abs(lastmod - cacheFile.lastModified()) < 1000); source = new NotFoundResource(new URI("/test/noexist.txt")); boolean exceptionThrown = false; try { result = impl.convert("notFound", source); } catch (NotFoundException ex) { exceptionThrown = true; } assertTrue(exceptionThrown); assertNull(impl.get("notFound")); URI latchedUri = new URI("/test/latched.txt"); final IResource latchedSource = new StringResource("Latched", latchedUri, new Date().getTime()); final Mutable<IResource> result1 = new MutableObject<IResource>(); final Mutable<IResource> result2 = new MutableObject<IResource>(); final Mutable<Throwable> exception = new MutableObject<Throwable>(); mutableLatch.setValue(new CountDownLatch(1)); final CountDownLatch finished = new CountDownLatch(2); new Thread() { @Override public void run() { try { result1.setValue(impl.convert("latched", latchedSource)); } catch (Throwable t) { exception.setValue(t); } finished.countDown(); } }.start(); Thread.sleep(250); new Thread() { @Override public void run() { try { result2.setValue(impl.convert("latched", latchedSource)); } catch (Throwable t) { exception.setValue(t); } finished.countDown(); } }.start(); Thread.sleep(250); assertNull(result1.getValue()); assertNull(result2.getValue()); mutableLatch.getValue().countDown(); finished.await(); if (exception.getValue() != null) throw exception.getValue(); assertEquals(result1.getValue().getURI(), result2.getValue().getURI()); cacheFile = new File(result1.getValue().getURI()); assertEquals("LATCHED", FileUtils.readFileToString(cacheFile)); }