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) {