Author: phuong_vu
Date: 2010-11-28 23:30:49 -0500 (Sun, 28 Nov 2010)
New Revision: 5327
Modified:
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/CachedStylesheet.java
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/SkinService.java
exo/portal/branches/3.1.x/component/web/src/main/java/org/exoplatform/web/application/javascript/JavascriptConfigService.java
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/Image.java
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/ResourceRequestFilter.java
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/webui/javascript/JavascriptServlet.java
Log:
EXOGTN-176 CSS Ressources are not cached properly
Modified:
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/CachedStylesheet.java
===================================================================
---
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/CachedStylesheet.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/CachedStylesheet.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -24,6 +24,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Date;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
@@ -40,6 +41,8 @@
/** . */
private final byte[] bytes;
+
+ private long lastModified;
public CachedStylesheet(String text)
{
@@ -59,11 +62,18 @@
//
this.text = text;
this.bytes = bytes;
+// Remove miliseconds because string of date retrieve from Http header doesn't have
miliseconds
+ lastModified = (new Date().getTime() / 1000) * 1000;
}
public String getText()
{
return text;
+ }
+
+ public long getLastModified()
+ {
+ return lastModified;
}
public void writeTo(BinaryOutput output) throws IOException
Modified:
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/SkinService.java
===================================================================
---
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/SkinService.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/component/portal/src/main/java/org/exoplatform/portal/resource/SkinService.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -329,6 +329,17 @@
orientation = Orientation.RT;
}
+ //
+ Map<String, CachedStylesheet> cache = orientation == Orientation.LT ? ltCache
: rtCache;
+ CachedStylesheet css = cache.get(path);
+ if (css == null)
+ {
+ StringBuilder sb = new StringBuilder();
+ processCSS(sb, path, orientation, true);
+ css = new CachedStylesheet(sb.toString());
+ cache.put(path, css);
+ }
+
// Try cache first
if (!PropertyManager.isDevelopping())
{
@@ -342,16 +353,6 @@
renderer.setExpiration(ONE_HOUR);
}
- //
- Map<String, CachedStylesheet> cache = orientation == Orientation.LT ?
ltCache : rtCache;
- CachedStylesheet css = cache.get(path);
- if (css == null)
- {
- StringBuilder sb = new StringBuilder();
- processCSS(sb, path, orientation, true);
- css = new CachedStylesheet(sb.toString());
- cache.put(path, css);
- }
css.writeTo(renderer.getOutput());
}
else
@@ -652,4 +653,30 @@
DefaultServletContainerFactory.getInstance().getServletContainer().removeWebAppListener(deployer);
DefaultServletContainerFactory.getInstance().getServletContainer().removeWebAppListener(removal);
}
+
+ /**
+ * Return last modifed date of cached css
+ * Return null if cached css can not be found
+ * @param path - path must not be null
+ */
+ public long getLastModified(String path) {
+ if (path == null) {
+ throw new IllegalArgumentException("path must not be null");
+ }
+
+ Map<String, CachedStylesheet> cache = ltCache;
+ if (path.endsWith("-lt.css")) {
+ path = path.substring(0, path.length() - "-lt.css".length()) +
".css";
+ } else if (path.endsWith("-rt.css")) {
+ path = path.substring(0, path.length() - "-rt.css".length()) +
".css";
+ cache = rtCache;
+ }
+
+ CachedStylesheet cachedCSS = cache.get(path);
+ if (cachedCSS == null) {
+ return Long.MAX_VALUE;
+ } else {
+ return cachedCSS.getLastModified();
+ }
+ }
}
\ No newline at end of file
Modified:
exo/portal/branches/3.1.x/component/web/src/main/java/org/exoplatform/web/application/javascript/JavascriptConfigService.java
===================================================================
---
exo/portal/branches/3.1.x/component/web/src/main/java/org/exoplatform/web/application/javascript/JavascriptConfigService.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/component/web/src/main/java/org/exoplatform/web/application/javascript/JavascriptConfigService.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -49,6 +49,8 @@
private byte[] jsBytes = null;
+ private long lastModified = Long.MAX_VALUE;
+
/** . */
private JavascriptDeployer deployer;
@@ -221,6 +223,18 @@
*/
public void writeMergedJavascript(OutputStream out) throws IOException
{
+ jsBytes = getMergedJavascript();
+
+ //
+ out.write(jsBytes);
+ }
+
+ /**
+ * Return merged javascript in byte array
+ * @return byte[]
+ */
+ public byte[] getMergedJavascript()
+ {
if (jsBytes == null)
{
// Generate javascript in a buffer
@@ -257,10 +271,15 @@
log.error("Error when generating minified javascript, will use normal
javascript instead", e);
jsBytes = bytes;
}
+// Remove miliseconds because string of date retrieve from Http header
doesn't have miliseconds
+ lastModified = (new Date().getTime() / 1000) * 1000;
}
+ return jsBytes;
+ }
- //
- out.write(jsBytes);
+ public long getLastModified()
+ {
+ return lastModified;
}
public boolean isModuleLoaded(CharSequence module)
Modified:
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/Image.java
===================================================================
---
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/Image.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/Image.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -19,6 +19,8 @@
package org.exoplatform.portal.application;
+import java.util.Date;
+
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
* @version $Revision$
@@ -29,10 +31,19 @@
final ImageType type;
final byte[] bytes;
+
+ final long lastModified;
public Image(ImageType type, byte[] bytes)
{
this.type = type;
this.bytes = bytes;
+// Remove miliseconds because string of date retrieve from Http header doesn't have
miliseconds
+ lastModified = (new Date().getTime() / 1000) * 1000;
}
+
+ public long getLastModified()
+ {
+ return lastModified;
+ }
}
Modified:
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/ResourceRequestFilter.java
===================================================================
---
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/ResourceRequestFilter.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/application/ResourceRequestFilter.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -36,6 +36,7 @@
import java.io.OutputStream;
import java.net.URLDecoder;
import java.nio.charset.Charset;
+import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -64,6 +65,10 @@
private ConcurrentMap<String, FutureTask<Image>> mirroredImageCache = new
ConcurrentHashMap<String, FutureTask<Image>>();
+ public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
+
+ public static final String LAST_MODIFIED = "Last-Modified";
+
public void afterInit(FilterConfig filterConfig)
{
cfg = filterConfig;
@@ -77,11 +82,19 @@
final String uri = URLDecoder.decode(httpRequest.getRequestURI(),
"UTF-8");
final HttpServletResponse httpResponse = (HttpServletResponse)response;
ExoContainer portalContainer = getContainer();
- SkinService skinService =
(SkinService)portalContainer.getComponentInstanceOfType(SkinService.class);
+ final SkinService skinService = (SkinService)
portalContainer.getComponentInstanceOfType(SkinService.class);
+ long ifModifiedSince = httpRequest.getDateHeader(IF_MODIFIED_SINCE);
//
if (uri.endsWith(".css"))
{
+// Check if cached resource has not been modifed, return 304 code
+ long cssLastModified = skinService.getLastModified(uri);
+ if (isNotModified(ifModifiedSince, cssLastModified)) {
+ httpResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+
final OutputStream out = response.getOutputStream();
final BinaryOutput output = new BinaryOutput()
{
@@ -118,6 +131,9 @@
{
httpResponse.setHeader("Cache-Control",
"no-cache");
}
+
+ long lastModified = skinService.getLastModified(uri);
+ processIfModified(lastModified, httpResponse);
}
};
@@ -192,8 +208,16 @@
Image img = futureImg.get();
if (img != null)
{
+ //Check if cached resource has not been modifed, return 304 code
+ long imgLastModified = img.getLastModified();
+ if (isNotModified(ifModifiedSince, imgLastModified)) {
+ httpResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
httpResponse.setContentType(img.type.getMimeType());
httpResponse.setContentLength(img.bytes.length);
+ processIfModified(imgLastModified, httpResponse);
+
OutputStream out = httpResponse.getOutputStream();
out.write(img.bytes);
out.close();
@@ -238,6 +262,30 @@
}
}
+ /**
+ * Add Last-Modified Http header to HttpServetResponse
+ */
+ public void processIfModified(long lastModified, HttpServletResponse httpResponse) {
+ httpResponse.setDateHeader(ResourceRequestFilter.LAST_MODIFIED, lastModified);
+ }
+
+ /**
+ * If cached resource has not changed since date in http header (If_Modified_Since),
return true
+ * Else return false;
+ * @param ifModifedSince - String, and HttpHeader element
+ * @param lastModified
+ * @param httpResponse
+ * @return
+ */
+ public boolean isNotModified(long ifModifedSince, long lastModified) {
+ if (!PropertyManager.isDevelopping()) {
+ if (ifModifedSince >= lastModified) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void destroy()
{
}
Modified:
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/webui/javascript/JavascriptServlet.java
===================================================================
---
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/webui/javascript/JavascriptServlet.java 2010-11-29
03:20:50 UTC (rev 5326)
+++
exo/portal/branches/3.1.x/webui/portal/src/main/java/org/exoplatform/portal/webui/javascript/JavascriptServlet.java 2010-11-29
04:30:49 UTC (rev 5327)
@@ -19,10 +19,14 @@
package org.exoplatform.portal.webui.javascript;
+import org.exoplatform.commons.utils.PropertyManager;
import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.portal.application.ResourceRequestFilter;
import org.exoplatform.web.application.javascript.JavascriptConfigService;
import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@@ -55,14 +59,23 @@
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException,
IOException
{
- JavascriptConfigService service =
+ final JavascriptConfigService service =
(JavascriptConfigService)ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(
JavascriptConfigService.class);
-
+ long lastModified = service.getLastModified();
+ long ifModifiedSince =
request.getDateHeader(ResourceRequestFilter.IF_MODIFIED_SINCE);
+
// Julien: should we also set charset along with the content type ?
response.setContentType("application/x-javascript");
- ServletOutputStream stream = response.getOutputStream();
- service.writeMergedJavascript(stream);
+ if (!PropertyManager.isDevelopping()) {
+ if (ifModifiedSince >= lastModified) {
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ }
+
+ byte[] jsBytes = service.getMergedJavascript();
+ response.setDateHeader(ResourceRequestFilter.LAST_MODIFIED, lastModified);
+ response.getOutputStream().write(jsBytes);
}
-
}