Author: ssmiweve
Date: 2008-02-16 11:40:22 +0100 (Sat, 16 Feb 2008)
New Revision: 6123

Added:
   
branches/2.16/war/src/main/java/no/sesat/search/http/filters/SiteJspLoaderFilter.java
   branches/2.16/war/src/main/webapp/META-INF/context.xml
Modified:
   branches/2.16/generic.sesam/
   branches/2.16/generic.sesam/pom.xml
   branches/2.16/generic.sesam/war/src/webapp/WEB-INF/web.xml
   
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/AbstractResourceLoader.java
   
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/UrlResourceLoader.java
   
branches/2.16/skinresourcefeed/src/main/java/no/sesat/commons/resourcefeed/ResourceServlet.java
   branches/2.16/war/src/main/webapp/WEB-INF/web.xml
Log:
SEARCH-4290 - Design and code with JSPs in skins



Property changes on: branches/2.16/generic.sesam
___________________________________________________________________
Name: svn:ignore
   + target


Modified: branches/2.16/generic.sesam/pom.xml
===================================================================
--- branches/2.16/generic.sesam/pom.xml 2008-02-16 08:34:44 UTC (rev 6122)
+++ branches/2.16/generic.sesam/pom.xml 2008-02-16 10:40:22 UTC (rev 6123)
@@ -73,6 +73,8 @@
                     <include>*.html</include>
                     <include>**/*.vm</include>
                     <include>**/*.html</include>
+                    <include>*.jsp</include>
+                    <include>**/*.jsp</include>
                 </includes>
             </resource>
             <resource>

Modified: branches/2.16/generic.sesam/war/src/webapp/WEB-INF/web.xml
===================================================================
--- branches/2.16/generic.sesam/war/src/webapp/WEB-INF/web.xml  2008-02-16 
08:34:44 UTC (rev 6122)
+++ branches/2.16/generic.sesam/war/src/webapp/WEB-INF/web.xml  2008-02-16 
10:40:22 UTC (rev 6123)
@@ -42,11 +42,11 @@
         </init-param>
         <init-param>
             <param-name>resources.restricted</param-name>
-            <param-value>properties,xml,vm,html,class,jar</param-value>
+            <param-value>properties,xml,vm,html,class,jar,jsp</param-value>
         </init-param>
         <init-param>
             <param-name>content.paths</param-name>
-            
<param-value>properties=conf,xml=conf,vm=templates,html=templates,css=css,js=javascript,jpg=images,gif=images,png=images,class=classes,jar=lib</param-value>
+            
<param-value>properties=conf,xml=conf,vm=templates,html=templates,css=css,js=javascript,jpg=images,gif=images,png=images,class=classes,jar=lib,jsp=jsp</param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>
     </servlet>
@@ -55,11 +55,6 @@
         <servlet-name>resource servlet</servlet-name>
         <url-pattern>/javascript/*</url-pattern>
     </servlet-mapping>
-
-    <welcome-file-list>
-        <welcome-file>/images/logo.jpg</welcome-file>
-    </welcome-file-list>
-
     <servlet-mapping>
         <servlet-name>resource servlet</servlet-name>
         <url-pattern>/css/*</url-pattern>
@@ -74,6 +69,10 @@
     </servlet-mapping>
     <servlet-mapping>
         <servlet-name>resource servlet</servlet-name>
+        <url-pattern>*.jsp</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>resource servlet</servlet-name>
         <url-pattern>/templates/*</url-pattern>
     </servlet-mapping>
     <servlet-mapping>

Modified: 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/AbstractResourceLoader.java
===================================================================
--- 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/AbstractResourceLoader.java
        2008-02-16 08:34:44 UTC (rev 6122)
+++ 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/AbstractResourceLoader.java
        2008-02-16 10:40:22 UTC (rev 6123)
@@ -209,8 +209,12 @@
 
         if (resourceType == Resource.BYTECODE) {
             // Convert package structure to path.
-            this.resource = resource.replace(".", "/") + ".class";
-
+            if(!resource.endsWith(".jsp")){
+                this.resource = resource.replace(".", "/") + ".class";
+            }else{
+                this.resource = resource;
+            }
+            
             if (jarFileName != null) {
                 // Construct the path portion of a JarUrl.
                 this.resource = jarFileName + "!/" + this.resource;

Modified: 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/UrlResourceLoader.java
===================================================================
--- 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/UrlResourceLoader.java
     2008-02-16 08:34:44 UTC (rev 6122)
+++ 
branches/2.16/site-spi/src/main/java/no/sesat/search/site/config/UrlResourceLoader.java
     2008-02-16 10:40:22 UTC (rev 6123)
@@ -202,6 +202,8 @@
             return "lib/";
         } else if (resource.endsWith(".class")) {
             return "classes/";
+        } else if (resource.endsWith(".jsp")) {
+            return "jsp/";
         } else {
             return "conf/";
         }

Modified: 
branches/2.16/skinresourcefeed/src/main/java/no/sesat/commons/resourcefeed/ResourceServlet.java
===================================================================
--- 
branches/2.16/skinresourcefeed/src/main/java/no/sesat/commons/resourcefeed/ResourceServlet.java
     2008-02-16 08:34:44 UTC (rev 6122)
+++ 
branches/2.16/skinresourcefeed/src/main/java/no/sesat/commons/resourcefeed/ResourceServlet.java
     2008-02-16 10:40:22 UTC (rev 6123)
@@ -170,18 +170,31 @@
         request.setCharacterEncoding("UTF-8"); // correct encoding
 
         // Get resource name. Also strip the version number out of the resource
-        final String configName = 
request.getPathInfo().replaceAll("/(\\d)+/","/");
+        final String pathInfo;
+        final String directory;
+        if(null != request.getPathInfo()){
+            // simple scenerio where servlet-mapping was a prefix match.
+            pathInfo = request.getPathInfo();
+            directory = request.getServletPath();
+        }else{
+            // servlet-mapping was extension based
+            pathInfo = 
request.getServletPath().substring(request.getServletPath().indexOf('/', 1));
+            directory = request.getServletPath().substring(0, 
request.getServletPath().indexOf('/', 1));
+        }
+        LOG.debug("pathInfo: " + pathInfo + " ; directory: " + directory);
+        assert null != pathInfo : "Invalid resource " + pathInfo;
         
-        assert null != configName : "Invalid resource " + 
request.getPathInfo();
-        assert 0 < configName.trim().length() : "Invalid resource " + 
request.getPathInfo();
-        assert 0 < configName.lastIndexOf('.') : "Invalid resource extension " 
+ request.getPathInfo();
+        final String configName = pathInfo.replaceAll("/(\\d)+/","/");
+        
+        assert 0 < configName.trim().length() : "Invalid resource " + pathInfo;
+        assert 0 < configName.lastIndexOf('.') : "Invalid resource extension " 
+ pathInfo;
 
         if (configName != null && configName.trim().length() > 0) {
 
             final String extension = 
configName.substring(configName.lastIndexOf('.') + 1).toLowerCase();
             
-            assert null != extension : "Invalid resource extension" + 
request.getPathInfo();
-            assert 0 < extension.trim().length() : "Invalid resource extension 
" + request.getPathInfo();
+            assert null != extension : "Invalid resource extension" + pathInfo;
+            assert 0 < extension.trim().length() : "Invalid resource extension 
" + pathInfo;
             
             final String ipAddr = null != 
request.getAttribute(REMOTE_ADDRESS_KEY)
                 ? (String) request.getAttribute(REMOTE_ADDRESS_KEY)
@@ -191,7 +204,6 @@
             response.setContentType(CONTENT_TYPES.get(extension) + 
";charset=UTF-8");
 
             // Path check. Resource can only be loaded through correct path.
-            final String directory = request.getServletPath();
             if (null != CONTENT_PATHS.get(extension) && 
directory.indexOf(CONTENT_PATHS.get(extension)) >= 0) {
 
                 // ok, check configuration resources are private.

Added: 
branches/2.16/war/src/main/java/no/sesat/search/http/filters/SiteJspLoaderFilter.java
===================================================================
--- 
branches/2.16/war/src/main/java/no/sesat/search/http/filters/SiteJspLoaderFilter.java
                               (rev 0)
+++ 
branches/2.16/war/src/main/java/no/sesat/search/http/filters/SiteJspLoaderFilter.java
       2008-02-16 10:40:22 UTC (rev 6123)
@@ -0,0 +1,260 @@
+/* Copyright (2006-2007) Schibsted Søk AS
+ * This file is part of SESAT.
+ *
+ *   SESAT is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Affero General Public License as published 
by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SESAT is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Affero General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Affero General Public License
+ *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package no.sesat.search.http.filters;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.MalformedURLException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import no.sesat.search.site.config.ResourceLoadException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import no.sesat.search.site.Site;
+import no.sesat.search.site.SiteContext;
+import no.sesat.search.site.config.BytecodeLoader;
+import no.sesat.search.site.config.UrlResourceLoader;
+import org.apache.log4j.Logger;
+
+
+/**
+ * Downloads JSP files from skins into sesat to be compiled and used locally.
+ * This makes it look like jsps from the other skin web applications actually 
are bundled into sesat. <br/><br/>
+ *
+ * Implementation issue: <a 
href="https://jira.sesam.no/jira/browse/SEARCH-4290";>Design and code with JSPs 
in skins</a>
+ *
+ * <br/><br/>
+ * 
+ * <b>Inclusion of jsps</b> may occurr with &lt;jsp:include page="..."/> 
+ *      or some other requestDispatcher.include(..) approach.
+ *      &lt;%@ include file=".."/%> will not work.
+ * 
+ * 
+ * <br/><br/>
+ *
+ * <b>To enable JSP files</b> in a particular skin to be downloaded into sesat 
the following configuration is required:
+ *  <ul>
+ * <li>in the skin's web.xml add "jsp" to the resources.restricted init-param 
for ResourceServlet,</li>
+ * <li>in the skin's web.xml add "jsp=jsp" to the content.paths init-param for 
ResourceServlet,</li>
+ * <li>in the skin's web.xml add the servlet-mapping:
+ * <pre>
+    &lt;servlet-mapping>
+        &lt;servlet-name>resource servlet&lt;/servlet-name>
+        &lt;url-pattern>*.jsp&lt;/url-pattern>
+    &lt;/servlet-mapping>
+ * </pre> so to avoid the skin's JspServlet and to serve the jsp files are 
resources back to sesat,</li>
+ * <li>in the skin's pom.xml add to the 
<pre>&lt;directory>src/main/templates&lt;/directory></pre>
+ *      the following to ensure jsps and bundled into the war file:
+ * <pre>
+    &lt;include>*.jsp&lt;/include>
+    &lt;include>*&#x02a;/*.jsp&lt;/include>
+ * </pre></li>
+ *  </ul>
+ * This have already been done in the base skin sesat-kernel/generic.sesam and 
can be used as an example.<br/><br/>
+ *
+ * <b>Tomcat, or the container used, must not use unpackWARs="false", or any 
non-file based deployment implementation,
+ * as this class must be able to write files into the deployed webapps 
directory.</b> <br/>
+ * Such files are written using a  FileChannel obtained like
+ * <pre>new RandomFileAccess(new File(root + 
"requested-jsp-name"),"rw").getChannel()</pre>
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Mck</a>
+ * @version $Id$
+ */
+public final class SiteJspLoaderFilter implements Filter {
+
+
+    private static final Logger LOG = 
Logger.getLogger(SiteJspLoaderFilter.class);
+
+    private FilterConfig config;
+    private String root;
+
+    /** [EMAIL PROTECTED] **/
+    public void init(final FilterConfig filterConfig) throws ServletException {
+
+        config = filterConfig;
+        root = config.getServletContext().getRealPath("/");
+    }
+
+    /** [EMAIL PROTECTED] **/
+    public void doFilter(
+            final ServletRequest request,
+            final ServletResponse response,
+            final FilterChain chain) throws IOException, ServletException {
+
+        if( request instanceof HttpServletRequest){
+
+            final String jsp = getRequestedJsp((HttpServletRequest)request);
+            LOG.debug("jsp: " + jsp + "; resource: " + 
config.getServletContext().getResource(jsp));
+
+            downloadJsp((HttpServletRequest)request, jsp);
+
+        }
+
+        chain.doFilter(request, response);
+    }
+
+    /** [EMAIL PROTECTED] **/
+    public void destroy() {
+    }
+
+    // copied from JspServlet.serve(..)
+    private String getRequestedJsp(
+            final HttpServletRequest request){
+
+        String jspUri = null;
+
+        String jspFile = (String) request.getAttribute(JSP_FILE);
+        if (jspFile != null) {
+            // JSP is specified via <jsp-file> in <servlet> declaration
+            jspUri = jspFile;
+        } else {
+            /*
+             * Check to see if the requested JSP has been the target of a
+             * RequestDispatcher.include()
+             */
+            jspUri = (String) request.getAttribute(INC_SERVLET_PATH);
+            if (jspUri != null) {
+                /*
+                * Requested JSP has been target of
+                 * RequestDispatcher.include(). Its path is assembled from the
+                 * relevant javax.servlet.include.* request attributes
+                 */
+                String pathInfo = (String) 
request.getAttribute("javax.servlet.include.path_info");
+                if (pathInfo != null) {
+                    jspUri += pathInfo;
+                }
+            } else {
+                /*
+                 * Requested JSP has not been the target of a
+                 * RequestDispatcher.include(). Reconstruct its path from the
+                 * request's getServletPath() and getPathInfo()
+                 */
+                jspUri = request.getServletPath();
+                String pathInfo = request.getPathInfo();
+                if (pathInfo != null) {
+                    jspUri += pathInfo;
+                }
+            }
+        }
+        return jspUri;
+    }
+
+    private void downloadJsp(
+            final HttpServletRequest request,
+            final String jsp) throws MalformedURLException{
+
+        byte[] golden = new byte[0];
+
+        // search skins for the jsp and write it out to "golden"
+        for(Site site = (Site) request.getAttribute(Site.NAME_KEY); 0 == 
golden.length; site = site.getParent()){
+
+            if(null == site){
+                if(null == config.getServletContext().getResource(jsp)){
+                    throw new ResourceLoadException("Unable to find " + jsp + 
" in any skin");
+                }
+                break;
+            }
+
+            final Site finalSite = site;
+            final BytecodeLoader bcLoader = 
UrlResourceLoader.newBytecodeLoader(
+                    new SiteContext(){
+                        public Site getSite() {
+                            return finalSite;
+                        }
+                    },
+                    jsp,
+                    null
+            );
+            bcLoader.abut();
+            golden = bcLoader.getBytecode();
+        }
+
+        // if golden now contains data save it to a local (ie local web 
application) file
+        if(0 < golden.length){
+            try {
+                final File file = new File(root + jsp);
+
+                // create the directory structure
+                file.getParentFile().mkdirs();
+
+                // check existing file
+                boolean needsUpdating = true;
+                final boolean fileExisted = file.exists();
+                if(!fileExisted){
+                    file.createNewFile();
+                }
+                final RandomAccessFile fileAccess = new RandomAccessFile(file, 
"rw");
+                final FileChannel channel = fileAccess.getChannel();
+
+                try{
+                    channel.lock();
+
+                    if(fileExisted){
+
+                        final byte[] bytes = new byte[(int)channel.size()];
+                        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+                        int reads; do{ reads = channel.read(byteBuffer); 
}while(0 < reads);
+
+                        needsUpdating = !Arrays.equals(golden, bytes);
+                    }
+
+                    if(needsUpdating){
+                        // download file from skin
+                        channel.write(ByteBuffer.wrap(golden), 0);
+                        channel.force(true);
+                        file.deleteOnExit();
+
+                    }
+                }finally{
+                    channel.close();
+                    LOG.debug("resource created as " + 
config.getServletContext().getResource(jsp));
+
+                }
+
+            }catch (IOException ex) {
+                LOG.error(ex.getMessage(), ex);
+            }
+        }
+    }
+
+    //// Imported from org.catalina.jasper.Constants
+
+    /**
+     * Request attribute for <code>&lt;jsp-file&gt;</code> element of a
+     * servlet definition.  If present on a request, this overrides the
+     * value returned by <code>request.getServletPath()</code> to select
+     * the JSP page to be executed.
+     */
+    public static final String JSP_FILE =
+        System.getProperty("org.apache.jasper.Constants.JSP_FILE", 
"org.apache.catalina.jsp_file");
+
+    /**
+     * Servlet context and request attributes that the JSP engine
+     * uses.
+     */
+    public static final String INC_SERVLET_PATH = 
"javax.servlet.include.servlet_path";
+
+}


Property changes on: 
branches/2.16/war/src/main/java/no/sesat/search/http/filters/SiteJspLoaderFilter.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: branches/2.16/war/src/main/webapp/META-INF/context.xml
===================================================================
--- branches/2.16/war/src/main/webapp/META-INF/context.xml                      
        (rev 0)
+++ branches/2.16/war/src/main/webapp/META-INF/context.xml      2008-02-16 
10:40:22 UTC (rev 6123)
@@ -0,0 +1,2 @@
+<!-- Since we dynamically add files into our deployment directory we must turn 
caching off. See SiteJspLoaderFilter.java--> 
+<Context cachingAllowed="false" />
\ No newline at end of file

Modified: branches/2.16/war/src/main/webapp/WEB-INF/web.xml
===================================================================
--- branches/2.16/war/src/main/webapp/WEB-INF/web.xml   2008-02-16 08:34:44 UTC 
(rev 6122)
+++ branches/2.16/war/src/main/webapp/WEB-INF/web.xml   2008-02-16 10:40:22 UTC 
(rev 6123)
@@ -76,6 +76,10 @@
         </init-param>
     </filter>
     
+    <filter>
+        <filter-name>SiteJspLoaderFilter</filter-name>
+        
<filter-class>no.sesat.search.http.filters.SiteJspLoaderFilter</filter-class>
+    </filter>
     
     <filter>
         <filter-name>UserFilter</filter-name>
@@ -102,7 +106,6 @@
     <filter-mapping>
         <filter-name>DataModelFilter</filter-name>
         <url-pattern>/*</url-pattern>
-        <!--dispatcher>INCLUDE</dispatcher--> <!-- avoid requests to jsps -->
         <dispatcher>FORWARD</dispatcher>
         <dispatcher>REQUEST</dispatcher>
     </filter-mapping>
@@ -127,6 +130,11 @@
         <dispatcher>FORWARD</dispatcher>
         <dispatcher>REQUEST</dispatcher> 
     </filter-mapping>
+    <filter-mapping>
+        <filter-name>SiteJspLoaderFilter</filter-name>
+        <url-pattern>*.jsp</url-pattern>
+        <dispatcher>INCLUDE</dispatcher>
+    </filter-mapping>
     
     <!-- Servlets -->
 
@@ -142,17 +150,17 @@
         <load-on-startup>1</load-on-startup>
     </servlet>
     <servlet>
-           <servlet-name>jsp</servlet-name>
-           <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+        <servlet-name>jsp</servlet-name>
+        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
         <init-param>
             <param-name>development</param-name>
             <param-value>false</param-value>
         </init-param>
         <init-param>
-            <param-name>reloading</param-name>
-            <param-value>false</param-value>
+            <!-- Because SiteJspLoaderFilter dynamically updates our jsp files 
check very frequently for changes -->s
+            <param-name>checkInterval</param-name>
+            <param-value>5</param-value>
         </init-param>
-
         <load-on-startup>3</load-on-startup>
     </servlet>
 

_______________________________________________
Kernel-commits mailing list
[email protected]
http://sesat.no/mailman/listinfo/kernel-commits

Reply via email to