Return-Path: Delivered-To: apmail-incubator-click-commits-archive@minotaur.apache.org Received: (qmail 82437 invoked from network); 6 Nov 2009 11:59:26 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 6 Nov 2009 11:59:26 -0000 Received: (qmail 12731 invoked by uid 500); 6 Nov 2009 11:59:26 -0000 Delivered-To: apmail-incubator-click-commits-archive@incubator.apache.org Received: (qmail 12715 invoked by uid 500); 6 Nov 2009 11:59:26 -0000 Mailing-List: contact click-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: click-dev@incubator.apache.org Delivered-To: mailing list click-commits@incubator.apache.org Received: (qmail 12705 invoked by uid 99); 6 Nov 2009 11:59:26 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 06 Nov 2009 11:59:26 +0000 X-ASF-Spam-Status: No, hits=-2.6 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 06 Nov 2009 11:59:24 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id EE86523888E2; Fri, 6 Nov 2009 11:59:03 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r833367 - /incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java Date: Fri, 06 Nov 2009 11:59:03 -0000 To: click-commits@incubator.apache.org From: sabob@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091106115903.EE86523888E2@eris.apache.org> Author: sabob Date: Fri Nov 6 11:59:03 2009 New Revision: 833367 URL: http://svn.apache.org/viewvc?rev=833367&view=rev Log: implemented resource service to use lazy loading instead Modified: incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java Modified: incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java?rev=833367&r1=833366&r2=833367&view=diff ============================================================================== --- incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java (original) +++ incubator/click/trunk/click/framework/src/org/apache/click/service/ClickResourceService.java Fri Nov 6 11:59:03 2009 @@ -18,30 +18,21 @@ */ package org.apache.click.service; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URL; import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; +import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.click.util.ClickUtils; -import org.apache.commons.io.FileUtils; +import org.apache.click.util.HtmlStringBuffer; import org.apache.commons.io.IOUtils; -import org.apache.commons.io.filefilter.TrueFileFilter; /** * Provides a default Click static resource service class. This class will @@ -50,12 +41,12 @@ * web root. *

* This service is useful for application servers which do not allow Click to - * automatically deploy resources to the web root /click/ directory. + * automatically deploy resources to the web root directory. */ public class ClickResourceService implements ResourceService { /** The click resources cache. */ - protected Map resourceCache = new HashMap(); + protected Map resourceCache = new ConcurrentHashMap(); /** The application log service. */ protected LogService logService; @@ -73,18 +64,6 @@ configService = ClickUtils.getConfigService(servletContext); logService = configService.getLogService(); - - // Load all JAR resources - List cacheables = getCacheableDirs(); - for (String cacheable : cacheables) { - loadJarResources(cacheable); - } - - // Load file system resources. File system resources override JAR - // resources - for (String cacheable : cacheables) { - loadDirResources(servletContext, cacheable); - } } /** @@ -120,9 +99,16 @@ String resourcePath = ClickUtils.getResourcePath(request); - if (!resourceCache.containsKey(resourcePath)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; + byte[] resourceData = resourceCache.get(resourcePath); + + if (resourceData == null) { + // Lazily load resource + resourceData = loadResourceData(resourcePath); + + if (resourceData == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } } String mimeType = ClickUtils.getMimeType(resourcePath); @@ -130,7 +116,14 @@ response.setContentType(mimeType); } - byte[] resourceData = resourceCache.get(resourcePath); + if (logService.isDebugEnabled()) { + HtmlStringBuffer buffer = new HtmlStringBuffer(200); + buffer.append("handleRequest: "); + buffer.append(request.getMethod()); + buffer.append(" "); + buffer.append(request.getRequestURL()); + logService.debug(buffer); + } renderResource(response, resourceData); } @@ -165,30 +158,30 @@ *

      * <-- The default Click *.htm mapping -->
      * <servlet-mapping>
-		 *   <servlet-name>ClickServlet</servlet-name>
-		 *   <url-pattern>*.htm</url-pattern>
-	   * </servlet-mapping>
+         *   <servlet-name>ClickServlet</servlet-name>
+         *   <url-pattern>*.htm</url-pattern>
+       * </servlet-mapping>
      *
      * <-- Add a mapping to serve all resources under /click directly from
      * the JARs. -->
-	   * <servlet-mapping>
-		 *   <servlet-name>ClickServlet</servlet-name>
-		 *   <url-pattern>/click/*</url-pattern>
-	   * </servlet-mapping>
+       * <servlet-mapping>
+         *   <servlet-name>ClickServlet</servlet-name>
+         *   <url-pattern>/click/*</url-pattern>
+       * </servlet-mapping>
      *
      * <-- Add another mapping to serve all resources under /clickclick
      * from the JARs. -->
-	   * <servlet-mapping>
-		 *   <servlet-name>ClickServlet</servlet-name>
-		 *   <url-pattern>/clickclick/*</url-pattern>
-	   * </servlet-mapping>
+       * <servlet-mapping>
+         *   <servlet-name>ClickServlet</servlet-name>
+         *   <url-pattern>/clickclick/*</url-pattern>
+       * </servlet-mapping>
      *
      * <-- Add a mapping to serve all resources under /mycorp
      * from the JARs. -->
-	   * <servlet-mapping>
-		 *   <servlet-name>ClickServlet</servlet-name>
-		 *   <url-pattern>/mycorp/*</url-pattern>
-	   * </servlet-mapping>
+       * <servlet-mapping>
+         *   <servlet-name>ClickServlet</servlet-name>
+         *   <url-pattern>/mycorp/*</url-pattern>
+       * </servlet-mapping>
      * 
* * @return list of directories that should be cached @@ -201,225 +194,47 @@ // Private Methods -------------------------------------------------------- - private void loadJarResources(String resourceDir) throws IOException { - if (resourceDir == null) { - throw new IllegalArgumentException("resource directory cannot be null"); - } - - long startTime = System.currentTimeMillis(); - - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - if (!resourceDir.startsWith("/")) { - resourceDir = '/' + resourceDir; - } - - // Find all jars and directories on the classpath that contains the - // directory "META-INF/resources/", and deploy those resources - String resourceDirectory = "META-INF/resources" + resourceDir; - Enumeration en = classLoader.getResources(resourceDirectory); - while (en.hasMoreElements()) { - URL url = en.nextElement(); - loadResourcesOnClasspath(url, resourceDirectory); - } - - if (logService.isTraceEnabled()) { - logService.trace("loaded files from jars and folders - " - + (System.currentTimeMillis() - startTime) + " ms"); - } - } - /** - * Deploy from the url all resources found under the prefix. + * Store the resource under the given resource path. * - * @param url the url of the jar or folder which resources to deploy - * @param resourceDirectory the directory under which resources are found - * @throws IOException if resources from the url cannot be deployed + * @param resourcePath the path to store the resource under + * @param data the resource byte array */ - private void loadResourcesOnClasspath(URL url, String resourceDirectory) - throws IOException { - - String path = url.getFile(); - - // Decode the url, esp on Windows where file paths can have their - // spaces encoded. decodeURL will convert C:\Program%20Files\project - // to C:\Program Files\project - path = ClickUtils.decodeURL(path); - - // Strip file prefix - if (path.startsWith("file:")) { - path = path.substring(5); - } - - String jarPath = null; - - // Check if path represents a jar - if (path.indexOf('!') > 0) { - jarPath = path.substring(0, path.indexOf('!')); - - File jar = new File(jarPath); - - if (jar.exists()) { - loadFilesInJar(jar, resourceDirectory); - - } else { - logService.error("Could not load the jar '" + jarPath - + "'. Please ensure this file exists in the specified" - + " location."); - } - } else { - File dir = new File(path); - loadFilesInJarDir(dir, resourceDirectory); + private void storeResourceData(String resourcePath, byte[] data) { + // Only cache in production modes + if (configService.isProductionMode() || configService.isProfileMode()) { + resourceCache.put(resourcePath, data); } } - private void loadFilesInJar(File jar, String resourceDirectory) - throws IOException { - - if (jar == null) { - throw new IllegalArgumentException("Jar cannot be null"); - } - - InputStream inputStream = null; - JarInputStream jarInputStream = null; - - try { - - inputStream = new FileInputStream(jar); - jarInputStream = new JarInputStream(inputStream); - JarEntry jarEntry = null; - - // Indicates whether feedback should be logged about the files deployed - // from jar - boolean logFeedback = true; - while ((jarEntry = jarInputStream.getNextJarEntry()) != null) { - - // Guard against loading folders -> META-INF/resources/click/ - if (jarEntry.isDirectory()) { - continue; - } - - // jarEntryName example -> META-INF/resources/click/table.css - String jarEntryName = jarEntry.getName(); - - // Only deploy resources from "META-INF/resources/" - int pathIndex = jarEntryName.indexOf(resourceDirectory); - if (pathIndex == 0) { - if (logFeedback && logService.isTraceEnabled()) { - logService.trace("loaded files from jar -> " - + jar.getCanonicalPath()); - - // Only provide feedback once per jar - logFeedback = false; - } - loadJarFile(jarEntryName, resourceDirectory); - } - } - } finally { - ClickUtils.close(jarInputStream); - ClickUtils.close(inputStream); - } - } - - @SuppressWarnings("unchecked") - private void loadFilesInJarDir(File dir, String resourceDirectory) - throws IOException { - - if (dir == null) { - throw new IllegalArgumentException("Dir cannot be null"); - } - - if (!dir.exists()) { - logService.trace("No resources deployed from the folder '" + dir.getAbsolutePath() - + "' as it does not exist."); - return; - } + /** + * Load the resource for the given resourcePath. This method will load the + * resource from the servlet context, and if not found, load it from the + * classpath under the folder 'META-INF/resources'. + * + * @param resourcePath the path to the resource to load + * @return the resource as a byte array + * @throws IOException if the resources cannot be loaded + */ + private byte[] loadResourceData(String resourcePath) throws IOException { - Iterator files = FileUtils.iterateFiles(dir, - TrueFileFilter.INSTANCE, - TrueFileFilter.INSTANCE); - - boolean logFeedback = true; - while (files.hasNext()) { - // file example -> META-INF/resources/click/table.css - File file = (File) files.next(); - - // Guard against loading folders -> META-INF/resources/click/ - if (file.isDirectory()) { - continue; - } + byte[] resourceData = null; - String fileName = file.getCanonicalPath().replace('\\', '/'); + ServletContext servletContext = configService.getServletContext(); - // Only deploy resources from "META-INF/resources/" - int pathIndex = fileName.indexOf(resourceDirectory); - if (pathIndex != -1) { - if (logFeedback && logService.isTraceEnabled()) { - logService.trace("loaded files from folder -> " - + dir.getAbsolutePath()); - - // Only provide feedback once per dir - logFeedback = false; - } - fileName = fileName.substring(pathIndex); - loadJarFile(fileName, resourceDirectory); - } - } - } + resourceData = getServletResourceData(servletContext, resourcePath); + if (resourceData != null) { + storeResourceData(resourcePath, resourceData); + } else { + resourceData = getClasspathResourceData("META-INF/resources" + + resourcePath); - private void loadJarFile(String file, String prefix) throws IOException { - // Only deploy resources containing the prefix - int pathIndex = file.indexOf(prefix); - if (pathIndex == 0) { - pathIndex += prefix.length(); - - // resourceName example -> click/table.css - String resourceName = file.substring(pathIndex); - - if (resourceName.length() > 0) { - byte[] resourceBytes = getClasspathResourceData(file); - - if (resourceBytes != null) { - resourceCache.put("/" + resourceName, resourceBytes); - } + if (resourceData != null) { + storeResourceData(resourcePath, resourceData); } } - } - - @SuppressWarnings("unchecked") - private void loadDirResources(ServletContext servletContext, String resourceDir) - throws IOException { - - if (resourceDir == null) { - throw new IllegalArgumentException("resource directory cannot be null"); - } - - Set resources = servletContext.getResourcePaths(resourceDir); - if (resources != null) { - // Add all resources withtin web application - for (Iterator i = resources.iterator(); i.hasNext();) { - String resource = (String) i.next(); - - // If resource is a folder, recursively look for resources in - // that folder - if (resource.endsWith("/")) { - - loadDirResources(servletContext, resource); - } else { - - if (!configService.isTemplate(resource)) { - - byte[] resourceData = - getServletResourceData(servletContext, resource); - - if (resourceData != null) { - resourceCache.put(resource, resourceData); - } - } - } - } - } + return resourceData; } /**