Author: rmannibucau
Date: Sun Sep 21 06:46:05 2014
New Revision: 1626533

URL: http://svn.apache.org/r1626533
Log:
TOMEE-1348new jaxrs static resource handling - backport from trunk

Added:
    
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/CXFJAXRSFilter.java
Modified:
    
tomee/tomee/branches/tomee-1.7.x/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
    
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java

Modified: 
tomee/tomee/branches/tomee-1.7.x/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java?rev=1626533&r1=1626532&r2=1626533&view=diff
==============================================================================
--- 
tomee/tomee/branches/tomee-1.7.x/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
 (original)
+++ 
tomee/tomee/branches/tomee-1.7.x/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
 Sun Sep 21 06:46:05 2014
@@ -57,6 +57,7 @@ import org.apache.openejb.server.cxf.tra
 import org.apache.openejb.server.httpd.HttpRequest;
 import org.apache.openejb.server.httpd.HttpRequestImpl;
 import org.apache.openejb.server.httpd.HttpResponse;
+import org.apache.openejb.server.httpd.ServletRequestAdapter;
 import org.apache.openejb.server.rest.EJBRestServiceInfo;
 import org.apache.openejb.server.rest.RsHttpListener;
 import org.apache.openejb.util.LogCategory;
@@ -92,8 +93,6 @@ import java.util.concurrent.CopyOnWriteA
 import java.util.logging.Level;
 import java.util.regex.Pattern;
 
-import static java.util.Arrays.asList;
-
 public class CxfRsHttpListener implements RsHttpListener {
 
     private static final Logger LOGGER = 
Logger.getInstance(LogCategory.OPENEJB_RS, CxfRsHttpListener.class);
@@ -106,10 +105,11 @@ public class CxfRsHttpListener implement
     public static final String STATIC_SUB_RESOURCE_RESOLUTION_KEY = 
"staticSubresourceResolution";
     public static final String RESOURCE_COMPARATOR_KEY = CXF_JAXRS_PREFIX + 
"resourceComparator";
 
-    private static final boolean TRY_STATIC_RESOURCES = 
"true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.jaxrs.static-first",
 "true"));
+    public static final boolean TRY_STATIC_RESOURCES = 
"true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.jaxrs.static-first",
 "true"));
     private static final String GLOBAL_PROVIDERS = 
SystemInstance.get().getProperty(PROVIDERS_KEY);
 
     private static final Map<String, String> STATIC_CONTENT_TYPES;
+    private static final String[] DEFAULT_WELCOME_FILES = new String[]{ 
"/index.html", "/index.htm" };
 
     private final HTTPTransportFactory transportFactory;
     private final String wildcard;
@@ -120,6 +120,8 @@ public class CxfRsHttpListener implement
     private final Collection<Pattern> staticResourcesList = new 
CopyOnWriteArrayList<Pattern>();
     private final List<ObjectName> jmxNames = new ArrayList<ObjectName>();
 
+    private static final char[] URL_SEP = new char[] { '?', '#', ';' };
+
     static {
         STATIC_CONTENT_TYPES = new HashMap<String, String>();
         STATIC_CONTENT_TYPES.put("html", "text/html");
@@ -150,11 +152,17 @@ public class CxfRsHttpListener implement
         }
     }
 
+    private String pattern;
+
     public CxfRsHttpListener(final HTTPTransportFactory httpTransportFactory, 
final String star) {
         transportFactory = httpTransportFactory;
         wildcard = star;
     }
 
+    public void setUrlPattern(final String pattern) {
+        this.pattern = pattern;
+    }
+
     @Override
     public void onMessage(final HttpRequest httpRequest, final HttpResponse 
httpResponse) throws Exception {
         // fix the address (to manage multiple connectors)
@@ -164,12 +172,6 @@ public class CxfRsHttpListener implement
             requestImpl.initServletPath(servlet);
         }
 
-        String baseURL = BaseUrlHelper.getBaseURL(httpRequest);
-        if (!baseURL.endsWith("/")) {
-            baseURL += "/";
-        }
-        httpRequest.setAttribute("org.apache.cxf.transport.endpoint.address", 
baseURL);
-
         boolean matchedStatic = false;
         if (TRY_STATIC_RESOURCES || (matchedStatic = matchPath(httpRequest))) {
             final String pathInfo = httpRequest.getPathInfo();
@@ -181,19 +183,32 @@ public class CxfRsHttpListener implement
             }
         }
 
-        // delegate invocation
+        doInvoke(httpRequest, httpResponse);
+    }
+
+    // normal endpoint without static resource handling
+    public void doInvoke(final HttpRequest httpRequest, final HttpResponse 
httpResponse) throws IOException {
+        String baseURL = BaseUrlHelper.getBaseURL(pattern != null ? new 
ServletRequestAdapter(httpRequest) {
+            @Override // we have a filter so we need the computed servlet path 
to not break CXF
+            public String getServletPath() {
+                return pattern;
+            }
+        } : httpRequest);
+        if (!baseURL.endsWith("/")) {
+            baseURL += "/";
+        }
+        httpRequest.setAttribute("org.apache.cxf.transport.endpoint.address", 
baseURL);
+
         final ClassLoader oldLoader = 
Thread.currentThread().getContextClassLoader();
         Thread.currentThread().setContextClassLoader(CxfUtil.initBusLoader());
         try {
             destination.invoke(null, httpRequest.getServletContext(), 
httpRequest, httpResponse);
         } finally {
-            if (oldLoader != null) {
-                CxfUtil.clearBusLoader(oldLoader);
-            }
+            CxfUtil.clearBusLoader(oldLoader);
         }
     }
 
-    private boolean matchPath(final HttpServletRequest request) {
+    public boolean matchPath(final HttpServletRequest request) {
         if (staticResourcesList.isEmpty()) {
             return false;
         }
@@ -210,18 +225,30 @@ public class CxfRsHttpListener implement
         return false;
     }
 
-    protected boolean serveStaticContent(final HttpServletRequest request,
-                                         final HttpServletResponse response,
-                                         final String pathInfo) throws 
ServletException {
+    public InputStream findStaticContent(final HttpServletRequest request, 
final String[] welcomeFiles) throws ServletException {
+        String pathInfo = 
request.getRequestURI().substring(request.getContextPath().length());
+        for (final char c : URL_SEP) {
+            final int indexOf = pathInfo.indexOf(c);
+            if (indexOf > 0) {
+                pathInfo = pathInfo.substring(0, indexOf);
+            }
+        }
         InputStream is = 
request.getServletContext().getResourceAsStream(pathInfo);
-        if (is == null && "/".equals(pathInfo)) {
-            for (final String n : asList("/index.html", "/index.htm")) {
+        if (is == null && ("/".equals(pathInfo) || pathInfo.isEmpty())) {
+            for (final String n : welcomeFiles) {
                 is = request.getServletContext().getResourceAsStream(n);
                 if (is != null) {
                     break;
                 }
             }
         }
+        return is;
+    }
+
+    public boolean serveStaticContent(final HttpServletRequest request,
+                                      final HttpServletResponse response,
+                                      final String pathInfo) throws 
ServletException {
+        final InputStream is = findStaticContent(request, 
DEFAULT_WELCOME_FILES);
         if (is == null) {
             return false;
         }

Added: 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/CXFJAXRSFilter.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/CXFJAXRSFilter.java?rev=1626533&view=auto
==============================================================================
--- 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/CXFJAXRSFilter.java
 (added)
+++ 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/CXFJAXRSFilter.java
 Sun Sep 21 06:46:05 2014
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *     contributor license agreements.  See the NOTICE file distributed with
+ *     this work for additional information regarding copyright ownership.
+ *     The ASF licenses this file to You under the Apache License, Version 2.0
+ *     (the "License"); you may not use this file except in compliance with
+ *     the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *     Unless required by applicable law or agreed to in writing, software
+ *     distributed under the License is distributed on an "AS IS" BASIS,
+ *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *     See the License for the specific language governing permissions and
+ *     limitations under the License.
+ */
+package org.apache.tomee.webservices;
+
+import org.apache.openejb.server.cxf.rs.CxfRsHttpListener;
+import org.apache.openejb.server.httpd.ServletRequestAdapter;
+import org.apache.openejb.server.httpd.ServletResponseAdapter;
+
+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 javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class CXFJAXRSFilter implements Filter {
+    private final CxfRsHttpListener delegate;
+    private final String[] welcomeFiles;
+
+    public CXFJAXRSFilter(final CxfRsHttpListener delegate, final String[] 
welcomeFiles) {
+        this.delegate = delegate;
+
+        this.welcomeFiles = new String[welcomeFiles.length];
+        for (int i = 0; i < welcomeFiles.length; i++) {
+            this.welcomeFiles[i] = '/' + welcomeFiles[i];
+        }
+    }
+
+    @Override
+    public void init(final FilterConfig filterConfig) throws ServletException {
+        // no-op
+    }
+
+    @Override
+    public void doFilter(final ServletRequest request, final ServletResponse 
response, final FilterChain chain) throws IOException, ServletException {
+        if (!HttpServletRequest.class.isInstance(request)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        final HttpServletRequest httpServletRequest = 
HttpServletRequest.class.cast(request);
+        final HttpServletResponse httpServletResponse = 
HttpServletResponse.class.cast(response);
+
+        if (CxfRsHttpListener.TRY_STATIC_RESOURCES || 
delegate.matchPath(httpServletRequest)) {
+            final InputStream staticContent = 
delegate.findStaticContent(httpServletRequest, welcomeFiles);
+            if (staticContent != null) {
+                chain.doFilter(request, response);
+                return;
+            }
+        }
+
+        try {
+            delegate.doInvoke(
+                    new ServletRequestAdapter(httpServletRequest, 
httpServletResponse, request.getServletContext()),
+                    new ServletResponseAdapter(httpServletResponse));
+        } catch (final Exception e) {
+            throw new ServletException("Error processing webservice request", 
e);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        // no-op
+    }
+}

Modified: 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java?rev=1626533&r1=1626532&r2=1626533&view=diff
==============================================================================
--- 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java
 (original)
+++ 
tomee/tomee/branches/tomee-1.7.x/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java
 Sun Sep 21 06:46:05 2014
@@ -21,18 +21,22 @@ import org.apache.catalina.Context;
 import org.apache.catalina.Engine;
 import org.apache.catalina.Host;
 import org.apache.catalina.Service;
-import org.apache.catalina.Wrapper;
 import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.ApplicationFilterConfig;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.server.cxf.rs.CxfRsHttpListener;
 import org.apache.openejb.server.httpd.HttpListener;
 import org.apache.openejb.server.httpd.util.HttpUtil;
 import org.apache.openejb.server.rest.RsRegistry;
-import org.apache.openejb.server.rest.RsServlet;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
+import org.apache.openejb.util.reflection.Reflections;
 import org.apache.tomee.catalina.environment.Hosts;
 import org.apache.tomee.loader.TomcatHelper;
 
+import java.lang.reflect.Constructor;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -99,11 +103,17 @@ public class TomcatRsRegistry implements
             throw new IllegalStateException("Invalid context '" + webContext + 
"'.  Cannot find context in host " + host.getName());
         }
 
-        final Wrapper wrapper = context.createWrapper();
-        final String name = "rest_" + listener.hashCode();
-        wrapper.setName(name);
-        wrapper.setServletClass(RsServlet.class.getName());
-        wrapper.setAsyncSupported(true);
+        final CxfRsHttpListener cxfRsHttpListener = 
findCxfRsHttpListener(listener);
+        final String description = "tomee-jaxrs-" + listener;
+
+        final FilterDef filterDef = new FilterDef();
+        filterDef.setAsyncSupported("true");
+        filterDef.setDescription(description);
+        filterDef.setFilterName(description);
+        filterDef.setDisplayName(description);
+        filterDef.setFilter(new CXFJAXRSFilter(cxfRsHttpListener, 
context.findWelcomeFiles()));
+        filterDef.setFilterClass(CXFJAXRSFilter.class.getName());
+        context.addFilterDef(filterDef);
 
         String mapping = completePath;
         if (!completePath.endsWith("/*")) { // respect servlet spec (!= from 
our embedded listeners)
@@ -113,13 +123,15 @@ public class TomcatRsRegistry implements
             mapping = mapping + "/*";
         }
 
-        context.addChild(wrapper);
-        wrapper.addMapping(removeWebContext(webContext, mapping));
-        context.addServletMapping(mapping, name);
-
-        final String listenerId = wrapper.getName() + 
RsServlet.class.getName() + listener.hashCode();
-        wrapper.addInitParameter(HttpListener.class.getName(), listenerId);
-        context.getServletContext().setAttribute(listenerId, listener);
+        final String urlPattern = removeWebContext(webContext, mapping);
+        cxfRsHttpListener.setUrlPattern(urlPattern.substring(0, 
urlPattern.length() - 1));
+
+        final FilterMap filterMap = new FilterMap();
+        filterMap.addURLPattern(urlPattern);
+        filterMap.setFilterName(filterDef.getFilterName());
+        context.addFilterMap(filterMap);
+
+        addFilterConfig(context, filterDef);
 
         path = address(connectors, host.getName(), webContext);
         final String key = address(connectors, host.getName(), completePath);
@@ -128,12 +140,23 @@ public class TomcatRsRegistry implements
         return new AddressInfo(path, key);
     }
 
-    private static Context findContext(final Container host, final String 
webContext) {
-        Context webapp = Context.class.cast(host.findChild(webContext));
-        if (webapp == null && "/".equals(webContext)) { // ROOT
-            webapp = Context.class.cast(host.findChild(""));
+    private void addFilterConfig(final Context context, final FilterDef 
filterDef) {
+        // hack to force filter to get a config otherwise it is ignored in the 
http routing
+        try {
+            final Constructor<ApplicationFilterConfig> cons = 
ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, 
FilterDef.class);
+            if (!cons.isAccessible()) {
+                cons.setAccessible(true);
+            }
+            final ApplicationFilterConfig config = cons.newInstance(context, 
filterDef);
+            ((Map<String, ApplicationFilterConfig>) Reflections.get(context, 
"filterConfigs")).put(filterDef.getFilterName(), config);
+        } catch (final Exception e) {
+            throw new IllegalStateException(e);
         }
-        return webapp;
+    }
+
+    private CxfRsHttpListener findCxfRsHttpListener(final HttpListener 
listener) {
+        // can we have some unwrapping to do here? normally no
+        return CxfRsHttpListener.class.cast(listener);
     }
 
     private static String removeWebContext(final String webContext, final 
String completePath) {
@@ -143,6 +166,14 @@ public class TomcatRsRegistry implements
         return completePath.substring(webContext.length());
     }
 
+    private static Context findContext(final Container host, final String 
webContext) {
+        Context webapp = Context.class.cast(host.findChild(webContext));
+        if (webapp == null && "/".equals(webContext)) { // ROOT
+            webapp = Context.class.cast(host.findChild(""));
+        }
+        return webapp;
+    }
+
     private static String address(final Collection<Connector> connectors, 
final String host, final String path) {
         final List<String> addresses = new ArrayList<String>();
         for (final Connector connector : connectors) {


Reply via email to