diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http')
29 files changed, 1298 insertions, 674 deletions
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelper.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelper.java new file mode 100644 index 000000000..04fc3e6db --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelper.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) Jan. 27, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal; + +import java.net.URL; +import org.eclipse.equinox.http.servlet.internal.util.Const; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpContext; +import org.osgi.service.http.context.ServletContextHelper; + +public class DefaultServletContextHelper extends ServletContextHelper implements HttpContext { + private final Bundle bundle; + public DefaultServletContextHelper(Bundle bundle) { + super(bundle); + this.bundle = bundle; + } + + @Override + public URL getResource(String name) { + if (name != null) { + if (name.startsWith(Const.SLASH)) { + name = name.substring(1); + } + + return bundle.getResource(name); + } + return null; + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelperFactory.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelperFactory.java new file mode 100644 index 000000000..ba1358b78 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/DefaultServletContextHelperFactory.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) Jan. 27, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal; + +import org.osgi.framework.*; +import org.osgi.service.http.context.ServletContextHelper; + +public class DefaultServletContextHelperFactory implements ServiceFactory<ServletContextHelper> { + @Override + public ServletContextHelper getService( + Bundle bundle, + ServiceRegistration<ServletContextHelper> registration) { + return new DefaultServletContextHelper(bundle); + } + + @Override + public void ungetService( + Bundle bundle, + ServiceRegistration<ServletContextHelper> registration, + ServletContextHelper service) { + // do nothing + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceImpl.java index 0ba942053..296235d45 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2017 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2019 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,59 +16,41 @@ package org.eclipse.equinox.http.servlet.internal; -import java.io.IOException; -import java.net.URL; import java.security.*; import java.util.Dictionary; -import javax.servlet.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import java.util.Hashtable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletException; import org.eclipse.equinox.http.servlet.ExtendedHttpService; +import org.eclipse.equinox.http.servlet.internal.context.WrappedHttpContext; +import org.eclipse.equinox.http.servlet.internal.util.Const; import org.eclipse.equinox.http.servlet.internal.util.Throw; -import org.osgi.framework.Bundle; +import org.osgi.framework.*; import org.osgi.service.http.*; +import org.osgi.service.http.context.ServletContextHelper; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; public class HttpServiceImpl implements HttpService, ExtendedHttpService { + private static AtomicLong legacyIdGenerator = new AtomicLong(0); + final Bundle bundle; //The bundle associated with this instance of http service final HttpServiceRuntimeImpl httpServiceRuntime; - private boolean shutdown = false; // We prevent use of this instance if HttpServiceFactory.ungetService has called unregisterAliases. - - class DefaultHttpContext implements HttpContext { - /** - * @throws IOException - */ - @Override - public boolean handleSecurity( - HttpServletRequest request, HttpServletResponse response) - throws IOException { - return true; - } - - @Override - public URL getResource(String name) { - if (name != null) { - if (name.startsWith("/")) { //$NON-NLS-1$ - name = name.substring(1); - } + private volatile boolean shutdown = false; // We prevent use of this instance if HttpServiceFactory.ungetService has called unregisterAliases. - return bundle.getResource(name); - } - return null; - } - - @Override - public String getMimeType(String name) { - return null; - } - - } + private final ConcurrentMap<HttpContext, ServiceReference<DefaultServletContextHelper>> contextMap = new ConcurrentHashMap<HttpContext, ServiceReference<DefaultServletContextHelper>>(); + private final ServiceReference<DefaultServletContextHelper> defaultHttpContextReference; public HttpServiceImpl( Bundle bundle, HttpServiceRuntimeImpl httpServiceRuntime) { this.bundle = bundle; this.httpServiceRuntime = httpServiceRuntime; + defaultHttpContextReference = this.bundle.getBundleContext().getServiceReference(DefaultServletContextHelper.class); } /** @@ -77,27 +59,31 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { public synchronized HttpContext createDefaultHttpContext() { checkShutdown(); - return new DefaultHttpContext(); + DefaultServletContextHelper defaultServletContextHelper = bundle.getBundleContext().getService(defaultHttpContextReference); + + contextMap.putIfAbsent(defaultServletContextHelper, defaultHttpContextReference); + + return defaultServletContextHelper; } /** - * @throws ServletException + * @throws ServletException * @see ExtendedHttpService#registerFilter(String, Filter, Dictionary, HttpContext) */ public synchronized void registerFilter( - final String alias, final Filter filter, + final String alias, final Filter filter, final Dictionary<String, String> initparams, HttpContext httpContext) throws ServletException { checkShutdown(); - - final HttpContext finalHttpContext = httpContext == null ? createDefaultHttpContext() : httpContext; + httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); + final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws ServletException { - httpServiceRuntime.registerHttpServiceFilter(bundle, alias, filter, initparams, finalHttpContext); + httpServiceRuntime.registerHttpServiceFilter(bundle, alias, filter, initparams, serviceReference); return null; } }); @@ -109,7 +95,7 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { } /** - * @throws NamespaceException + * @throws NamespaceException * @see HttpService#registerResources(String, String, HttpContext) */ public synchronized void registerResources( @@ -117,12 +103,13 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { throws NamespaceException { checkShutdown(); - final HttpContext finalHttpContext = httpContext == null ? createDefaultHttpContext() : httpContext; + httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); + final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws NamespaceException { - httpServiceRuntime.registerHttpServiceResources(bundle, alias, name, finalHttpContext); + httpServiceRuntime.registerHttpServiceResources(bundle, alias, name, serviceReference); return null; } }); @@ -133,22 +120,23 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { } /** - * @throws ServletException - * @throws NamespaceException + * @throws ServletException + * @throws NamespaceException * @see HttpService#registerServlet(String, Servlet, Dictionary, HttpContext) */ public synchronized void registerServlet( - final String alias, final Servlet servlet, + final String alias, final Servlet servlet, final Dictionary initparams, HttpContext httpContext) throws ServletException, NamespaceException { checkShutdown(); - final HttpContext finalHttpContext = httpContext == null ? createDefaultHttpContext() : httpContext; + httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); + final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws NamespaceException, ServletException { - httpServiceRuntime.registerHttpServiceServlet(bundle, alias, servlet, initparams, finalHttpContext); + httpServiceRuntime.registerHttpServiceServlet(bundle, alias, servlet, initparams, serviceReference); return null; } }); @@ -188,4 +176,29 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { "Service instance is already shutdown"); //$NON-NLS-1$ } } + + private long generateLegacyId() { + return legacyIdGenerator.getAndIncrement(); + } + + private HttpContext registerContext(HttpContext httpContext) { + ServiceReference<? extends HttpContext> serviceReference = contextMap.get(httpContext); + + if (serviceReference == null) { + Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, httpContext.getClass().getName().replaceAll("[^a-zA-Z_0-9\\-]", "_") + "-" + generateLegacyId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/"); //$NON-NLS-1$ + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, httpServiceRuntime.getTargetFilter()); + props.put(Const.EQUINOX_LEGACY_CONTEXT_HELPER, Boolean.TRUE); + props.put(Const.EQUINOX_LEGACY_HTTP_CONTEXT_INITIATING_ID, bundle.getBundleId()); + + @SuppressWarnings("unchecked") + ServiceRegistration<DefaultServletContextHelper> registration = (ServiceRegistration<DefaultServletContextHelper>)bundle.getBundleContext().registerService(ServletContextHelper.class.getName(), new WrappedHttpContext(httpContext, bundle), props); + + contextMap.put(httpContext, registration.getReference()); + } + + return httpContext; + } + } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceObjectRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceObjectRegistration.java index 72348f209..c78adbfc9 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceObjectRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceObjectRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) Dec 1, 2014 Liferay, Inc. + * Copyright (c) 2014, 2019 Liferay, Inc. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -9,27 +9,24 @@ * SPDX-License-Identifier: EPL-2.0 * * Contributors: - * Liferay, Inc. - initial API and implementation and/or initial + * Liferay, Inc. - initial API and implementation and/or initial * documentation ******************************************************************************/ package org.eclipse.equinox.http.servlet.internal; -import org.eclipse.equinox.http.servlet.internal.context.HttpContextHelperFactory; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceRegistration; public class HttpServiceObjectRegistration { public final Object serviceKey; public final ServiceRegistration<?> registration; - public final HttpContextHelperFactory factory; public final Bundle bundle; public HttpServiceObjectRegistration( Object serviceKey, ServiceRegistration<?> registration, - HttpContextHelperFactory factory, Bundle bundle) { + Bundle bundle) { this.serviceKey = serviceKey; this.registration = registration; - this.factory = factory; this.bundle = bundle; } } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java index 1ad919b95..a69f1117a 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,9 +16,8 @@ package org.eclipse.equinox.http.servlet.internal; import java.io.IOException; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; +import java.util.Map.Entry; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.*; import javax.servlet.Filter; @@ -26,7 +25,10 @@ import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer; import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO; -import org.eclipse.equinox.http.servlet.internal.context.*; +import org.eclipse.equinox.http.servlet.internal.context.ContextController; +import org.eclipse.equinox.http.servlet.internal.context.DispatchTargets; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedFailedServletContextDTO; import org.eclipse.equinox.http.servlet.internal.error.*; import org.eclipse.equinox.http.servlet.internal.servlet.HttpSessionTracker; import org.eclipse.equinox.http.servlet.internal.servlet.Match; @@ -34,7 +36,6 @@ import org.eclipse.equinox.http.servlet.internal.util.*; import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator; import org.osgi.framework.*; import org.osgi.framework.dto.ServiceReferenceDTO; -import org.osgi.service.http.HttpContext; import org.osgi.service.http.NamespaceException; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.HttpServiceRuntime; @@ -86,7 +87,8 @@ public class HttpServiceRuntimeImpl defaultContextProps.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE); defaultContextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, Const.SLASH); defaultContextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, this.targetFilter); - defaultContextReg = consumingContext.registerService(ServletContextHelper.class, new DefaultServletContextHelperFactory(), defaultContextProps); + defaultContextReg = consumingContext.registerService( + new String [] {ServletContextHelper.class.getName(), DefaultServletContextHelper.class.getName()}, new DefaultServletContextHelperFactory(), defaultContextProps); } @Override @@ -98,27 +100,9 @@ public class HttpServiceRuntimeImpl return result; } - String contextName = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME); - String contextPath = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH); - try { - if (contextName == null) { - throw new IllegalContextNameException( - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + " is null. Ignoring!", //$NON-NLS-1$ - DTOConstants.FAILURE_REASON_VALIDATION_FAILED); - } - - if (contextPath == null) { - throw new IllegalContextPathException( - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + " is null. Ignoring!", //$NON-NLS-1$ - DTOConstants.FAILURE_REASON_VALIDATION_FAILED); - } - - contextPath = adaptContextPath(contextPath, serviceReference); - ContextController contextController = new ContextController( - trackingContext, consumingContext, serviceReference, new ProxyContext(contextName, parentServletContext), - this, contextName, contextPath, httpSessionTracker); + trackingContext, consumingContext, serviceReference, parentServletContext, this); controllerMap.put(serviceReference, contextController); @@ -127,18 +111,18 @@ public class HttpServiceRuntimeImpl catch (HttpWhiteboardFailureException hwfe) { parentServletContext.log(hwfe.getMessage(), hwfe); - recordFailedServletContextDTO(serviceReference, contextName, contextPath, hwfe.getFailureReason()); + recordFailedServletContextDTO(serviceReference, 0, hwfe.getFailureReason()); } catch (Exception e) { parentServletContext.log(e.getMessage(), e); - recordFailedServletContextDTO(serviceReference, contextName, contextPath, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + recordFailedServletContextDTO(serviceReference, 0, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); } return result; } - private String adaptContextPath(String contextPath, ServiceReference<ServletContextHelper> helper) { + public String adaptContextPath(String contextPath, ServiceReference<ServletContextHelper> helper) { ContextPathCustomizer pathAdaptor = contextPathCustomizerHolder.getHighestRanked(); if (pathAdaptor != null) { String contextPrefix = pathAdaptor.getContextPathPrefix(helper); @@ -164,8 +148,16 @@ public class HttpServiceRuntimeImpl return null; } + public boolean isDefaultContext(ContextController contextController) { + ServiceReference<?> thisReference = defaultContextReg.getReference(); + ServiceReference<ServletContextHelper> contextReference = contextController.getServiceReference(); + if (thisReference == null) throw new NullPointerException("Default Context Service reference is null. " + this); //$NON-NLS-1$ + if (contextReference == null) throw new NullPointerException("Context Service reference is null. " + contextController); //$NON-NLS-1$ + return thisReference.equals(contextReference); + } + @Override - public RequestInfoDTO calculateRequestInfoDTO(String path) { + public synchronized RequestInfoDTO calculateRequestInfoDTO(String path) { RequestInfoDTO requestInfoDTO = new RequestInfoDTO(); requestInfoDTO.path = path; @@ -180,7 +172,7 @@ public class HttpServiceRuntimeImpl return requestInfoDTO; } - public void destroy() { + public synchronized void destroy() { invalidatorReg.unregister(); defaultContextReg.unregister(); @@ -197,14 +189,13 @@ public class HttpServiceRuntimeImpl failedServletDTOs.clear(); httpSessionTracker.clear(); + registeredObjects.clear(); httpSessionTracker = null; attributes = null; trackingContext = null; consumingContext = null; - legacyIdGenerator = null; parentServletContext = null; - registeredObjects = null; contextServiceTracker = null; contextPathCustomizerHolder = null; } @@ -229,26 +220,43 @@ public class HttpServiceRuntimeImpl requestInfoDTO); } - if (dispatchTargets == null) { + if (dispatchTargets == null && !Const.SLASH.equals(pathString)) { // regex match dispatchTargets = getDispatchTargets( requestURI, null, queryString, Match.REGEX, requestInfoDTO); } if (dispatchTargets == null) { - // handle '/' aliases + // handle with servlet mapped to '/' + // the servletpath is the requestURI minus the contextpath and the pathinfo is null dispatchTargets = getDispatchTargets( requestURI, null, queryString, Match.DEFAULT_SERVLET, requestInfoDTO); } + if (dispatchTargets == null && Const.SLASH.equals(pathString)) { + // handle with servlet mapped to '' (empty string) + // the pathinfo is '/' and the servletpath and contextpath are the empty string ("") + dispatchTargets = getDispatchTargets( + requestURI, null, queryString, Match.CONTEXT_ROOT, + requestInfoDTO); + } + return dispatchTargets; } + public HttpSessionTracker getHttpSessionTracker() { + return httpSessionTracker; + } + public Set<Object> getRegisteredObjects() { return registeredObjects; } + public String getTargetFilter() { + return targetFilter; + } + public List<String> getHttpServiceEndpoints() { return StringPlus.from( attributes.get( @@ -256,24 +264,33 @@ public class HttpServiceRuntimeImpl } @Override - public RuntimeDTO getRuntimeDTO() { + public synchronized RuntimeDTO getRuntimeDTO() { RuntimeDTO runtimeDTO = new RuntimeDTO(); - runtimeDTO.serviceDTO = getServiceDTO(); - - // TODO FailedErrorDTOs - - runtimeDTO.failedErrorPageDTOs = null; + runtimeDTO.failedErrorPageDTOs = getFailedErrorPageDTOs(); runtimeDTO.failedFilterDTOs = getFailedFilterDTOs(); runtimeDTO.failedListenerDTOs = getFailedListenerDTOs(); runtimeDTO.failedResourceDTOs = getFailedResourceDTOs(); runtimeDTO.failedServletContextDTOs = getFailedServletContextDTO(); runtimeDTO.failedServletDTOs = getFailedServletDTOs(); + runtimeDTO.serviceDTO = getServiceDTO(); runtimeDTO.servletContextDTOs = getServletContextDTOs(); return runtimeDTO; } + private FailedErrorPageDTO[] getFailedErrorPageDTOs() { + Collection<FailedErrorPageDTO> fepDTOs = failedErrorPageDTOs.values(); + + List<FailedErrorPageDTO> copies = new ArrayList<FailedErrorPageDTO>(); + + for (FailedErrorPageDTO failedErrorPageDTO : fepDTOs) { + copies.add(DTOUtil.clone(failedErrorPageDTO)); + } + + return copies.toArray(new FailedErrorPageDTO[0]); + } + private ServiceReferenceDTO getServiceDTO() { ServiceReferenceDTO[] services = consumingContext.getBundle().adapt(ServiceReferenceDTO[].class); for (ServiceReferenceDTO serviceDTO : services) { @@ -303,22 +320,31 @@ public class HttpServiceRuntimeImpl return true; } - org.osgi.framework.Filter targetFilter; + org.osgi.framework.Filter whiteboardTargetFilter; try { - targetFilter = FrameworkUtil.createFilter(target); + whiteboardTargetFilter = FrameworkUtil.createFilter(target); } catch (InvalidSyntaxException ise) { throw new IllegalArgumentException(ise); } - if (targetFilter.matches(attributes)) { + if (whiteboardTargetFilter.matches(attributes)) { return true; } return false; } + public boolean matchesAnyContext(ServiceReference<?> serviceReference) { + for (ContextController contextController : controllerMap.values()) { + if (contextController.matches(serviceReference)) { + return true; + } + } + return false; + } + @Override public synchronized void modifiedService( ServiceReference<ServletContextHelper> serviceReference, @@ -336,10 +362,16 @@ public class HttpServiceRuntimeImpl ContextController contextController = contextControllerRef.get(); if (contextController != null) { + Iterator<Entry<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO>> iterator = failedServletContextDTOs.entrySet().iterator(); + while (iterator.hasNext()) { + if (iterator.next().getValue().shadowingServiceId == contextController.getServiceId()) { + iterator.remove(); + } + } contextController.destroy(); } - controllerMap.remove(serviceReference); failedServletContextDTOs.remove(serviceReference); + controllerMap.remove(serviceReference); trackingContext.ungetService(serviceReference); } @@ -373,8 +405,8 @@ public class HttpServiceRuntimeImpl return null; } - long generateLegacyId() { - return legacyIdGenerator.getAndIncrement(); + public Collection<ContextController> getContextControllers() { + return controllerMap.values(); } public DispatchTargets getDispatchTargets( @@ -398,9 +430,9 @@ public class HttpServiceRuntimeImpl String servletPath = requestURI; String pathInfo = null; - if (match == Match.DEFAULT_SERVLET) { - pathInfo = servletPath; - servletPath = Const.SLASH; + if (match == Match.CONTEXT_ROOT) { + pathInfo = Const.SLASH; + servletPath = Const.BLANK; } do { @@ -415,7 +447,7 @@ public class HttpServiceRuntimeImpl } } - if (match == Match.EXACT) { + if ((match == Match.EXACT) || (match == Match.CONTEXT_ROOT) || (match == Match.DEFAULT_SERVLET)) { break; } @@ -444,7 +476,7 @@ public class HttpServiceRuntimeImpl copies.add(DTOUtil.clone(failedFilterDTO)); } - return copies.toArray(new FailedFilterDTO[copies.size()]); + return copies.toArray(new FailedFilterDTO[0]); } private FailedListenerDTO[] getFailedListenerDTOs() { @@ -456,10 +488,10 @@ public class HttpServiceRuntimeImpl copies.add(DTOUtil.clone(failedListenerDTO)); } - return copies.toArray(new FailedListenerDTO[copies.size()]); + return copies.toArray(new FailedListenerDTO[0]); } - private FailedResourceDTO[] getFailedResourceDTOs() { + public FailedResourceDTO[] getFailedResourceDTOs() { Collection<FailedResourceDTO> frDTOs = failedResourceDTOs.values(); List<FailedResourceDTO> copies = new ArrayList<FailedResourceDTO>(); @@ -468,11 +500,11 @@ public class HttpServiceRuntimeImpl copies.add(DTOUtil.clone(failedResourceDTO)); } - return copies.toArray(new FailedResourceDTO[copies.size()]); + return copies.toArray(new FailedResourceDTO[0]); } private FailedServletContextDTO[] getFailedServletContextDTO() { - Collection<FailedServletContextDTO> fscDTOs = failedServletContextDTOs.values(); + Collection<ExtendedFailedServletContextDTO> fscDTOs = failedServletContextDTOs.values(); List<FailedServletContextDTO> copies = new ArrayList<FailedServletContextDTO>(); @@ -480,7 +512,7 @@ public class HttpServiceRuntimeImpl copies.add(DTOUtil.clone(failedServletContextDTO)); } - return copies.toArray(new FailedServletContextDTO[copies.size()]); + return copies.toArray(new FailedServletContextDTO[0]); } private FailedServletDTO[] getFailedServletDTOs() { @@ -492,28 +524,27 @@ public class HttpServiceRuntimeImpl copies.add(DTOUtil.clone(failedServletDTO)); } - return copies.toArray(new FailedServletDTO[copies.size()]); + return copies.toArray(new FailedServletDTO[0]); } - private ServletContextDTO[] getServletContextDTOs() { + public ServletContextDTO[] getServletContextDTOs() { List<ServletContextDTO> servletContextDTOs = new ArrayList<ServletContextDTO>(); for (ContextController contextController : controllerMap.values()) { servletContextDTOs.add(contextController.getServletContextDTO()); } - return servletContextDTOs.toArray( - new ServletContextDTO[servletContextDTOs.size()]); + return servletContextDTOs.toArray(new ServletContextDTO[0]); } public void registerHttpServiceFilter( - Bundle bundle, String alias, Filter filter, Dictionary<String, String> initparams, HttpContext httpContext) throws ServletException { + Bundle bundle, String alias, Filter filter, Dictionary<String, String> initparams, ServiceReference<? extends ServletContextHelper> serviceReference) { if (alias == null) { - throw new IllegalArgumentException("Alias cannot be null"); + throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ } if (filter == null) { - throw new IllegalArgumentException("Filter cannot be null"); + throw new IllegalArgumentException("Filter cannot be null"); //$NON-NLS-1$ } ContextController.checkPattern(alias); @@ -539,7 +570,6 @@ public class HttpServiceRuntimeImpl if ((initparams != null) && (initparams.get(Const.FILTER_NAME) != null)) { filterName = initparams.get(Const.FILTER_NAME); } - HttpContextHelperFactory factory = getOrRegisterHttpContextHelperFactory(bundle, httpContext); HttpServiceObjectRegistration objectRegistration = null; ServiceRegistration<Filter> registration = null; @@ -548,8 +578,7 @@ public class HttpServiceRuntimeImpl props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, targetFilter); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, alias); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME, filterName); - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + Const.EQUINOX_LEGACY_CONTEXT_HELPER + "=true)"); //$NON-NLS-1$ //$NON-NLS-2$ - props.put(Const.EQUINOX_LEGACY_CONTEXT_SELECT, factory.getFilter()); + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(serviceReference)); props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader()); props.put(Constants.SERVICE_RANKING, findFilterPriority(initparams)); fillInitParams(props, initparams, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX); @@ -560,7 +589,7 @@ public class HttpServiceRuntimeImpl // check that init got called and did not throw an exception filterFactory.checkForError(); - objectRegistration = new HttpServiceObjectRegistration(filter, registration, factory, bundle); + objectRegistration = new HttpServiceObjectRegistration(filter, registration, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { objectRegistrations = new HashSet<HttpServiceObjectRegistration>(); @@ -571,8 +600,6 @@ public class HttpServiceRuntimeImpl } finally { if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) { // something bad happened above (likely going to throw a runtime exception) - // need to clean up the factory reference - decrementFactoryUseCount(factory); if (registration != null) { registration.unregister(); } @@ -617,17 +644,17 @@ public class HttpServiceRuntimeImpl } throw new IllegalArgumentException( - "filter-priority must be an integer between -1000 and 1000 but " + - "was: " + filterPriority); + "filter-priority must be an integer between -1000 and 1000 but " + //$NON-NLS-1$ + "was: " + filterPriority); //$NON-NLS-1$ } public void registerHttpServiceResources( - Bundle bundle, String alias, String name, HttpContext httpContext) throws NamespaceException { + Bundle bundle, String alias, String name, ServiceReference<? extends ServletContextHelper> serviceReference) throws NamespaceException { if (alias == null) { - throw new IllegalArgumentException("Alias cannot be null"); + throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ } if (name == null) { - throw new IllegalArgumentException("Name cannot be null"); + throw new IllegalArgumentException("Name cannot be null"); //$NON-NLS-1$ } String pattern = alias; if (pattern.startsWith("/*.")) { //$NON-NLS-1$ @@ -643,9 +670,9 @@ public class HttpServiceRuntimeImpl synchronized (legacyMappings) { HttpServiceObjectRegistration objectRegistration = null; - HttpContextHelperFactory factory = getOrRegisterHttpContextHelperFactory(bundle, httpContext); + ServiceRegistration<?> registration = null; try { - String fullAlias = getFullAlias(alias, factory); + String fullAlias = getFullAlias(alias, serviceReference); HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias); if (existing != null) { throw new PatternInUseException(alias); @@ -654,11 +681,11 @@ public class HttpServiceRuntimeImpl props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, targetFilter); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN, pattern); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX, name); - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, factory.getFilter()); + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(serviceReference)); props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader()); - ServiceRegistration<?> registration = bundle.getBundleContext().registerService(String.class, "resource", props); //$NON-NLS-1$ - objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, factory, bundle); + registration = bundle.getBundleContext().registerService(String.class, "resource", props); //$NON-NLS-1$ + objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { @@ -678,19 +705,26 @@ public class HttpServiceRuntimeImpl if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) { // something bad happened above (likely going to throw a runtime exception) // need to clean up the factory reference - decrementFactoryUseCount(factory); + if (registration != null) { + registration.unregister(); + } } } } } + private Object getFilter(ServiceReference<? extends ServletContextHelper> serviceReference) { + String ctxName = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME); + return String.format("(%s=%s)", HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, ctxName); //$NON-NLS-1$ + } + public void registerHttpServiceServlet( - Bundle bundle, String alias, Servlet servlet, Dictionary<String, String> initparams, HttpContext httpContext) throws NamespaceException, ServletException{ + Bundle bundle, String alias, Servlet servlet, Dictionary<String, String> initparams, ServiceReference<? extends ServletContextHelper> serviceReference) throws NamespaceException, ServletException{ if (alias == null) { - throw new IllegalArgumentException("Alias cannot be null"); + throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ } if (servlet == null) { - throw new IllegalArgumentException("Servlet cannot be null"); + throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$ } // check the pattern against the original input @@ -713,9 +747,8 @@ public class HttpServiceRuntimeImpl } HttpServiceObjectRegistration objectRegistration = null; ServiceRegistration<Servlet> registration = null; - HttpContextHelperFactory factory = getOrRegisterHttpContextHelperFactory(bundle, httpContext); try { - String fullAlias = getFullAlias(alias, factory); + String fullAlias = getFullAlias(alias, serviceReference); HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias); if (existing != null) { throw new PatternInUseException(alias); @@ -729,7 +762,7 @@ public class HttpServiceRuntimeImpl props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, targetFilter); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, pattern); props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, servletName); - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, factory.getFilter()); + props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(serviceReference)); props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader()); fillInitParams(props, initparams, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); @@ -739,7 +772,7 @@ public class HttpServiceRuntimeImpl // check that init got called and did not throw an exception legacyServlet.checkForError(); - objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, factory, bundle); + objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { @@ -760,7 +793,6 @@ public class HttpServiceRuntimeImpl if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) { // something bad happened above (likely going to throw a runtime exception) // need to clean up the factory reference - decrementFactoryUseCount(factory); if (registration != null) { registration.unregister(); } @@ -769,8 +801,9 @@ public class HttpServiceRuntimeImpl } } - private String getFullAlias(String alias, HttpContextHelperFactory factory) { - AtomicReference<ContextController> controllerRef = contextServiceTracker.getService(factory.getServiceReference()); + private String getFullAlias(String alias, ServiceReference<? extends ServletContextHelper> serviceReference) { + @SuppressWarnings("unchecked") + AtomicReference<ContextController> controllerRef = contextServiceTracker.getService((ServiceReference<ServletContextHelper>)serviceReference); if (controllerRef != null) { ContextController controller = controllerRef.get(); if (controller != null) { @@ -802,7 +835,6 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } - decrementFactoryUseCount(objectRegistration.factory); legacyMappings.remove(aliasCustomization); } @@ -824,7 +856,6 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } - decrementFactoryUseCount(objectRegistration.factory); legacyMappings.remove(filter); } } @@ -840,43 +871,12 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } - decrementFactoryUseCount(objectRegistration.factory); legacyMappings.remove(objectRegistration.serviceKey); } } } } - private HttpContextHelperFactory getOrRegisterHttpContextHelperFactory(Bundle initiatingBundle, HttpContext httpContext) { - if (httpContext == null) { - throw new NullPointerException("A null HttpContext is not allowed."); //$NON-NLS-1$ - } - synchronized (httpContextHelperFactories) { - HttpContextHelperFactory factory = httpContextHelperFactories.get(httpContext); - if (factory == null) { - factory = new HttpContextHelperFactory(httpContext); - Dictionary<String, Object> props = new Hashtable<String, Object>(); - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, httpContext.getClass().getName().replaceAll("[^a-zA-Z_0-9\\-]", "_") + "-" + generateLegacyId()); //$NON-NLS-1$ - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/"); //$NON-NLS-1$ - props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, targetFilter); - props.put(Const.EQUINOX_LEGACY_CONTEXT_HELPER, Boolean.TRUE); - props.put(Const.EQUINOX_LEGACY_HTTP_CONTEXT_INITIATING_ID, initiatingBundle.getBundleId()); - factory.setRegistration(consumingContext.registerService(ServletContextHelper.class, factory, props)); - httpContextHelperFactories.put(httpContext, factory); - } - factory.incrementUseCount(); - return factory; - } - } - - private void decrementFactoryUseCount(HttpContextHelperFactory factory) { - synchronized (httpContextHelperFactories) { - if (factory.decrementUseCount() == 0) { - httpContextHelperFactories.remove(factory.getHttpContext()); - } - } - } - private static org.osgi.framework.Filter createResourceFilter(BundleContext context) { StringBuilder sb = new StringBuilder(); @@ -980,6 +980,17 @@ public class HttpServiceRuntimeImpl return resourceServiceFilter; } + public void recordFailedErrorPageDTO( + ServiceReference<?> serviceReference, + FailedErrorPageDTO failedErrorPageDTO) { + + if (failedErrorPageDTOs.containsKey(serviceReference)) { + return; + } + + failedErrorPageDTOs.put(serviceReference, failedErrorPageDTO); + } + public void recordFailedFilterDTO( ServiceReference<Filter> serviceReference, FailedFilterDTO failedFilterDTO) { @@ -1003,7 +1014,7 @@ public class HttpServiceRuntimeImpl } public void recordFailedResourceDTO( - ServiceReference<Object> serviceReference, FailedResourceDTO failedResourceDTO) { + ServiceReference<?> serviceReference, FailedResourceDTO failedResourceDTO) { if (failedResourceDTOs.containsKey(serviceReference)) { return; @@ -1012,30 +1023,30 @@ public class HttpServiceRuntimeImpl failedResourceDTOs.put(serviceReference, failedResourceDTO); } - private void recordFailedServletContextDTO( - ServiceReference<ServletContextHelper> serviceReference, String contextName, - String contextPath, int failureReason) { + public void recordFailedServletContextDTO( + ServiceReference<ServletContextHelper> serviceReference, long shadowingServiceId, int failureReason) { - FailedServletContextDTO failedServletContextDTO = new FailedServletContextDTO(); + ExtendedFailedServletContextDTO failedServletContextDTO = new ExtendedFailedServletContextDTO(); failedServletContextDTO.attributes = Collections.emptyMap(); - failedServletContextDTO.contextPath = contextPath; - failedServletContextDTO.errorPageDTOs = new ErrorPageDTO[0]; + failedServletContextDTO.contextPath = String.valueOf(serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH)); + failedServletContextDTO.errorPageDTOs = new ExtendedErrorPageDTO[0]; failedServletContextDTO.failureReason = failureReason; failedServletContextDTO.filterDTOs = new FilterDTO[0]; failedServletContextDTO.initParams = ServiceProperties.parseInitParams( serviceReference, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX); failedServletContextDTO.listenerDTOs = new ListenerDTO[0]; - failedServletContextDTO.name = contextName; + failedServletContextDTO.name = String.valueOf(serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME)); failedServletContextDTO.resourceDTOs = new ResourceDTO[0]; failedServletContextDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); failedServletContextDTO.servletDTOs = new ServletDTO[0]; + failedServletContextDTO.shadowingServiceId = shadowingServiceId; failedServletContextDTOs.put(serviceReference, failedServletContextDTO); } public void recordFailedServletDTO( - ServiceReference<Servlet> serviceReference, + ServiceReference<?> serviceReference, ExtendedFailedServletDTO failedServletDTO) { if (failedServletDTOs.containsKey(serviceReference)) { @@ -1045,6 +1056,12 @@ public class HttpServiceRuntimeImpl failedServletDTOs.put(serviceReference, failedServletDTO); } + public void removeFailedErrorPageDTO( + ServiceReference<Servlet> serviceReference) { + + failedErrorPageDTOs.remove(serviceReference); + } + public void removeFailedFilterDTO( ServiceReference<Filter> serviceReference) { @@ -1063,13 +1080,13 @@ public class HttpServiceRuntimeImpl failedResourceDTOs.remove(serviceReference); } - public void removeFailedServletDTOs( + public void removeFailedServletDTO( ServiceReference<Servlet> serviceReference) { failedServletDTOs.remove(serviceReference); } - public void fireSessionIdChanged(String oldSessionId) { + public synchronized void fireSessionIdChanged(String oldSessionId) { for (ContextController contextController : controllerMap.values()) { contextController.fireSessionIdChanged(oldSessionId); } @@ -1081,7 +1098,7 @@ public class HttpServiceRuntimeImpl private Map<String, Object> attributes; private final String targetFilter; - private final ServiceRegistration<ServletContextHelper> defaultContextReg; + private final ServiceRegistration<?> defaultContextReg; private ServletContext parentServletContext; private BundleContext trackingContext; @@ -1093,32 +1110,30 @@ public class HttpServiceRuntimeImpl private final org.osgi.framework.Filter listenerServiceFilter; // BEGIN of old HttpService support - private Map<HttpContext, HttpContextHelperFactory> httpContextHelperFactories = - Collections.synchronizedMap(new HashMap<HttpContext, HttpContextHelperFactory>()); - private Map<Object, HttpServiceObjectRegistration> legacyMappings = + private final Map<Object, HttpServiceObjectRegistration> legacyMappings = Collections.synchronizedMap(new HashMap<Object, HttpServiceObjectRegistration>()); - private Map<Bundle, Set<HttpServiceObjectRegistration>> bundleRegistrations = + private final Map<Bundle, Set<HttpServiceObjectRegistration>> bundleRegistrations = new HashMap<Bundle, Set<HttpServiceObjectRegistration>>(); - private Map<Bundle, Map<String, String>> bundleAliasCustomizations = new HashMap<Bundle, Map<String,String>>(); + private final Map<Bundle, Map<String, String>> bundleAliasCustomizations = new HashMap<Bundle, Map<String,String>>(); // END of old HttpService support - private ConcurrentMap<ServiceReference<ServletContextHelper>, ContextController> controllerMap = - new ConcurrentHashMap<ServiceReference<ServletContextHelper>, ContextController>(); + private final ConcurrentMap<ServiceReference<ServletContextHelper>, ContextController> controllerMap = + new ConcurrentSkipListMap<ServiceReference<ServletContextHelper>, ContextController>(Collections.reverseOrder()); + private final ConcurrentMap<ServiceReference<?>, FailedErrorPageDTO> failedErrorPageDTOs = + new ConcurrentHashMap<ServiceReference<?>, FailedErrorPageDTO>(); private final ConcurrentMap<ServiceReference<Filter>, FailedFilterDTO> failedFilterDTOs = new ConcurrentHashMap<ServiceReference<Filter>, FailedFilterDTO>(); private final ConcurrentMap<ServiceReference<EventListener>, FailedListenerDTO> failedListenerDTOs = new ConcurrentHashMap<ServiceReference<EventListener>, FailedListenerDTO>(); - private final ConcurrentMap<ServiceReference<Object>, FailedResourceDTO> failedResourceDTOs = - new ConcurrentHashMap<ServiceReference<Object>, FailedResourceDTO>(); - private final ConcurrentMap<ServiceReference<ServletContextHelper>, FailedServletContextDTO> failedServletContextDTOs = - new ConcurrentHashMap<ServiceReference<ServletContextHelper>, FailedServletContextDTO>(); - private final ConcurrentMap<ServiceReference<Servlet>, ExtendedFailedServletDTO> failedServletDTOs = - new ConcurrentHashMap<ServiceReference<Servlet>, ExtendedFailedServletDTO>(); - - private AtomicLong legacyIdGenerator = new AtomicLong(0); + private final ConcurrentMap<ServiceReference<?>, FailedResourceDTO> failedResourceDTOs = + new ConcurrentHashMap<ServiceReference<?>, FailedResourceDTO>(); + private final ConcurrentMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO> failedServletContextDTOs = + new ConcurrentHashMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO>(); + private final ConcurrentMap<ServiceReference<?>, ExtendedFailedServletDTO> failedServletDTOs = + new ConcurrentHashMap<ServiceReference<?>, ExtendedFailedServletDTO>(); - private Set<Object> registeredObjects = Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>()); + private final Set<Object> registeredObjects = Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>()); private ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker; private ServiceTracker<ContextPathCustomizer, ContextPathCustomizer> contextPathAdaptorTracker; @@ -1126,29 +1141,6 @@ public class HttpServiceRuntimeImpl private HttpSessionTracker httpSessionTracker; private final ServiceRegistration<HttpSessionInvalidator> invalidatorReg; - static class DefaultServletContextHelperFactory implements ServiceFactory<ServletContextHelper> { - @Override - public ServletContextHelper getService( - Bundle bundle, - ServiceRegistration<ServletContextHelper> registration) { - return new DefaultServletContextHelper(bundle); - } - - @Override - public void ungetService( - Bundle bundle, - ServiceRegistration<ServletContextHelper> registration, - ServletContextHelper service) { - // do nothing - } - } - - static class DefaultServletContextHelper extends ServletContextHelper { - public DefaultServletContextHelper(Bundle b) { - super(b); - } - } - static class LegacyServiceObject { final AtomicReference<Exception> error = new AtomicReference<Exception>(new ServletException("The init() method was never called.")); //$NON-NLS-1$ public void checkForError() { @@ -1333,4 +1325,16 @@ public class HttpServiceRuntimeImpl } } + public boolean failedResourceDTO(ServiceReference<?> serviceReference) { + return failedResourceDTOs.containsKey(serviceReference); + } + + public boolean failedServletDTO(ServiceReference<?> serviceReference) { + return failedServletDTOs.containsKey(serviceReference); + } + + public boolean failedErrorPageDTO(ServiceReference<?> serviceReference) { + return failedErrorPageDTOs.containsKey(serviceReference); + } + } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java index 6d87145aa..16f115b5f 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Raymond Augé and others. + * Copyright (c) 2016, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,12 +21,16 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import javax.servlet.*; import javax.servlet.Filter; import javax.servlet.http.*; +import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO; import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; import org.eclipse.equinox.http.servlet.internal.customizer.*; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO.ErrorCodeType; import org.eclipse.equinox.http.servlet.internal.error.*; import org.eclipse.equinox.http.servlet.internal.registration.*; import org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration; @@ -50,20 +54,28 @@ public class ContextController { final Bundle bundle; final long serviceId; final int serviceRanking; + final ClassLoader legacyTCCL; public ServiceHolder(ServiceObjects<S> serviceObjects) { this.serviceObjects = serviceObjects; this.bundle = serviceObjects.getServiceReference().getBundle(); this.service = serviceObjects.getService(); - this.serviceId = (Long) serviceObjects.getServiceReference().getProperty(Constants.SERVICE_ID); + this.legacyTCCL = (ClassLoader)serviceObjects.getServiceReference().getProperty(Const.EQUINOX_LEGACY_TCCL_PROP); + Long serviceIdProp = (Long)serviceObjects.getServiceReference().getProperty(Constants.SERVICE_ID); + if (legacyTCCL != null) { + // this is a legacy registration; use a negative id for the DTO + serviceIdProp = -serviceIdProp; + } + this.serviceId = serviceIdProp; Integer rankProp = (Integer) serviceObjects.getServiceReference().getProperty(Constants.SERVICE_RANKING); this.serviceRanking = rankProp == null ? 0 : rankProp.intValue(); } - public ServiceHolder(S service, Bundle bundle, long serviceId, int serviceRanking) { + public ServiceHolder(S service, Bundle bundle, long serviceId, int serviceRanking, ClassLoader legacyTCCL) { this.service = service; this.bundle = bundle; this.serviceObjects = null; this.serviceId = serviceId; this.serviceRanking = serviceRanking; + this.legacyTCCL = legacyTCCL; } public S get() { return service; @@ -72,6 +84,11 @@ public class ContextController { public Bundle getBundle() { return bundle; } + + public ClassLoader getLegacyTCCL() { + return legacyTCCL; + } + public void release() { if (serviceObjects != null && service != null) { try { @@ -111,40 +128,21 @@ public class ContextController { public ContextController( BundleContext trackingContextParam, BundleContext consumingContext, - ServiceReference<ServletContextHelper> servletContextHelperRef, - ProxyContext proxyContext, HttpServiceRuntimeImpl httpServiceRuntime, - String contextName, String contextPath, HttpSessionTracker httpSessionTracker) { - - validate(contextName, contextPath); + ServiceReference<ServletContextHelper> serviceReference, + ServletContext parentServletContext, HttpServiceRuntimeImpl httpServiceRuntime) { - this.servletContextHelperRef = servletContextHelperRef; - - long serviceId = (Long)servletContextHelperRef.getProperty(Constants.SERVICE_ID); - - StringBuilder filterBuilder = new StringBuilder(); - filterBuilder.append('('); - filterBuilder.append(Constants.SERVICE_ID); - filterBuilder.append('='); - filterBuilder.append(serviceId); - filterBuilder.append(')'); - this.servletContextHelperRefFilter = filterBuilder.toString(); - this.proxyContext = proxyContext; + this.trackingContext = trackingContextParam; + this.consumingContext = consumingContext; + this.serviceReference = serviceReference; this.httpServiceRuntime = httpServiceRuntime; - this.contextName = contextName; - - if (contextPath.equals(Const.SLASH)) { - contextPath = Const.BLANK; - } - - this.contextPath = contextPath; - this.contextServiceId = serviceId; + this.contextName = validateName(); + this.contextPath = validatePath(); + this.proxyContext = new ProxyContext(contextName, parentServletContext); + this.contextServiceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); + this.servletContextHelperRefFilter = createFilter(contextServiceId); this.initParams = ServiceProperties.parseInitParams( - servletContextHelperRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX, proxyContext.getServletContext()); - - this.trackingContext = trackingContextParam; - this.consumingContext = consumingContext; - this.httpSessionTracker = httpSessionTracker; + serviceReference, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX, parentServletContext); listenerServiceTracker = new ServiceTracker<EventListener, AtomicReference<ListenerRegistration>>( trackingContext, httpServiceRuntime.getListenerFilter(), @@ -184,12 +182,13 @@ public class ContextController { boolean addedRegisteredObject = false; try { if (filter == null) { - throw new IllegalArgumentException("Filter cannot be null"); + throw new IllegalArgumentException("Filter cannot be null"); //$NON-NLS-1$ } addedRegisteredObject = httpServiceRuntime.getRegisteredObjects().add(filter); - if (addedRegisteredObject) { - registration = doAddFilterRegistration(filterHolder, filterRef); + if (!addedRegisteredObject) { + throw new HttpWhiteboardFailureException("Multiple registration of instance detected. Prototype scope is recommended: " + filterRef, DTOConstants.FAILURE_REASON_SERVICE_IN_USE); //$NON-NLS-1$ } + registration = doAddFilterRegistration(filterHolder, filterRef); } finally { if (registration == null) { filterHolder.release(); @@ -203,21 +202,13 @@ public class ContextController { private FilterRegistration doAddFilterRegistration(ServiceHolder<Filter> filterHolder, ServiceReference<Filter> filterRef) throws ServletException { - ClassLoader legacyTCCL = (ClassLoader)filterRef.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP); boolean asyncSupported = ServiceProperties.parseBoolean( filterRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED); List<String> dispatcherList = StringPlus.from( filterRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_DISPATCHER)); - String[] dispatchers = dispatcherList.toArray( - new String[dispatcherList.size()]); - Long serviceId = (Long)filterRef.getProperty( - Constants.SERVICE_ID); - if (legacyTCCL != null) { - // this is a legacy registration; use a negative id for the DTO - serviceId = -serviceId; - } + String[] dispatchers = dispatcherList.toArray(new String[0]); Integer filterPriority = (Integer)filterRef.getProperty( Constants.SERVICE_RANKING); if (filterPriority == null) { @@ -228,15 +219,15 @@ public class ContextController { List<String> patternList = StringPlus.from( filterRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN)); - String[] patterns = patternList.toArray(new String[patternList.size()]); + String[] patterns = patternList.toArray(new String[0]); List<String> regexList = StringPlus.from( filterRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_REGEX)); - String[] regexs = regexList.toArray(new String[regexList.size()]); + String[] regexs = regexList.toArray(new String[0]); List<String> servletList = StringPlus.from( filterRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_SERVLET)); - String[] servletNames = servletList.toArray(new String[servletList.size()]); + String[] servletNames = servletList.toArray(new String[0]); String name = ServiceProperties.parseName(filterRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME), filterHolder.get()); @@ -247,8 +238,8 @@ public class ContextController { ((regexs == null) || (regexs.length == 0)) && ((servletNames == null) || (servletNames.length == 0))) { - throw new IllegalArgumentException( - "Patterns, regex or servletNames must contain a value."); + throw new HttpWhiteboardFailureException( + "Patterns, regex or servletNames must contain a value.", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ } if (patterns != null) { @@ -257,8 +248,14 @@ public class ContextController { } } + if (regexs != null) { + for (String regex : regexs) { + checkRegex(regex); + } + } + if (filter == null) { - throw new IllegalArgumentException("Filter cannot be null"); + throw new HttpWhiteboardFailureException("Filter cannot be null", DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE); //$NON-NLS-1$ } if (name == null) { @@ -281,7 +278,7 @@ public class ContextController { filterDTO.name = name; filterDTO.patterns = sort(patterns); filterDTO.regexs = regexs; - filterDTO.serviceId = serviceId; + filterDTO.serviceId = filterHolder.serviceId; filterDTO.servletContextId = contextServiceId; filterDTO.servletNames = sort(servletNames); @@ -291,7 +288,7 @@ public class ContextController { ServletContext servletContext = createServletContext( filterHolder.getBundle(), curServletContextHelper); FilterRegistration newRegistration = new FilterRegistration( - filterHolder, filterDTO, filterPriority, this, legacyTCCL); + filterHolder, filterDTO, filterPriority, this); FilterConfig filterConfig = new FilterConfigImpl( name, filterInitParams, servletContext); @@ -310,7 +307,7 @@ public class ContextController { ListenerRegistration registration = null; try { if (listener == null) { - throw new IllegalArgumentException("EventListener cannot be null"); + throw new IllegalArgumentException("EventListener cannot be null"); //$NON-NLS-1$ } registration = doAddListenerRegistration(listenerHolder, listenerRef); } finally { @@ -325,25 +322,24 @@ public class ContextController { ServiceHolder<EventListener> listenerHolder, ServiceReference<EventListener> listenerRef) throws ServletException { - EventListener eventListener = listenerHolder.get(); List<Class<? extends EventListener>> classes = getListenerClasses(listenerRef); if (classes.isEmpty()) { throw new IllegalArgumentException( - "EventListener does not implement a supported type."); + "EventListener does not implement a supported type."); //$NON-NLS-1$ } for (ListenerRegistration listenerRegistration : listenerRegistrations) { if (listenerRegistration.getT().equals(eventListener)) { throw new ServletException( - "EventListener has already been registered."); + "EventListener has already been registered."); //$NON-NLS-1$ } } ListenerDTO listenerDTO = new ListenerDTO(); - listenerDTO.serviceId = (Long) listenerRef.getProperty(Constants.SERVICE_ID); + listenerDTO.serviceId = listenerHolder.serviceId; listenerDTO.servletContextId = contextServiceId; listenerDTO.types = asStringArray(classes); @@ -377,24 +373,29 @@ public class ContextController { ClassLoader legacyTCCL = (ClassLoader)resourceRef.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP); Integer rankProp = (Integer) resourceRef.getProperty(Constants.SERVICE_RANKING); int serviceRanking = rankProp == null ? 0 : rankProp.intValue(); - List<String> patternList = StringPlus.from( - resourceRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN)); - String[] patterns = patternList.toArray(new String[patternList.size()]); + Object patternObj = resourceRef.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN); + if (!(patternObj instanceof String) && + !(patternObj instanceof String[]) && + !(patternObj instanceof Collection)) { + throw new HttpWhiteboardFailureException("Expect pattern to be String+ (String | String[] | Collection<String>)", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + List<String> patternList = StringPlus.from(patternObj); + String[] patterns = patternList.toArray(new String[0]); Long serviceId = (Long)resourceRef.getProperty( Constants.SERVICE_ID); if (legacyTCCL != null) { // this is a legacy registration; use a negative id for the DTO serviceId = -serviceId; } - String prefix = (String)resourceRef.getProperty( + Object prefixObj = resourceRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX); - checkPrefix(prefix); + checkPrefix(prefixObj); + String prefix = (String)prefixObj; if ((patterns == null) || (patterns.length < 1)) { throw new IllegalArgumentException( - "Patterns must contain a value."); + "Patterns must contain a value."); //$NON-NLS-1$ } for (String pattern : patterns) { @@ -417,8 +418,8 @@ public class ContextController { ServletContext servletContext = createServletContext( bundle, curServletContextHelper); ResourceRegistration resourceRegistration = new ResourceRegistration( - new ServiceHolder<Servlet>(servlet, bundle, serviceId, serviceRanking), - resourceDTO, curServletContextHelper, this, legacyTCCL); + resourceRef, new ServiceHolder<Servlet>(servlet, bundle, serviceId, serviceRanking, legacyTCCL), + resourceDTO, curServletContextHelper, this); ServletConfig servletConfig = new ServletConfigImpl( resourceRegistration.getName(), new HashMap<String, String>(), servletContext); @@ -432,13 +433,14 @@ public class ContextController { return Throw.unchecked(t); } + recordEndpointShadowing(resourceRegistration); + endpointRegistrations.add(resourceRegistration); return resourceRegistration; } - public ServletRegistration addServletRegistration(ServiceReference<Servlet> servletRef) throws ServletException { - + public ServletRegistration addServletRegistration(ServiceReference<Servlet> servletRef) { checkShutdown(); ServiceHolder<Servlet> servletHolder = new ServiceHolder<Servlet>(consumingContext.getServiceObjects(servletRef)); @@ -447,12 +449,13 @@ public class ContextController { boolean addedRegisteredObject = false; try { if (servlet == null) { - throw new IllegalArgumentException("Servlet cannot be null"); + throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$ } addedRegisteredObject = httpServiceRuntime.getRegisteredObjects().add(servlet); - if (addedRegisteredObject) { - registration = doAddServletRegistration(servletHolder, servletRef); + if (!addedRegisteredObject) { + throw new HttpWhiteboardFailureException("Multiple registration of instance detected. Prototype scope is recommended: " + servletRef, DTOConstants.FAILURE_REASON_SERVICE_IN_USE); //$NON-NLS-1$ } + registration = doAddServletRegistration(servletHolder, servletRef); } finally { if (registration == null) { // Always attempt to release here; even though destroy() may have been called @@ -468,24 +471,17 @@ public class ContextController { return registration; } - private ServletRegistration doAddServletRegistration(ServiceHolder<Servlet> servletHolder, ServiceReference<Servlet> servletRef) throws ServletException { - + private ServletRegistration doAddServletRegistration(ServiceHolder<Servlet> servletHolder, ServiceReference<Servlet> servletRef) { boolean asyncSupported = ServiceProperties.parseBoolean( servletRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); - ClassLoader legacyTCCL = (ClassLoader)servletRef.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP); List<String> errorPageList = StringPlus.from( servletRef.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE)); - String[] errorPages = errorPageList.toArray(new String[errorPageList.size()]); + String[] errorPages = errorPageList.toArray(new String[0]); Map<String, String> servletInitParams = ServiceProperties.parseInitParams( servletRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); List<String> patternList = StringPlus.from( servletRef.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN)); - String[] patterns = patternList.toArray(new String[patternList.size()]); - Long serviceId = (Long)servletRef.getProperty(Constants.SERVICE_ID); - if (legacyTCCL != null) { - // this is a legacy registration; use a negative id for the DTO - serviceId = -serviceId; - } + String[] patterns = patternList.toArray(new String[0]); String servletNameFromProperties = (String)servletRef.getProperty( HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); String generatedServletName = ServiceProperties.parseName( @@ -535,14 +531,14 @@ public class ContextController { servletDTO.multipartMaxRequestSize = (multipartMaxRequestSize != null ? multipartMaxRequestSize : -1L); servletDTO.name = generatedServletName; servletDTO.patterns = sort(patterns); - servletDTO.serviceId = serviceId; + servletDTO.serviceId = servletHolder.serviceId; servletDTO.servletContextId = contextServiceId; servletDTO.servletInfo = servletHolder.get().getServletInfo(); - ErrorPageDTO errorPageDTO = null; + ExtendedErrorPageDTO errorPageDTO = null; if ((errorPages != null) && (errorPages.length > 0)) { - errorPageDTO = new ErrorPageDTO(); + errorPageDTO = new ExtendedErrorPageDTO(); errorPageDTO.asyncSupported = asyncSupported; List<String> exceptions = new ArrayList<String>(); @@ -553,16 +549,21 @@ public class ContextController { for(String errorPage : errorPages) { try { if ("4xx".equals(errorPage)) { //$NON-NLS-1$ + errorPageDTO.erroCodeType = ErrorCodeType.RANGE_4XX; for (long code = 400; code < 500; code++) { errorCodeSet.add(code); } } else if ("5xx".equals(errorPage)) { //$NON-NLS-1$ + errorPageDTO.erroCodeType = ErrorCodeType.RANGE_5XX; for (long code = 500; code < 600; code++) { errorCodeSet.add(code); } - } else { + } else if (errorPage.length() == 3) { + errorPageDTO.erroCodeType = ErrorCodeType.SPECIFIC; long code = Long.parseLong(errorPage); errorCodeSet.add(code); + } else { + exceptions.add(errorPage); } } catch (NumberFormatException nfe) { @@ -577,10 +578,10 @@ public class ContextController { i++; } errorPageDTO.errorCodes = errorCodes; - errorPageDTO.exceptions = exceptions.toArray(new String[exceptions.size()]); + errorPageDTO.exceptions = exceptions.toArray(new String[0]); errorPageDTO.initParams = servletInitParams; errorPageDTO.name = generatedServletName; - errorPageDTO.serviceId = serviceId; + errorPageDTO.serviceId = servletHolder.serviceId; errorPageDTO.servletContextId = contextServiceId; errorPageDTO.servletInfo = servletHolder.get().getServletInfo(); } @@ -592,7 +593,7 @@ public class ContextController { servletHolder.getBundle(), curServletContextHelper); ServletRegistration servletRegistration = new ServletRegistration( servletHolder, servletDTO, errorPageDTO, curServletContextHelper, this, - servletContext, legacyTCCL); + servletContext); ServletConfig servletConfig = new ServletConfigImpl( generatedServletName, servletInitParams, servletContext); @@ -605,11 +606,105 @@ public class ContextController { return Throw.unchecked(t); } + recordEndpointShadowing(servletRegistration); + recordErrorPageShadowing(servletRegistration, errorPageDTO); + endpointRegistrations.add(servletRegistration); return servletRegistration; } + private void recordEndpointShadowing(EndpointRegistration<?> newRegistration) { + Set<EndpointRegistration<?>> shadowedRegs = new HashSet<EndpointRegistration<?>>(); + for (EndpointRegistration<?> existingRegistration : endpointRegistrations) { + for (String newPattern : newRegistration.getPatterns()) { + for (String existingPattern : existingRegistration.getPatterns()) { + if (newPattern.equals(existingPattern)) { + // the new reg is shadowing an existing reg + if (newRegistration.compareTo(existingRegistration) < 0) { + shadowedRegs.add(existingRegistration); + } + // the new reg is shadowed by existing reg + else { + shadowedRegs.add(newRegistration); + } + // notice that we keep checking all the existing regs. more than one could be shadowed because reg's multi patterns + } + } + } + } + for (EndpointRegistration<?> shadowedReg : shadowedRegs) { + if (shadowedReg instanceof ServletRegistration) { + recordFailedServletDTO(shadowedReg.getServiceReference(), (ExtendedServletDTO)shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); + } + else { + recordFailedResourceDTO(shadowedReg.getServiceReference(), (ResourceDTO)shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); + } + } + } + + private void recordErrorPageShadowing(ServletRegistration servletRegistration, ExtendedErrorPageDTO newErrorPageDTO) { + if (newErrorPageDTO == null) { + return; + } + Set<ServletRegistration> shadowedEPs = new HashSet<ServletRegistration>(); + for (EndpointRegistration<?> existingRegistration : endpointRegistrations) { + if (!(existingRegistration instanceof ServletRegistration)) { + continue; + } + ServletRegistration existingSRegistration = (ServletRegistration)existingRegistration; + ExtendedErrorPageDTO existingErrorPageDTO = existingSRegistration.getErrorPageDTO(); + if ((existingErrorPageDTO == null) || + (((existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_4XX) || (existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_5XX)) && (newErrorPageDTO.erroCodeType == ErrorCodeType.SPECIFIC))) { + continue; + } + if (((existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_4XX) && (newErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_4XX)) || + ((existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_5XX) && (newErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_5XX))) { + if (servletRegistration.compareTo(existingSRegistration) < 0) { + shadowedEPs.add(existingSRegistration); + } + // the new reg is shadowed by existing reg + else { + shadowedEPs.add(servletRegistration); + } + continue; + } + for (long newErrorCode : newErrorPageDTO.errorCodes) { + for (long existingCode : existingErrorPageDTO.errorCodes) { + if (newErrorCode == existingCode) { + // the new reg is shadowing an existing reg + if (servletRegistration.compareTo(existingSRegistration) < 0) { + shadowedEPs.add(existingSRegistration); + } + // the new reg is shadowed by existing reg + else { + shadowedEPs.add(servletRegistration); + } + // notice that we keep checking all the existing regs. more than one could be shadowed because reg's multi patterns + } + } + } + for (String newException : newErrorPageDTO.exceptions) { + for (String existingException : existingErrorPageDTO.exceptions) { + if (newException.equals(existingException)) { + // the new reg is shadowing an existing reg + if (servletRegistration.compareTo(existingSRegistration) < 0) { + shadowedEPs.add(existingSRegistration); + } + // the new reg is shadowed by existing reg + else { + shadowedEPs.add(servletRegistration); + } + // notice that we keep checking all the existing regs. more than one could be shadowed because reg's multi patterns + } + } + } + } + for (ServletRegistration shadowedReg : shadowedEPs) { + recordFailedErrorPageDTO(shadowedReg.getServiceReference(), shadowedReg.getErrorPageDTO(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); + } + } + public void destroy() { flushActiveSessions(); resourceServiceTracker.close(); @@ -920,16 +1015,13 @@ public class ContextController { targetFilter = FrameworkUtil.createFilter(contextSelector); } catch (InvalidSyntaxException ise) { - throw new IllegalArgumentException(ise); + throw new HttpWhiteboardFailureException(ise.getMessage(), DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } return matches(targetFilter); } private boolean visibleContextHelper(ServiceReference<?> whiteBoardService) { - if (consumingContext.getBundle().equals(servletContextHelperRef.getBundle())) { - return true; - } try { if (whiteBoardService.getBundle().getBundleContext().getAllServiceReferences(ServletContextHelper.class.getName(), servletContextHelperRefFilter) != null) { return true; @@ -942,7 +1034,7 @@ public class ContextController { } public boolean matches(org.osgi.framework.Filter targetFilter) { - return targetFilter.match(servletContextHelperRef); + return targetFilter.match(serviceReference); } @Override @@ -986,17 +1078,18 @@ public class ContextController { return; } - FilterDTO[] filterDTOs = - new FilterDTO[matchedFilterRegistrations.size()]; + List<FilterDTO> filterDTOs = new ArrayList<FilterDTO>(); - for (int i = 0; i < filterDTOs.length ; i++) { + for (int i = 0; i < matchedFilterRegistrations.size() ; i++) { FilterRegistration filterRegistration = matchedFilterRegistrations.get(i); - filterDTOs[i] = filterRegistration.getD(); + if (Arrays.binarySearch(filterRegistration.getD().dispatcher, DispatcherType.REQUEST.toString()) > -1) { + filterDTOs.add(filterRegistration.getD()); + } } - requestInfoDTO.filterDTOs = filterDTOs; + requestInfoDTO.filterDTOs = filterDTOs.toArray(new FilterDTO[0]); } private String[] asStringArray( @@ -1023,8 +1116,8 @@ public class ContextController { DispatcherType.valueOf(type); } catch (IllegalArgumentException iae) { - throw new IllegalArgumentException( - "Invalid dispatcher '" + type + "'", iae); + throw new HttpWhiteboardFailureException( + "Invalid dispatcher '" + type + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ } } @@ -1035,28 +1128,53 @@ public class ContextController { public static void checkPattern(String pattern) { if (pattern == null) { - throw new IllegalArgumentException("Pattern cannot be null"); + throw new HttpWhiteboardFailureException("Pattern cannot be null", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ } if (pattern.indexOf("*.") == 0) { //$NON-NLS-1$ return; } + if (Const.BLANK.equals(pattern)) { + return; + } + + if (Const.SLASH.equals(pattern)) { + return; + } + if (!pattern.startsWith(Const.SLASH) || - (pattern.endsWith(Const.SLASH) && !pattern.equals(Const.SLASH))) { + (pattern.endsWith(Const.SLASH) && !pattern.equals(Const.SLASH)) || + pattern.contains("**")) { //$NON-NLS-1$ - throw new IllegalArgumentException( - "Invalid pattern '" + pattern + "'"); + throw new HttpWhiteboardFailureException( + "Invalid pattern '" + pattern + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ } } - private void checkPrefix(String prefix) { - if (prefix == null) { - throw new IllegalArgumentException("Prefix cannot be null"); + private static void checkPrefix(Object prefixObj) { + if (prefixObj == null) { + throw new HttpWhiteboardFailureException("Prefix cannot be null.", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ } + if (!(prefixObj instanceof String)) { + throw new HttpWhiteboardFailureException("Prefix must be String.", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + String prefix = (String)prefixObj; + if (prefix.endsWith(Const.SLASH) && !prefix.equals(Const.SLASH)) { - throw new IllegalArgumentException("Invalid prefix '" + prefix + "'"); + throw new HttpWhiteboardFailureException("Invalid prefix '" + prefix + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + private static void checkRegex(String regex) { + try { + Pattern.compile(regex); + } + catch (PatternSyntaxException pse) { + throw new HttpWhiteboardFailureException( + "Invalid regex '" + regex + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ } } @@ -1067,6 +1185,16 @@ public class ContextController { } } + private static String createFilter(long contextServiceId) { + StringBuilder filterBuilder = new StringBuilder(); + filterBuilder.append('('); + filterBuilder.append(Constants.SERVICE_ID); + filterBuilder.append('='); + filterBuilder.append(contextServiceId); + filterBuilder.append(')'); + return filterBuilder.toString(); + } + private ServletContext createServletContext( Bundle curBundle, ServletContextHelper curServletContextHelper) { @@ -1086,25 +1214,28 @@ public class ContextController { for (EndpointRegistration<?> endpointRegistration : endpointRegistrations) { if (endpointRegistration instanceof ResourceRegistration) { - resourceDTOs.add(DTOUtil.clone((ResourceDTO)endpointRegistration.getD())); + if (!httpServiceRuntime.failedResourceDTO(endpointRegistration.getServiceReference())) { + resourceDTOs.add(DTOUtil.clone((ResourceDTO)endpointRegistration.getD())); + } } else { ServletRegistration servletRegistration = (ServletRegistration)endpointRegistration; - servletDTOs.add(DTOUtil.clone(servletRegistration.getD())); + if (!httpServiceRuntime.failedServletDTO(servletRegistration.getServiceReference())) { + servletDTOs.add(DTOUtil.clone(servletRegistration.getD())); + } ErrorPageDTO errorPageDTO = servletRegistration.getErrorPageDTO(); - if (errorPageDTO != null) { + if ((errorPageDTO != null) && + !httpServiceRuntime.failedErrorPageDTO(servletRegistration.getServiceReference())) { + errorPageDTOs.add(DTOUtil.clone(errorPageDTO)); } } } - servletContextDTO.errorPageDTOs = errorPageDTOs.toArray( - new ErrorPageDTO[errorPageDTOs.size()]); - servletContextDTO.resourceDTOs = resourceDTOs.toArray( - new ResourceDTO[resourceDTOs.size()]); - servletContextDTO.servletDTOs = servletDTOs.toArray( - new ServletDTO[servletDTOs.size()]); + servletContextDTO.errorPageDTOs = errorPageDTOs.toArray(new ErrorPageDTO[0]); + servletContextDTO.resourceDTOs = resourceDTOs.toArray(new ResourceDTO[0]); + servletContextDTO.servletDTOs = servletDTOs.toArray(new ServletDTO[0]); } private void collectFilterDTOs( @@ -1116,8 +1247,7 @@ public class ContextController { filterDTOs.add(DTOUtil.clone(filterRegistration.getD())); } - servletContextDTO.filterDTOs = filterDTOs.toArray( - new FilterDTO[filterDTOs.size()]); + servletContextDTO.filterDTOs = filterDTOs.toArray(new FilterDTO[0]); } private void collectListenerDTOs( @@ -1129,8 +1259,7 @@ public class ContextController { listenerDTOs.add(DTOUtil.clone(listenerRegistration.getD())); } - servletContextDTO.listenerDTOs = listenerDTOs.toArray( - new ListenerDTO[listenerDTOs.size()]); + servletContextDTO.listenerDTOs = listenerDTOs.toArray(new ListenerDTO[0]); } private Map<String, Object> getDTOAttributes(ServletContext servletContext) { @@ -1148,9 +1277,9 @@ public class ContextController { } private List<Class<? extends EventListener>> getListenerClasses( - ServiceReference<EventListener> serviceReference) { + ServiceReference<EventListener> listenerReference) { - List<String> objectClassList = StringPlus.from(serviceReference.getProperty(Constants.OBJECTCLASS)); + List<String> objectClassList = StringPlus.from(listenerReference.getProperty(Constants.OBJECTCLASS)); List<Class<? extends EventListener>> classes = new ArrayList<Class<? extends EventListener>>(); @@ -1184,15 +1313,19 @@ public class ContextController { return classes; } + public ServiceReference<ServletContextHelper> getServiceReference() { + return serviceReference; + } + private ServletContextHelper getServletContextHelper(Bundle curBundle) { BundleContext context = curBundle.getBundleContext(); - return context.getService(servletContextHelperRef); + return context.getService(serviceReference); } public void ungetServletContextHelper(Bundle curBundle) { BundleContext context = curBundle.getBundleContext(); try { - context.ungetService(servletContextHelperRef); + context.ungetService(serviceReference); } catch (IllegalStateException e) { // this can happen if the whiteboard bundle is in the process of stopping // and the framework is in the middle of auto-unregistering any services @@ -1233,7 +1366,7 @@ public class ContextController { HttpSessionAdaptor httpSessionAdaptor = activeSessions.remove(sessionId); if (httpSessionAdaptor != null) { - httpSessionTracker.removeHttpSessionAdaptor(sessionId, httpSessionAdaptor); + httpServiceRuntime.getHttpSessionTracker().removeHttpSessionAdaptor(sessionId, httpSessionAdaptor); } } @@ -1304,27 +1437,169 @@ public class ContextController { return previousHttpSessionAdaptor; } - httpSessionTracker.addHttpSessionAdaptor(sessionId, httpSessionAdaptor); + httpServiceRuntime.getHttpSessionTracker().addHttpSessionAdaptor(sessionId, httpSessionAdaptor); return null; } - private void validate(String preValidationContextName, String preValidationContextPath) { - if (!contextNamePattern.matcher(preValidationContextName).matches()) { + public void recordFailedErrorPageDTO( + ServiceReference<?> servletReference, ExtendedErrorPageDTO errorPageDTO, int failureReason) { + + FailedErrorPageDTO failedErrorPageDTO = new FailedErrorPageDTO(); + failedErrorPageDTO.asyncSupported = errorPageDTO.asyncSupported; + failedErrorPageDTO.errorCodes = errorPageDTO.errorCodes; + failedErrorPageDTO.exceptions = errorPageDTO.exceptions; + failedErrorPageDTO.failureReason = failureReason; + failedErrorPageDTO.initParams = errorPageDTO.initParams; + failedErrorPageDTO.name = errorPageDTO.name; + failedErrorPageDTO.serviceId = errorPageDTO.serviceId; + failedErrorPageDTO.servletContextId = errorPageDTO.servletContextId; + failedErrorPageDTO.servletInfo = errorPageDTO.servletInfo; + + getHttpServiceRuntime().recordFailedErrorPageDTO(servletReference, failedErrorPageDTO); + } + + public void recordFailedResourceDTO( + ServiceReference<?> resourceReference, ResourceDTO resourceDTO, int failureReason) { + + FailedResourceDTO failedResourceDTO = new FailedResourceDTO(); + failedResourceDTO.failureReason = failureReason; + failedResourceDTO.patterns = resourceDTO.patterns; + failedResourceDTO.prefix = resourceDTO.prefix; + failedResourceDTO.serviceId = resourceDTO.serviceId; + failedResourceDTO.servletContextId = resourceDTO.servletContextId; + + getHttpServiceRuntime().recordFailedResourceDTO(resourceReference, failedResourceDTO); + } + + public void recordFailedServletDTO( + ServiceReference<?> servletReference, ExtendedServletDTO servletDTO, int failureReason) { + + ExtendedFailedServletDTO failedServletDTO = new ExtendedFailedServletDTO(); + + if (servletDTO != null) { + failedServletDTO.asyncSupported = servletDTO.asyncSupported; + failedServletDTO.failureReason = failureReason; + failedServletDTO.initParams = servletDTO.initParams; + failedServletDTO.multipartEnabled = servletDTO.multipartEnabled; + failedServletDTO.multipartFileSizeThreshold = servletDTO.multipartFileSizeThreshold; + failedServletDTO.multipartLocation = servletDTO.multipartLocation; + failedServletDTO.multipartMaxFileSize = servletDTO.multipartMaxFileSize; + failedServletDTO.multipartMaxRequestSize = servletDTO.multipartMaxRequestSize; + failedServletDTO.name = servletDTO.name; + failedServletDTO.patterns = servletDTO.patterns; + failedServletDTO.serviceId = servletDTO.serviceId; + failedServletDTO.servletContextId = servletDTO.servletContextId; + failedServletDTO.servletInfo = servletDTO.servletInfo; + } + else { + failedServletDTO.asyncSupported = BooleanPlus.from( + servletReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED), false); + failedServletDTO.failureReason = failureReason; + failedServletDTO.initParams = ServiceProperties.parseInitParams( + servletReference, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); + failedServletDTO.multipartEnabled = ServiceProperties.parseBoolean( + servletReference, Const.EQUINOX_HTTP_MULTIPART_ENABLED); + Integer multipartFileSizeThreshold = (Integer)servletReference.getProperty( + Const.EQUINOX_HTTP_MULTIPART_FILESIZETHRESHOLD); + if (multipartFileSizeThreshold != null) { + failedServletDTO.multipartFileSizeThreshold = multipartFileSizeThreshold; + } + failedServletDTO.multipartLocation = (String)servletReference.getProperty( + Const.EQUINOX_HTTP_MULTIPART_LOCATION); + Long multipartMaxFileSize = (Long)servletReference.getProperty( + Const.EQUINOX_HTTP_MULTIPART_MAXFILESIZE); + if (multipartMaxFileSize != null) { + failedServletDTO.multipartMaxFileSize = multipartMaxFileSize; + } + Long multipartMaxRequestSize = (Long)servletReference.getProperty( + Const.EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE); + if (multipartMaxRequestSize != null) { + failedServletDTO.multipartMaxRequestSize = multipartMaxRequestSize; + } + failedServletDTO.name = (String)servletReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); + failedServletDTO.patterns = StringPlus.from( + servletReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN)).toArray(new String[0]); + failedServletDTO.serviceId = (Long)servletReference.getProperty(Constants.SERVICE_ID); + if (servletReference.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP) != null) { + failedServletDTO.serviceId = -failedServletDTO.serviceId; + } + failedServletDTO.servletContextId = getServiceId(); + failedServletDTO.servletInfo = Const.BLANK; + } + + getHttpServiceRuntime().recordFailedServletDTO(servletReference, failedServletDTO); + } + + private String validateName() { + Object contextNameObj = serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME); + + if (contextNameObj == null) { + throw new IllegalContextNameException( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + " is null. Ignoring!", //$NON-NLS-1$ + DTOConstants.FAILURE_REASON_VALIDATION_FAILED); + } + else if (!(contextNameObj instanceof String)) { + throw new IllegalContextNameException( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + " is not String. Ignoring!", //$NON-NLS-1$ + DTOConstants.FAILURE_REASON_VALIDATION_FAILED); + } + + String name = (String)contextNameObj; + + if (!contextNamePattern.matcher(name).matches()) { throw new IllegalContextNameException( - "The context name '" + preValidationContextName + "' does not follow Bundle-SymbolicName syntax.", //$NON-NLS-1$ //$NON-NLS-2$ + "The context name '" + name + "' does not follow Bundle-SymbolicName syntax.", //$NON-NLS-1$ //$NON-NLS-2$ DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } + // Now check for naming conflicts + for (ContextController existingContext : httpServiceRuntime.getContextControllers()) { + if (name.equals(existingContext.getContextName())) { + if (serviceReference.compareTo(existingContext.serviceReference) < 0) { + throw new HttpWhiteboardFailureException("Context with same name exists. " + serviceReference, DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + httpServiceRuntime.recordFailedServletContextDTO( + existingContext.serviceReference, (Long)serviceReference.getProperty(Constants.SERVICE_ID), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); + } + } + + return name; + } + + private String validatePath() { + Object contextPathObj = serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH); + + if (contextPathObj == null) { + throw new IllegalContextPathException( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + " is null. Ignoring!", //$NON-NLS-1$ + DTOConstants.FAILURE_REASON_VALIDATION_FAILED); + } + else if (!(contextPathObj instanceof String)) { + throw new IllegalContextPathException( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + " is not String. Ignoring!", //$NON-NLS-1$ + DTOConstants.FAILURE_REASON_VALIDATION_FAILED); + } + + String path = (String)contextPathObj; + try { @SuppressWarnings("unused") - URI uri = new URI(Const.HTTP, Const.LOCALHOST, preValidationContextPath, null); + URI uri = new URI(Const.HTTP, Const.LOCALHOST, path, null); } catch (URISyntaxException use) { throw new IllegalContextPathException( - "The context path '" + preValidationContextPath + "' is not valid URI path syntax.", //$NON-NLS-1$ //$NON-NLS-2$ + "The context path '" + path + "' is not valid URI path syntax.", //$NON-NLS-1$ //$NON-NLS-2$ DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } + + path = httpServiceRuntime.adaptContextPath(path, serviceReference); + if (path.equals(Const.SLASH)) { + path = Const.BLANK; + } + + return path; } private static final String[] DISPATCHER = @@ -1347,10 +1622,9 @@ public class ContextController { private final ConcurrentMap<String, HttpSessionAdaptor> activeSessions = new ConcurrentHashMap<String, HttpSessionAdaptor>(); private final HttpServiceRuntimeImpl httpServiceRuntime; - private final HttpSessionTracker httpSessionTracker; private final Set<ListenerRegistration> listenerRegistrations = new HashSet<ListenerRegistration>(); private final ProxyContext proxyContext; - private final ServiceReference<ServletContextHelper> servletContextHelperRef; + private final ServiceReference<ServletContextHelper> serviceReference; private final String servletContextHelperRefFilter; private boolean shutdown; private String string; diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHelperFactory.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHelperFactory.java deleted file mode 100644 index 396181039..000000000 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHelperFactory.java +++ /dev/null @@ -1,154 +0,0 @@ -/******************************************************************************* - * Copyright (c) Nov 21, 2014 Liferay, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Liferay, Inc. - initial API and implementation and/or initial - * documentation - ******************************************************************************/ - -package org.eclipse.equinox.http.servlet.internal.context; - -import java.io.IOException; -import java.net.URL; -import java.util.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.osgi.framework.*; -import org.osgi.service.http.HttpContext; -import org.osgi.service.http.context.ServletContextHelper; - -public class HttpContextHelperFactory - implements ServiceFactory<ServletContextHelper> { - - final HttpContext httpContext; - final AtomicReference<ServiceRegistration<ServletContextHelper>> registrationRef = - new AtomicReference<ServiceRegistration<ServletContextHelper>>(); - final AtomicReference<String> filterRef = new AtomicReference<String>(); - final AtomicLong useCount = new AtomicLong(0); - - public HttpContextHelperFactory(HttpContext httpContext) { - this.httpContext = httpContext; - } - - @Override - public ServletContextHelper getService( - Bundle bundle, ServiceRegistration<ServletContextHelper> registration) { - setRegistration(registration); - return new HttpContextHelper(bundle); - } - - @Override - public void ungetService( - Bundle bundle, ServiceRegistration<ServletContextHelper> registration, - ServletContextHelper service) { - // nothing to do - } - - public void setRegistration(ServiceRegistration<ServletContextHelper> registration) { - if (this.registrationRef.compareAndSet(null, registration)) { - StringBuilder filterBuilder = new StringBuilder(); - filterBuilder.append('('); - filterBuilder.append(Constants.SERVICE_ID); - filterBuilder.append('='); - filterBuilder.append(registration.getReference().getProperty(Constants.SERVICE_ID)); - filterBuilder.append(')'); - filterRef.compareAndSet(null, filterBuilder.toString()); - } - } - - public ServiceReference<ServletContextHelper> getServiceReference() { - ServiceRegistration<ServletContextHelper> reg = registrationRef.get(); - if (reg != null) { - try { - return reg.getReference(); - } catch (IllegalStateException e) { - // do nothing - } - } - return null; - } - - public String getFilter() { - return filterRef.get(); - } - - - public long incrementUseCount() { - return useCount.incrementAndGet(); - } - - public long decrementUseCount() { - long result = useCount.decrementAndGet(); - if (result == 0) { - ServiceRegistration<ServletContextHelper> registration = registrationRef.get(); - if (registration != null) { - try { - registration.unregister(); - } catch (IllegalStateException e) { - // ignore; already unregistered - } - } - } - return result; - } - - public Object getHttpContext() { - return httpContext; - } - - public class HttpContextHelper extends ServletContextHelper { - private final Bundle bundle; - - public HttpContextHelper(Bundle bundle) { - this.bundle = bundle; - } - - @Override - public boolean handleSecurity( - HttpServletRequest request, HttpServletResponse response) - throws IOException { - return httpContext.handleSecurity(request, response); - } - - @Override - public URL getResource(String name) { - return httpContext.getResource(name); - } - - @Override - public String getMimeType(String name) { - return httpContext.getMimeType(name); - } - - @Override - public Set<String> getResourcePaths(String path) { - if ((path == null) || (bundle == null)) { - return null; - } - - final Enumeration<URL> enumeration = bundle.findEntries( - path, null, false); - - if (enumeration == null) { - return null; - } - - final Set<String> result = new HashSet<String>(); - - while (enumeration.hasMoreElements()) { - result.add(enumeration.nextElement().getPath()); - } - - return result; - } - } -} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/WrappedHttpContext.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/WrappedHttpContext.java new file mode 100644 index 000000000..51246f5b5 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/WrappedHttpContext.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) Jan. 27, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal.context; + +import java.io.IOException; +import java.net.URL; +import java.util.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.equinox.http.servlet.internal.DefaultServletContextHelper; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpContext; + +public class WrappedHttpContext extends DefaultServletContextHelper { + + private final HttpContext httpContext; + private final Bundle bundle; + + public WrappedHttpContext(HttpContext httpContext, Bundle bundle) { + super(bundle); + this.httpContext = httpContext; + this.bundle = bundle; + } + + @Override + public boolean handleSecurity( + HttpServletRequest request, HttpServletResponse response) + throws IOException { + return httpContext.handleSecurity(request, response); + } + + @Override + public URL getResource(String name) { + return httpContext.getResource(name); + } + + @Override + public String getMimeType(String name) { + return httpContext.getMimeType(name); + } + + @Override + public Set<String> getResourcePaths(String path) { + if ((path == null) || (bundle == null)) { + return null; + } + + final Enumeration<URL> enumeration = bundle.findEntries( + path, null, false); + + if (enumeration == null) { + return null; + } + + final Set<String> result = new HashSet<String>(); + + while (enumeration.hasMoreElements()) { + result.add(enumeration.nextElement().getPath()); + } + + return result; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextFilterTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextFilterTrackerCustomizer.java index 61b72b3e4..ee9efa443 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextFilterTrackerCustomizer.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextFilterTrackerCustomizer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -50,11 +50,21 @@ public class ContextFilterTrackerCustomizer return result; } - if (!contextController.matches(serviceReference)) { - return result; - } - try { + if (!contextController.matches(serviceReference)) { + // Only the default context will perform the "does anyone match" checks. + if (httpServiceRuntime.isDefaultContext(contextController) && + !httpServiceRuntime.matchesAnyContext(serviceReference)) { + + throw new HttpWhiteboardFailureException( + "Doesn't match any contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } + + return result; + } + + httpServiceRuntime.removeFailedFilterDTO(serviceReference); + result.set(contextController.addFilterRegistration(serviceReference)); } catch (HttpWhiteboardFailureException hwfe) { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextListenerTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextListenerTrackerCustomizer.java index 8a8f18ee3..bb6ad17ce 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextListenerTrackerCustomizer.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextListenerTrackerCustomizer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -50,11 +50,21 @@ public class ContextListenerTrackerCustomizer return result; } - if (!contextController.matches(serviceReference)) { - return result; - } - try { + if (!contextController.matches(serviceReference)) { + // Only the default context will perform the "does anyone match" checks. + if (httpServiceRuntime.isDefaultContext(contextController) && + !httpServiceRuntime.matchesAnyContext(serviceReference)) { + + throw new HttpWhiteboardFailureException( + "Doesn't match any contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } + + return result; + } + + httpServiceRuntime.removeFailedListenerDTO(serviceReference); + String listener = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER); if (Boolean.FALSE.toString().equalsIgnoreCase(listener)) { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextResourceTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextResourceTrackerCustomizer.java index d7fa1e80b..61477208e 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextResourceTrackerCustomizer.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextResourceTrackerCustomizer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -48,11 +48,21 @@ public class ContextResourceTrackerCustomizer return result; } - if (!contextController.matches(serviceReference)) { - return result; - } - try { + if (!contextController.matches(serviceReference)) { + // Only the default context will perform the "does anyone match" checks. + if (httpServiceRuntime.isDefaultContext(contextController) && + !httpServiceRuntime.matchesAnyContext(serviceReference)) { + + throw new HttpWhiteboardFailureException( + "Doesn't match any contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } + + return result; + } + + httpServiceRuntime.removeFailedResourceDTO(serviceReference); + result.set(contextController.addResourceRegistration(serviceReference)); } catch (HttpWhiteboardFailureException hwfe) { @@ -100,7 +110,7 @@ public class ContextResourceTrackerCustomizer failedResourceDTO.failureReason = failureReason; failedResourceDTO.patterns = StringPlus.from( serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN)).toArray(new String[0]); - failedResourceDTO.prefix = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX); + failedResourceDTO.prefix = String.valueOf(serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX)); failedResourceDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); failedResourceDTO.servletContextId = contextController.getServiceId(); diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextServletTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextServletTrackerCustomizer.java index b5fddfdb5..cf5044415 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextServletTrackerCustomizer.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextServletTrackerCustomizer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,15 +16,13 @@ package org.eclipse.equinox.http.servlet.internal.customizer; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.Servlet; -import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO; import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.error.HttpWhiteboardFailureException; import org.eclipse.equinox.http.servlet.internal.registration.ServletRegistration; -import org.eclipse.equinox.http.servlet.internal.util.*; -import org.osgi.framework.*; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.service.http.runtime.dto.DTOConstants; -import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; /** * @author Raymond Augé @@ -50,22 +48,32 @@ public class ContextServletTrackerCustomizer return result; } - if (!contextController.matches(serviceReference)) { - return result; - } - try { + if (!contextController.matches(serviceReference)) { + // Only the default context will perform the "does anyone match" checks. + if (httpServiceRuntime.isDefaultContext(contextController) && + !httpServiceRuntime.matchesAnyContext(serviceReference)) { + + throw new HttpWhiteboardFailureException( + "Doesn't match any contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } + + return result; + } + + httpServiceRuntime.removeFailedServletDTO(serviceReference); + result.set(contextController.addServletRegistration(serviceReference)); } catch (HttpWhiteboardFailureException hwfe) { httpServiceRuntime.log(hwfe.getMessage(), hwfe); - recordFailedServletDTO(serviceReference, hwfe.getFailureReason()); + contextController.recordFailedServletDTO(serviceReference, null, hwfe.getFailureReason()); } catch (Throwable t) { httpServiceRuntime.log(t.getMessage(), t); - recordFailedServletDTO(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + contextController.recordFailedServletDTO(serviceReference, null, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); } return result; @@ -91,46 +99,8 @@ public class ContextServletTrackerCustomizer registration.destroy(); } - contextController.getHttpServiceRuntime().removeFailedServletDTOs(serviceReference); - } - - private void recordFailedServletDTO( - ServiceReference<Servlet> serviceReference, int failureReason) { - - ExtendedFailedServletDTO failedServletDTO = new ExtendedFailedServletDTO(); - - failedServletDTO.asyncSupported = BooleanPlus.from( - serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED), false); - failedServletDTO.failureReason = failureReason; - failedServletDTO.initParams = ServiceProperties.parseInitParams( - serviceReference, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); - failedServletDTO.multipartEnabled = ServiceProperties.parseBoolean( - serviceReference, Const.EQUINOX_HTTP_MULTIPART_ENABLED); - Integer multipartFileSizeThreshold = (Integer)serviceReference.getProperty( - Const.EQUINOX_HTTP_MULTIPART_FILESIZETHRESHOLD); - if (multipartFileSizeThreshold != null) { - failedServletDTO.multipartFileSizeThreshold = multipartFileSizeThreshold; - } - failedServletDTO.multipartLocation = (String)serviceReference.getProperty( - Const.EQUINOX_HTTP_MULTIPART_LOCATION); - Long multipartMaxFileSize = (Long)serviceReference.getProperty( - Const.EQUINOX_HTTP_MULTIPART_MAXFILESIZE); - if (multipartMaxFileSize != null) { - failedServletDTO.multipartMaxFileSize = multipartMaxFileSize; - } - Long multipartMaxRequestSize = (Long)serviceReference.getProperty( - Const.EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE); - if (multipartMaxRequestSize != null) { - failedServletDTO.multipartMaxRequestSize = multipartMaxRequestSize; - } - failedServletDTO.name = (String)serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); - failedServletDTO.patterns = StringPlus.from( - serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN)).toArray(new String[0]); - failedServletDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); - failedServletDTO.servletContextId = contextController.getServiceId(); - failedServletDTO.servletInfo = Const.BLANK; - - contextController.getHttpServiceRuntime().recordFailedServletDTO(serviceReference, failedServletDTO); + contextController.getHttpServiceRuntime().removeFailedServletDTO(serviceReference); + contextController.getHttpServiceRuntime().removeFailedErrorPageDTO(serviceReference); } private ContextController contextController; diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/RegistrationServiceTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/RegistrationServiceTrackerCustomizer.java index 0ef3dd136..93954b73c 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/RegistrationServiceTrackerCustomizer.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/RegistrationServiceTrackerCustomizer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedErrorPageDTO.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedErrorPageDTO.java new file mode 100644 index 000000000..b6f4b31d9 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedErrorPageDTO.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) Jan. 28, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal.dto; + +import org.osgi.service.http.runtime.dto.ErrorPageDTO; + +/** + * Internal Extended DTO model used for simplifying handling logic. + */ +public class ExtendedErrorPageDTO extends ErrorPageDTO { + + public enum ErrorCodeType { + RANGE_4XX, RANGE_5XX, SPECIFIC + } + + /** + * Indicates the type of error codes defined. This is calculated by the system. + */ + public ErrorCodeType erroCodeType; +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedFailedServletContextDTO.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedFailedServletContextDTO.java new file mode 100644 index 000000000..8db94fea6 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/dto/ExtendedFailedServletContextDTO.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) Jan. 29, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal.dto; + +import org.osgi.service.http.runtime.dto.FailedServletContextDTO; + +/** + * Internal Extended DTO model used for simplifying handling logic. + */ +public class ExtendedFailedServletContextDTO extends FailedServletContextDTO { + + /** + * Holds the serviceId of the service that shadowed this context. + */ + public long shadowingServiceId; + +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredFilterException.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredFilterException.java index 949ca3da5..70e0e5c5c 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredFilterException.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredFilterException.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -15,16 +15,16 @@ package org.eclipse.equinox.http.servlet.internal.error; import javax.servlet.Filter; -import javax.servlet.ServletException; +import org.osgi.service.http.runtime.dto.DTOConstants; /** * @author Raymond Augé */ -public class RegisteredFilterException extends ServletException { +public class RegisteredFilterException extends HttpWhiteboardFailureException { private static final long serialVersionUID = 4321327145573490998L; public RegisteredFilterException(Filter filter) { - super("Filter has already been registered: " + filter); + super("Filter has already been registered: " + filter, DTOConstants.FAILURE_REASON_SERVICE_IN_USE); //$NON-NLS-1$ } -}
\ No newline at end of file +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java index d27fb8453..4f4bd27f4 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2015 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -22,6 +22,7 @@ import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.context.ContextController.ServiceHolder; import org.eclipse.equinox.http.servlet.internal.servlet.Match; import org.osgi.dto.DTO; +import org.osgi.framework.ServiceReference; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.http.context.ServletContextHelper; @@ -31,22 +32,22 @@ import org.osgi.service.http.context.ServletContextHelper; public abstract class EndpointRegistration<D extends DTO> extends MatchableRegistration<Servlet, D> implements Comparable<EndpointRegistration<?>>{ - private final ServiceHolder<Servlet> servletHolder; + protected final ServiceHolder<Servlet> servletHolder; private final ServletContextHelper servletContextHelper; //The context used during the registration of the servlet private final ContextController contextController; private final ClassLoader classLoader; public EndpointRegistration( ServiceHolder<Servlet> servletHolder, D d, ServletContextHelper servletContextHelper, - ContextController contextController, ClassLoader legacyTCCL) { + ContextController contextController) { super(servletHolder.get(), d); this.servletHolder = servletHolder; this.servletContextHelper = servletContextHelper; this.contextController = contextController; - if (legacyTCCL != null) { + if (servletHolder.getLegacyTCCL() != null) { // legacy registrations used the current TCCL at registration time - classLoader = legacyTCCL; + classLoader = servletHolder.getLegacyTCCL(); } else { classLoader = servletHolder.getBundle().adapt(BundleWiring.class).getClassLoader(); } @@ -115,6 +116,8 @@ public abstract class EndpointRegistration<D extends DTO> return servletContextHelper; } + public abstract ServiceReference<?> getServiceReference(); + @Override public String match( String name, String servletPath, String pathInfo, String extension, diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/FilterRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/FilterRegistration.java index 669fb2f47..8cc36da4f 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/FilterRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/FilterRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2016 IBM Corporation and others. + * Copyright (c) 2011, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -25,8 +25,6 @@ import org.eclipse.equinox.http.servlet.internal.context.ContextController.Servi import org.eclipse.equinox.http.servlet.internal.servlet.FilterChainImpl; import org.eclipse.equinox.http.servlet.internal.servlet.Match; import org.eclipse.equinox.http.servlet.internal.util.Const; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.http.runtime.dto.FilterDTO; @@ -45,35 +43,20 @@ public class FilterRegistration public FilterRegistration( ServiceHolder<Filter> filterHolder, FilterDTO filterDTO, int priority, - ContextController contextController, ClassLoader legacyTCCL) { + ContextController contextController) { super(filterHolder.get(), filterDTO); this.filterHolder = filterHolder; this.priority = priority; this.contextController = contextController; this.compiledRegexs = getCompiledRegex(filterDTO); - if (legacyTCCL != null) { + if (filterHolder.getLegacyTCCL() != null) { // legacy filter registrations used the current TCCL at registration time - classLoader = legacyTCCL; + classLoader = filterHolder.getLegacyTCCL(); } else { classLoader = filterHolder.getBundle().adapt(BundleWiring.class).getClassLoader(); } - String legacyContextFilter = (String) filterHolder.getServiceReference().getProperty(Const.EQUINOX_LEGACY_CONTEXT_SELECT); - if (legacyContextFilter != null) { - // This is a legacy Filter registration. - // This filter tells us the real context controller, - // backed by an HttpContext that should be used to init/destroy this Filter - org.osgi.framework.Filter f = null; - try { - f = FrameworkUtil.createFilter(legacyContextFilter); - } - catch (InvalidSyntaxException e) { - // nothing - } - initDestoyWithContextController = f == null || contextController.matches(f); - } else { - initDestoyWithContextController = true; - } + initDestoyWithContextController = true; needDecode = MatchableRegistration.patternsRequireDecode(filterDTO.patterns); } @@ -243,23 +226,31 @@ public class FilterRegistration pattern = pattern.substring(0, extensionMatchIndex + 2); } - // first try prefix path matching; taking into account wild cards if necessary - if ((pattern.charAt(0) == '/')) { - if (isPathWildcardMatch(pattern, path)) { - if (extensionWithPrefixMatch != null) { - return extensionWithPrefixMatch.equals(extension); + if (pattern.isEmpty() && Const.SLASH.equals(path)) { + return true; + } + else if (!pattern.isEmpty()) { + // first try prefix path matching; taking into account wild cards if necessary + if (pattern.charAt(0) == '/') { + if (isPathWildcardMatch(pattern, path)) { + if (extensionWithPrefixMatch != null) { + return extensionWithPrefixMatch.equals(extension); + } + // special case for context path + if (Const.SLASH.equals(path) && Const.SLASH_STAR.equals(pattern)) { + return false; + } + return true; } - return true; + return false; } - return false; - } - // next try extension matching if requested - if (pattern.charAt(0) == '*') { - return pattern.substring(2).equals(extension); + // next try extension matching if requested + if (pattern.charAt(0) == '*') { + return pattern.substring(2).equals(extension); + } } - // this is really an invalid case that should have gotten caught at registration time return false; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/MatchableRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/MatchableRegistration.java index 296662d82..4fc27ff39 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/MatchableRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/MatchableRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2015 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -70,12 +70,18 @@ public abstract class MatchableRegistration<T, D extends DTO> if (match == Match.EXACT) { return pattern.equals(servletPath); } + if ((match == Match.CONTEXT_ROOT) && Const.BLANK.equals(pattern)) { + return Const.BLANK.equals(servletPath) && Const.SLASH.equals(pathInfo); + } + if ((match == Match.DEFAULT_SERVLET) && Const.SLASH.equals(pattern)) { + return !servletPath.isEmpty() && pathInfo == null; + } if (pattern.indexOf(Const.SLASH_STAR_DOT) == 0) { pattern = pattern.substring(1); } - if (pattern.charAt(0) == '/') { + if (!pattern.isEmpty() && pattern.charAt(0) == '/') { if ((match == Match.DEFAULT_SERVLET) && (pattern.length() == 1)) { return true; } @@ -117,4 +123,4 @@ public abstract class MatchableRegistration<T, D extends DTO> } return false; } -}
\ No newline at end of file +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ResourceRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ResourceRegistration.java index 2d84f1210..5a6e535e4 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ResourceRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ResourceRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -17,6 +17,7 @@ package org.eclipse.equinox.http.servlet.internal.registration; import javax.servlet.Servlet; import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.context.ContextController.ServiceHolder; +import org.osgi.framework.ServiceReference; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.dto.ResourceDTO; /** @@ -25,12 +26,13 @@ import org.osgi.service.http.runtime.dto.ResourceDTO; public class ResourceRegistration extends EndpointRegistration<ResourceDTO> { public ResourceRegistration( - ServiceHolder<Servlet> servletHolder, ResourceDTO resourceDTO, + ServiceReference<?> serviceReference, ServiceHolder<Servlet> servletHolder, ResourceDTO resourceDTO, ServletContextHelper servletContextHelper, - ContextController contextController, ClassLoader legacyTCCL) { + ContextController contextController) { - super(servletHolder, resourceDTO, servletContextHelper, contextController, legacyTCCL); + super(servletHolder, resourceDTO, servletContextHelper, contextController); + this.serviceReference = serviceReference; name = servletHolder.get().getClass().getName().concat("#").concat(getD().prefix); //$NON-NLS-1$ needDecode = MatchableRegistration.patternsRequireDecode(resourceDTO.patterns); } @@ -51,11 +53,17 @@ public class ResourceRegistration extends EndpointRegistration<ResourceDTO> { } @Override + public ServiceReference<?> getServiceReference() { + return serviceReference; + } + + @Override public boolean needDecode() { return needDecode; } private final boolean needDecode; private final String name; + private final ServiceReference<?> serviceReference; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ServletRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ServletRegistration.java index 49df3338b..9e61c8e9f 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ServletRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ServletRegistration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 Cognos Incorporated, IBM Corporation and others + * Copyright (c) 2005, 2019 Cognos Incorporated, IBM Corporation and others * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -23,11 +23,12 @@ import javax.servlet.http.Part; import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.context.ContextController.ServiceHolder; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; import org.eclipse.equinox.http.servlet.internal.multipart.MultipartSupport; import org.eclipse.equinox.http.servlet.internal.multipart.MultipartSupportFactory; import org.eclipse.equinox.http.servlet.internal.servlet.Match; +import org.osgi.framework.ServiceReference; import org.osgi.service.http.context.ServletContextHelper; -import org.osgi.service.http.runtime.dto.ErrorPageDTO; //This class wraps the servlet object registered in the HttpService.registerServlet call, to manage the context classloader when handleRequests are being asked. public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO> { @@ -51,11 +52,11 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO } public ServletRegistration( - ServiceHolder<Servlet> servletHolder, ExtendedServletDTO servletDTO, ErrorPageDTO errorPageDTO, + ServiceHolder<Servlet> servletHolder, ExtendedServletDTO servletDTO, ExtendedErrorPageDTO errorPageDTO, ServletContextHelper servletContextHelper, - ContextController contextController, ServletContext servletContext, ClassLoader legacyTCCL) { + ContextController contextController, ServletContext servletContext) { - super(servletHolder, servletDTO, servletContextHelper, contextController, legacyTCCL); + super(servletHolder, servletDTO, servletContextHelper, contextController); this.errorPageDTO = errorPageDTO; @@ -72,7 +73,7 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO needDecode = MatchableRegistration.patternsRequireDecode(servletDTO.patterns); } - public ErrorPageDTO getErrorPageDTO() { + public ExtendedErrorPageDTO getErrorPageDTO() { return errorPageDTO; } @@ -92,6 +93,11 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO } @Override + public ServiceReference<?> getServiceReference() { + return servletHolder.getServiceReference(); + } + + @Override public String match( String name, String servletPath, String pathInfo, String extension, Match match) { @@ -126,6 +132,6 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO } private final boolean needDecode; - private final ErrorPageDTO errorPageDTO; + private final ExtendedErrorPageDTO errorPageDTO; private final MultipartSupport multipartSupport; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java index bd5e63e1d..e7f5bc44a 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2019 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -25,6 +25,7 @@ import javax.servlet.http.*; import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.context.DispatchTargets; import org.eclipse.equinox.http.servlet.internal.registration.EndpointRegistration; +import org.eclipse.equinox.http.servlet.internal.registration.ServletRegistration; import org.eclipse.equinox.http.servlet.internal.util.Const; import org.eclipse.equinox.http.servlet.internal.util.EventListeners; import org.osgi.service.http.HttpContext; @@ -443,6 +444,20 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return new ArrayList<Part>(getParts0().values()); } + public AsyncContext startAsync() throws IllegalStateException { + EndpointRegistration<?> endpointRegistration = dispatchTargets.peek().getServletRegistration(); + + if (endpointRegistration instanceof ServletRegistration) { + ServletRegistration servletRegistration = (ServletRegistration)endpointRegistration; + + if (servletRegistration.getD().asyncSupported) { + return request.startAsync(); + } + } + + throw new IllegalStateException("Async not supported by " + endpointRegistration); //$NON-NLS-1$ + } + private Map<String, Part> getParts0() throws IOException, ServletException { org.eclipse.equinox.http.servlet.internal.registration.ServletRegistration servletRegistration = getServletRegistration(); @@ -474,4 +489,4 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return null; } -}
\ No newline at end of file +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java index 2cfcd70ed..8bb8aebd1 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2019 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -85,7 +85,7 @@ public class HttpSessionAdaptor implements HttpSession, Serializable { /**@deprecated*/ public String[] getValueNames() { Collection<String> result = getAttributeNames0(); - return result.toArray(new String[result.size()]); + return result.toArray(new String[0]); } public void invalidate() { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/Match.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/Match.java index 6d512d6d4..ab69bf783 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/Match.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/Match.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -19,6 +19,6 @@ package org.eclipse.equinox.http.servlet.internal.servlet; */ public enum Match { - EXACT, EXTENSION, REGEX, DEFAULT_SERVLET + EXACT, EXTENSION, REGEX, DEFAULT_SERVLET, CONTEXT_ROOT -}
\ No newline at end of file +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResponseStateHandler.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResponseStateHandler.java index 7aa55ac08..c3f820753 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResponseStateHandler.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResponseStateHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -24,6 +24,7 @@ import org.eclipse.equinox.http.servlet.internal.context.ContextController; import org.eclipse.equinox.http.servlet.internal.context.DispatchTargets; import org.eclipse.equinox.http.servlet.internal.registration.EndpointRegistration; import org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration; +import org.eclipse.equinox.http.servlet.internal.util.HttpStatus; /** * @author Raymond Augé @@ -84,7 +85,9 @@ public class ResponseStateHandler { setException(e); - if (dispatchTargets.getDispatcherType() != DispatcherType.REQUEST) { + if (dispatchTargets.getDispatcherType() != DispatcherType.ERROR && + dispatchTargets.getDispatcherType() != DispatcherType.REQUEST) { + throwException(e); } } @@ -95,6 +98,43 @@ public class ResponseStateHandler { filterRegistration.removeReference(); } + if ((exception != null) && dispatchTargets.getDispatcherType() == DispatcherType.ERROR) { + // This was the error handler throwing an error. + // We have to handle this with a custom error page of our own. + + PrintWriter writer = response.getWriter(); + + Integer status = (Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + String message = (String)request.getAttribute(RequestDispatcher.ERROR_MESSAGE); + + if (message == null) { + message = exception.getMessage(); + } + + request.getServletContext().log(message, exception); + + final HttpStatus httpStatus = HttpStatus.of(status); + + writer.println("<!DOCTYPE html>"); //$NON-NLS-1$ + writer.println("<html lang=\"en\"><head>"); //$NON-NLS-1$ + writer.println("<meta charset=\"utf-8\" />"); //$NON-NLS-1$ + writer.println("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />"); //$NON-NLS-1$ + writer.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"); //$NON-NLS-1$ + writer.print("<title>"); //$NON-NLS-1$ + writer.print(httpStatus.value()); + writer.print(" - "); //$NON-NLS-1$ + writer.print(httpStatus.description()); + writer.println("</title></head>"); //$NON-NLS-1$ + writer.print("<body><div><h1>"); //$NON-NLS-1$ + writer.print(httpStatus.value()); + writer.print(" <small>"); //$NON-NLS-1$ + writer.print(httpStatus.description()); + writer.println("</small></h1>"); //$NON-NLS-1$ + writer.print("<p>"); //$NON-NLS-1$ + writer.print(message); + writer.println("</p></div></body></html>"); //$NON-NLS-1$ + } + if (dispatchTargets.getDispatcherType() == DispatcherType.FORWARD) { response.flushBuffer(); @@ -171,11 +211,24 @@ public class ResponseStateHandler { } ContextController contextController = dispatchTargets.getContextController(); - Class<? extends Exception> clazz = exception.getClass(); - final String className = clazz.getName(); + Class<?> clazz = exception.getClass(); + final String originalClassName = clazz.getName(); + String className = originalClassName; + + DispatchTargets errorDispatchTargets; + + do { + errorDispatchTargets = contextController.getDispatchTargets( + className, null, null, null, null, null, Match.EXACT, null); - final DispatchTargets errorDispatchTargets = contextController.getDispatchTargets( - className, null, null, null, null, null, Match.EXACT, null); + if (errorDispatchTargets != null) { + break; + } + + clazz = clazz.getSuperclass(); + className = clazz.getName(); + } + while (Exception.class.isAssignableFrom(clazz)); if (errorDispatchTargets == null) { throwException(exception); @@ -196,7 +249,7 @@ public class ResponseStateHandler { if (attributeName.equals(RequestDispatcher.ERROR_EXCEPTION)) { return exception; } else if (attributeName.equals(RequestDispatcher.ERROR_EXCEPTION_TYPE)) { - return className; + return originalClassName; } else if (attributeName.equals(RequestDispatcher.ERROR_MESSAGE)) { return exception.getMessage(); } else if (attributeName.equals(RequestDispatcher.ERROR_REQUEST_URI)) { @@ -340,4 +393,4 @@ public class ResponseStateHandler { HttpServletRequest request; HttpServletResponse response; -}
\ No newline at end of file +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/Const.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/Const.java index c71f0f806..2a725ff97 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/Const.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/Const.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Raymond Augé and others. + * Copyright (c) 2014, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -48,7 +48,6 @@ public class Const { public static final String EQUINOX_HTTP_MULTIPART_MAXFILESIZE = "equinox.http.whiteboard.servlet.multipart.maxFileSize"; //$NON-NLS-1$ public static final String EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE = "equinox.http.whiteboard.servlet.multipart.maxRequestSize"; //$NON-NLS-1$ public static final String EQUINOX_LEGACY_TCCL_PROP = "equinox.legacy.tccl"; //$NON-NLS-1$ - public static final String EQUINOX_LEGACY_CONTEXT_SELECT = "equinox.context.select"; //$NON-NLS-1$ public static final String EQUINOX_LEGACY_CONTEXT_HELPER = "equinox.legacy.context.helper"; //$NON-NLS-1$ public static final String EQUINOX_LEGACY_HTTP_CONTEXT_INITIATING_ID = "equinox.legacy.http.context.initiating.id"; //$NON-NLS-1$ public static final String UTF8 = "UTF-8"; //$NON-NLS-1$ diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/DTOUtil.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/DTOUtil.java index d22f41344..59899f3fc 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/DTOUtil.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/DTOUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2016 Raymond Augé and others. + * Copyright (c) 2015, 2019 Raymond Augé and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -41,6 +41,22 @@ public class DTOUtil { return clone; } + public static FailedErrorPageDTO clone(FailedErrorPageDTO original) { + FailedErrorPageDTO clone = new FailedErrorPageDTO(); + + clone.asyncSupported = copy(original.asyncSupported); + clone.errorCodes = copy(original.errorCodes); + clone.exceptions = copy(original.exceptions); + clone.failureReason = copy(original.failureReason); + clone.initParams = copyStringMap(original.initParams); + clone.name = copy(original.name); + clone.serviceId = copy(original.serviceId); + clone.servletContextId = copy(original.servletContextId); + clone.servletInfo = copy(original.servletInfo); + + return clone; + } + public static FailedFilterDTO clone(FailedFilterDTO original) { FailedFilterDTO clone = new FailedFilterDTO(); @@ -177,7 +193,7 @@ public class DTOUtil { private static long[] copy(long[] array) { if (array == null) { - return null; + return new long[0]; } if (array.length == 0) { return array; @@ -188,7 +204,7 @@ public class DTOUtil { private static String[] copy(String[] array) { if (array == null) { - return null; + return new String[0]; } if (array.length == 0) { return array; @@ -223,14 +239,14 @@ public class DTOUtil { } private static Map<String, String> copyStringMap(Map<String, String> initParams) { + if (initParams == null) { + return Collections.emptyMap(); + } return new HashMap<String, String>(initParams); } public static <V> Map<String, Object> copyGenericMap(Map<String, V> value) { - if (value == null) { - return null; - } - if (value.isEmpty()) { + if ((value == null) || value.isEmpty()) { return Collections.emptyMap(); } HashMap<String, Object> result = new HashMap<String, Object>(); diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpStatus.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpStatus.java new file mode 100644 index 000000000..5db5d3e08 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpStatus.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.internal.util; + +/** + * @author Raymond Augé + */ +public enum HttpStatus { + + UNKNOWN_STATUS(-1, "Unknown Status", ""), //$NON-NLS-1$ //$NON-NLS-2$ + + CONTINUE(100, "Continue", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + SWITCHING_PROTOCOLS(101, "Switching Protocols", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + PROCESSING(102, "Processing", "RFC2518"), //$NON-NLS-1$ //$NON-NLS-2$ + + EARLY_HINTS(103, "Early Hints", "RFC8297"), //$NON-NLS-1$ //$NON-NLS-2$ + + OK(200, "OK", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + CREATED(201, "Created", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + ACCEPTED(202, "Accepted", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NON_AUTHORITATIVE_INFORMATION(203, "Non Authoritative Information", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NO_CONTENT(204, "No Content", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + RESET_CONTENT(205, "Reset Content", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + PARTIAL_CONTENT(206, "Partial Content", "RFC7233"), //$NON-NLS-1$ //$NON-NLS-2$ + /** )*/ + MULTI_STATUS(207, "Partial Update OK", "RFC4918"), //$NON-NLS-1$ //$NON-NLS-2$ + + ALREADY_REPORTED(208, "Already Reported", "RFC5842"), //$NON-NLS-1$ //$NON-NLS-2$ + + IM_USED(226, "IM Used", "RFC3229"), //$NON-NLS-1$ //$NON-NLS-2$ + + MULTIPLE_CHOICES(300, "Multiple Choices", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + MOVED_PERMANENTLY(301, "Moved Permanently", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + MOVED_TEMPORARILY(302, "Found", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + SEE_OTHER(303, "See Other", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NOT_MODIFIED(304, "Not Modified", "RFC7232"), //$NON-NLS-1$ //$NON-NLS-2$ + + USE_PROXY(305, "Use Proxy", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + TEMPORARY_REDIRECT(307, "Temporary Redirect", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + PERMANENT_REDIRECT(308, "Permanent Redirect", "RFC7538"), //$NON-NLS-1$ //$NON-NLS-2$ + + BAD_REQUEST(400, "Bad Request", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + UNAUTHORIZED(401, "Unauthorized", "RFC7235"), //$NON-NLS-1$ //$NON-NLS-2$ + + PAYMENT_REQUIRED(402, "Payment Required", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + FORBIDDEN(403, "Forbidden", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NOT_FOUND(404, "Not Found", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + METHOD_NOT_ALLOWED(405, "Method Not Allowed", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NOT_ACCEPTABLE(406, "Not Acceptable", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required", "RFC7235"), //$NON-NLS-1$ //$NON-NLS-2$ + + REQUEST_TIMEOUT(408, "Request Timeout", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + CONFLICT(409, "Conflict", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + GONE(410, "Gone", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + LENGTH_REQUIRED(411, "Length Required", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + PRECONDITION_FAILED(412, "Precondition Failed", "RFC7232"), //$NON-NLS-1$ //$NON-NLS-2$ + + PAYLOAD_TOO_LARGE(413, "Payload Too Large", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + URI_TOO_LONG(414, "URI Too Long", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + RANGE_NOT_SATISFIABLE(416, "Range Not Satisfiable", "RFC7233"), //$NON-NLS-1$ //$NON-NLS-2$ + + EXPECTATION_FAILED(417, "Expectation Failed", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + MISDIRECTED_REQUEST(421, "Misdirected Request", "RFC7540"), //$NON-NLS-1$ //$NON-NLS-2$ + + UNPROCESSABLE_ENTITY(422, "Unprocessable Entity", "RFC4918"), //$NON-NLS-1$ //$NON-NLS-2$ + + LOCKED(423, "Locked", "RFC4918"), //$NON-NLS-1$ //$NON-NLS-2$ + + FAILED_DEPENDENCY(424, "Failed Dependency", "RFC4918"), //$NON-NLS-1$ //$NON-NLS-2$ + + PRECONDITION_REQUIRED(428, "Precondition Required", "RFC6585"), //$NON-NLS-1$ //$NON-NLS-2$ + + TOO_MANY_REQUESTS(429, "Too Many Requests", "RFC6585"), //$NON-NLS-1$ //$NON-NLS-2$ + + REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large", "RFC6585"), //$NON-NLS-1$ //$NON-NLS-2$ + + UNAVAILABLE_FOR_LEGAL_REASONS(451, "Unavailable For Legal Reasons", "RFC7725"), //$NON-NLS-1$ //$NON-NLS-2$ + + INTERNAL_SERVER_ERROR(500, "Internal Server Error", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + NOT_IMPLEMENTED(501, "Not Implemented", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + BAD_GATEWAY(502, "Bad Gateway", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + SERVICE_UNAVAILABLE(503, "Service Unavailable", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + GATEWAY_TIMEOUT(504, "Gateway Timeout", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported", "RFC7231"), //$NON-NLS-1$ //$NON-NLS-2$ + + VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates", "RFC2295"), //$NON-NLS-1$ //$NON-NLS-2$ + + INSUFFICIENT_STORAGE(507, "Insufficient Storage", "RFC4918"), //$NON-NLS-1$ //$NON-NLS-2$ + + LOOP_DETECTED(508, "Loop Detected", "RFC5842"), //$NON-NLS-1$ //$NON-NLS-2$ + + NOT_EXTENDED(510, "Not Extended", "RFC2774"), //$NON-NLS-1$ //$NON-NLS-2$ + + NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required", "RFC6585"); //$NON-NLS-1$ //$NON-NLS-2$ + + private HttpStatus(int value, String description, String reference) { + this.value = value; + this.description = description; + this.reference = reference; + } + + public String description() { + return description; + } + + public String reference() { + return reference; + } + + public int value() { + return value; + } + + private final int value; + private final String description; + private final String reference; + + public static HttpStatus of(int value) { + for (HttpStatus v : HttpStatus.values()) { + if (v.value == value) { + return v; + } + } + return UNKNOWN_STATUS; + } +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/ServiceProperties.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/ServiceProperties.java index bca5f1031..7ef15ed07 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/ServiceProperties.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/ServiceProperties.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2015 Liferay, Inc. + * Copyright (c) 2014, 2019 Liferay, Inc. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -50,9 +50,11 @@ public class ServiceProperties { } for (String key : serviceReference.getPropertyKeys()) { if (key.startsWith(prefix)) { + Object value = serviceReference.getProperty(key); + if (value instanceof String) { initParams.put( - key.substring(prefix.length()), - String.valueOf(serviceReference.getProperty(key))); + key.substring(prefix.length()), (String)value); + } } } |