Skip to content

Instantly share code, notes, and snippets.

@eungju
Created November 16, 2012 09:15
Show Gist options
  • Select an option

  • Save eungju/4085759 to your computer and use it in GitHub Desktop.

Select an option

Save eungju/4085759 to your computer and use it in GitHub Desktop.
Servlet Assets Helper
<@resources.stylesheet "default.css" />
<@resources.javascript "jquery.min.js" />
<#macro stylesheet path>
<link rel="stylesheet" href="${StaticResources.uri("/resources/" + path)}" type="text/css" />
</#macro>
<#macro javascript path>
<script src="${StaticResources.uri("/resources/" + path)}" type="text/javascript"></script>
</#macro>
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.io.Resources;
public class StaticResources {
private HashFunction signatureFunction = Hashing.md5();
private ServletContext context;
private LoadingCache<String, String> signatures;
public StaticResources(ServletContext context, boolean alwaysFresh) {
Preconditions.checkNotNull(context, "The servlet context is required");
this.context = context;
CacheLoader<String, String> signatureCacheLoader = new CacheLoader<String, String>() {
public String load(String key) {
return signature(key);
}
};
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
if (alwaysFresh) {
builder.expireAfterWrite(0, TimeUnit.SECONDS);
}
this.signatures = builder.build(signatureCacheLoader);
}
public String signature(String path) {
try {
return signatureFunction.hashBytes(Resources.toByteArray(context.getResource(path))).toString();
} catch (IOException e) {
throw new RuntimeException("Unable to read the resource", e);
}
}
/**
* The path must begin with a "/" and is interpreted as relative to the current context root.
*/
public String uri(String path) {
Preconditions.checkArgument(path.startsWith("/"), "The path must begin with a \"/\".");
StringBuilder result = new StringBuilder(context.getContextPath());
result.append(path).append("?_s=").append(signatures.getUnchecked(path));
return result.toString();
}
}
import javax.servlet.ServletContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;
public class StaticResourcesInitializer implements ServletContextAware, InitializingBean {
private ServletContext context;
private boolean alwaysFresh = false;
public void setServletContext(ServletContext context) {
this.context = context;
}
public void setAlwaysFresh(boolean alwaysFresh) {
this.alwaysFresh = alwaysFresh;
}
@Override
public void afterPropertiesSet() throws Exception {
context.setAttribute("StaticResources", new StaticResources(context, alwaysFresh));
}
}
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import javax.servlet.ServletContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.google.common.io.Resources;
@RunWith(MockitoJUnitRunner.class)
public class StaticResourcesTest {
private StaticResources dut;
private @Mock ServletContext context;
private String path = "/resources/jquery-1.6.1.min.js";
private String sig = "9573f9134986b52cff0401ac3218d075";
@Before public void beforeEach() throws Exception {
dut = new StaticResources(context, true);
when(context.getResource(path)).thenReturn(Resources.getResource("webapps" + path));
}
@Test public void signature() {
assertEquals(sig, dut.signature(path));
}
@Test public void uri_with_root_context_path() {
when(context.getContextPath()).thenReturn("");
assertEquals(path + "?_s=" + sig, dut.uri(path));
}
@Test(expected=IllegalArgumentException.class) public void uri_throws_exception_when_the_path_does_not_start_with_slash() {
when(context.getContextPath()).thenReturn("");
assertEquals(path + "?_s=" + sig, dut.uri("resources/x.js"));
}
@Test public void uri_with_none_root_context_path() {
when(context.getContextPath()).thenReturn("/login");
assertEquals("/login" + path + "?_s=" + sig, dut.uri(path));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment