diff options
author | Raymond Auge | 2019-01-31 15:41:45 +0000 |
---|---|---|
committer | Raymond Auge | 2019-02-06 19:39:40 +0000 |
commit | 7d6da7c9bdf36bf132bd5384d909651b97c770ca (patch) | |
tree | f1139d3128c6de0dd47fe94c9678fded21db69d9 | |
parent | 036a8c573d1e3fdceab9d026494a3c1e6ac0c846 (diff) | |
download | rt.equinox.bundles-7d6da7c9bdf36bf132bd5384d909651b97c770ca.tar.gz rt.equinox.bundles-7d6da7c9bdf36bf132bd5384d909651b97c770ca.tar.xz rt.equinox.bundles-7d6da7c9bdf36bf132bd5384d909651b97c770ca.zip |
Bug 544011 - [http whiteboard] update to R7 (http whiteboard 1.1)Y20190206-2200I20190206-1800
Signed-off-by: Raymond Auge <raymond.auge@liferay.com>
67 files changed, 2710 insertions, 836 deletions
diff --git a/bundles/org.eclipse.equinox.http.jetty/.settings/.api_filters b/bundles/org.eclipse.equinox.http.jetty/.settings/.api_filters deleted file mode 100644 index 8c66a0355..000000000 --- a/bundles/org.eclipse.equinox.http.jetty/.settings/.api_filters +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<component id="org.eclipse.equinox.http.jetty" version="2"> - <resource path="src/org/eclipse/equinox/http/jetty/JettyConstants.java" type="org.eclipse.equinox.http.jetty.JettyConstants"> - <filter id="1209008130"> - <message_arguments> - <message_argument value="1.5"/> - <message_argument value="3.7"/> - <message_argument value="HOUSEKEEPER_INTERVAL"/> - </message_arguments> - </filter> - </resource> -</component> diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF index 7dec26cdc..cf06baa9e 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.equinox.http.servlet.tests Bundle-SymbolicName: org.eclipse.equinox.http.servlet.tests -Bundle-Version: 1.5.300.qualifier +Bundle-Version: 1.6.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Eclipse-BundleShape: dir Require-Bundle: org.junit;bundle-version="4.0" diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml index a9b7e11a7..1be02a941 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml +++ b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.http.servlet.tests</artifactId> - <version>1.5.300-SNAPSHOT</version> + <version>1.6.0-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <build> diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java index d2f0dfe60..129fca466 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java @@ -13,8 +13,13 @@ *******************************************************************************/ package org.eclipse.equinox.http.servlet.testbase; +import org.eclipse.equinox.http.servlet.tests.AuthenticationTest; import org.eclipse.equinox.http.servlet.tests.DispatchingTest; +import org.eclipse.equinox.http.servlet.tests.PreprocessorTestCase; import org.eclipse.equinox.http.servlet.tests.ServletTest; +import org.eclipse.equinox.http.servlet.tests.TestHttpServiceAndErrorPage; +import org.eclipse.equinox.http.servlet.tests.TestHttpServiceAndNamedServlet; +import org.eclipse.equinox.http.servlet.tests.TestUpload; import org.eclipse.equinox.http.servlet.tests.Test_140_11_3; import org.eclipse.equinox.http.servlet.tests.Test_140_2_17to22; import org.eclipse.equinox.http.servlet.tests.Test_140_2_26to27; @@ -36,6 +41,7 @@ import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_C import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_tieGoesToOldest; import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_PATH_type; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED; +import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_4xx; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_exception; import org.eclipse.equinox.http.servlet.tests.Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_error; @@ -49,7 +55,9 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({ + AuthenticationTest.class, DispatchingTest.class, + PreprocessorTestCase.class, ServletTest.class, Test_140_11_3.class, Test_140_2_17to22.class, @@ -72,13 +80,17 @@ import org.junit.runners.Suite.SuiteClasses; Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_tieGoesToOldest.class, Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_PATH_type.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED.class, + Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_4xx.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_exception.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_error.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_request.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_REGEX.class, - Test_table_140_6_HTTP_WHITEBOARD_RESOURCE_validation.class + Test_table_140_6_HTTP_WHITEBOARD_RESOURCE_validation.class, + TestHttpServiceAndErrorPage.class, + TestHttpServiceAndNamedServlet.class, + TestUpload.class, }) public class AllTests { // see @SuiteClasses diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java index 1a8022cb1..e4f2617f8 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java @@ -15,6 +15,7 @@ package org.eclipse.equinox.http.servlet.testbase; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.OutputStream; @@ -29,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -57,6 +59,7 @@ import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.http.HttpService; +import org.osgi.service.http.NamespaceException; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.HttpServiceRuntime; import org.osgi.service.http.runtime.HttpServiceRuntimeConstants; @@ -73,6 +76,7 @@ import org.osgi.service.http.runtime.dto.ServletContextDTO; import org.osgi.service.http.runtime.dto.ServletDTO; import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; public class BaseTest { @@ -92,7 +96,34 @@ public class BaseTest { advisor = new BundleAdvisor(bundleContext); stopJetty(); startBundles(); - runtimeTracker = new ServiceTracker<>(bundleContext, HttpServiceRuntime.class, null); + runtimeTracker = new ServiceTracker<>(bundleContext, HttpServiceRuntime.class, new ServiceTrackerCustomizer<HttpServiceRuntime,ServiceReference<HttpServiceRuntime>>() { + + @Override + public ServiceReference<HttpServiceRuntime> addingService( + ServiceReference<HttpServiceRuntime> reference) { + final Object obj = reference + .getProperty(Constants.SERVICE_CHANGECOUNT); + if (obj != null) { + httpRuntimeChangeCount.set(Long.valueOf(obj.toString())); + } + return reference; + } + + @Override + public void modifiedService( + ServiceReference<HttpServiceRuntime> reference, + ServiceReference<HttpServiceRuntime> service) { + addingService(reference); + } + + @Override + public void removedService( + ServiceReference<HttpServiceRuntime> reference, + ServiceReference<HttpServiceRuntime> service) { + httpRuntimeChangeCount.set(-1); + } + + }); runtimeTracker.open(); runtimeTracker.waitForService(100); startJetty(); @@ -454,6 +485,99 @@ public class BaseTest { return getHttpServiceRuntime().getRuntimeDTO().failedResourceDTOs; } + protected long waitForRegistration(final long previousCount) { + return waitForRegistration(previousCount, 100); + } + + protected long waitForRegistration(final long previousCount, + int maxAttempts) { + while (this.httpRuntimeChangeCount.longValue() == previousCount) { + if (maxAttempts <= 0) { + throw new IllegalStateException("Max attempts exceeded"); + } + try { + Thread.sleep(20L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + maxAttempts--; + } + return this.httpRuntimeChangeCount.longValue(); + } + + protected long getHttpRuntimeChangeCount() { + return httpRuntimeChangeCount.longValue(); + } + + protected void registerDummyServletInHttpService() + throws ServletException, NamespaceException { + final String path = "/tesths"; + final HttpService service = this.getHttpService(); + service.registerServlet(path, new HttpServlet() { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, + HttpServletResponse resp) throws IOException { + resp.getWriter().print("helloworld"); + resp.flushBuffer(); + } + }, null, null); + } + + protected void unregisterDummyServletFromHttpService() { + this.getHttpService().unregister("/tesths"); + } + + protected ServletContextDTO getServletContextDTOForDummyServlet() { + for (final ServletContextDTO dto : this.getHttpServiceRuntime() + .getRuntimeDTO().servletContextDTOs) { + for (final ServletDTO sd : dto.servletDTOs) { + if (sd.patterns.length > 0 + && "/tesths".equals(sd.patterns[0])) { + return dto; + } + } + } + fail("Servlet context for http service not found"); + return null; + } + + protected FailedErrorPageDTO getFailedErrorPageDTOByException( + String exception) { + for (FailedErrorPageDTO failedErrorPageDTO : getFailedErrorPageDTOs()) { + for (String ex : failedErrorPageDTO.exceptions) { + if (exception.equals(ex)) { + return failedErrorPageDTO; + } + } + } + + return null; + } + + protected ErrorPageDTO getErrorPageDTOByException(String context, + String exception) { + ServletContextDTO servletContextDTO = getServletContextDTOByName( + context); + + if (servletContextDTO == null) { + return null; + } + + for (ErrorPageDTO errorPageDTO : servletContextDTO.errorPageDTOs) { + for (String ex : errorPageDTO.exceptions) { + if (exception.equals(ex)) { + return errorPageDTO; + } + } + } + + return null; + } + + final AtomicLong httpRuntimeChangeCount = new AtomicLong(-1); + protected static final String PROTOTYPE = "prototype/"; protected static final String CONFIGURE = "configure"; protected static final String UNREGISTER = "unregister"; @@ -480,7 +604,7 @@ public class BaseTest { protected BundleAdvisor advisor; protected ServletRequestAdvisor requestAdvisor; protected final Collection<ServiceRegistration<? extends Object>> registrations = new ArrayList<ServiceRegistration<? extends Object>>(); - protected ServiceTracker<HttpServiceRuntime, HttpServiceRuntime> runtimeTracker; + protected ServiceTracker<HttpServiceRuntime, ServiceReference<HttpServiceRuntime>> runtimeTracker; protected static class TestFilter implements Filter { AtomicInteger called = new AtomicInteger(0); diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java new file mode 100644 index 000000000..2c1dd6261 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.osgi.service.http.context.ServletContextHelper; + +public class AuthenticationTest extends BaseTest { + + @Test + public void test_forwardSecurity() throws Exception { + final List<String> callStack = new ArrayList<>(); + setup(callStack); + + // request without auth -> no servlet invoked + requestAdvisor.request("context1/servlet?forward=true"); + assertTrue(callStack.isEmpty()); + + // request with auth and forward -> servlet invoked + requestAdvisor.request("context1/servlet?forward=true&auth=true"); + assertEquals(6, callStack.size()); + assertEquals(Arrays.asList("handle1", "servlet/context1", "handle1", "servlet/context1", "finish1", "finish1"), callStack); + callStack.clear(); + } + + @Test + public void test_handleFinishSecurity() throws Exception { + final List<String> callStack = new ArrayList<>(); + setup(callStack); + + // request without auth -> no servlet invoked + requestAdvisor.request("context1/servlet"); + assertTrue(callStack.isEmpty()); + + // request with auth -> servlet invoked + requestAdvisor.request("context1/servlet?auth=true"); + assertEquals(3, callStack.size()); + assertEquals(Arrays.asList("handle1", "servlet/context1", "finish1"), callStack); + callStack.clear(); + + // request to context2, no auth required + requestAdvisor.request("context2/servlet"); + assertEquals(3, callStack.size()); + assertEquals(Arrays.asList("handle2", "servlet/context2", "finish2"), callStack); + } + + private static final String AUTH_PAR = "auth"; + + private static final String REC_PAR = "rec"; + + private void setup(final List<String> callStack) throws Exception { + final BundleContext context = getBundleContext(); + + // setup context 1 + final Dictionary<String,Object> ctx1Props = new Hashtable<String,Object>(); + ctx1Props.put(HTTP_WHITEBOARD_CONTEXT_NAME, "context1"); + ctx1Props.put(HTTP_WHITEBOARD_CONTEXT_PATH, "/context1"); + registrations.add(context.registerService( + ServletContextHelper.class, + new ServletContextHelper() { + + @Override + public boolean handleSecurity(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + + if (request.getParameter(AUTH_PAR) != null) { + callStack.add("handle1"); + return true; + } + return false; + } + + @Override + public void finishSecurity(final HttpServletRequest request, final HttpServletResponse response) { + callStack.add("finish1"); + } + + }, + ctx1Props) + ); + + // setup context 2 + final Dictionary<String,Object> ctx2Props = new Hashtable<String,Object>(); + ctx2Props.put(HTTP_WHITEBOARD_CONTEXT_NAME, "context2"); + ctx2Props.put(HTTP_WHITEBOARD_CONTEXT_PATH, "/context2"); + registrations.add(context.registerService( + ServletContextHelper.class, + new ServletContextHelper() { + + @Override + public boolean handleSecurity(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + + callStack.add("handle2"); + return true; + } + + @Override + public void finishSecurity(final HttpServletRequest request, final HttpServletResponse response) { + callStack.add("finish2"); + } + + }, + ctx2Props) + ); + + // servlet for both contexts + @SuppressWarnings("serial") + class AServlet extends HttpServlet { + + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + + callStack.add("servlet" + request.getContextPath()); + + if (request.getContextPath().equals("/context1") + && request.getAttribute(REC_PAR) == null) { + if (request.getParameter("forward") != null) { + request.setAttribute(REC_PAR, "true"); + request.getRequestDispatcher("/servlet") + .forward(request, response); + return; + } else if (request.getParameter("include") != null) { + request.setAttribute(REC_PAR, "true"); + request.getRequestDispatcher("/servlet") + .include(request, response); + } else if (request.getParameter("throw") != null) { + callStack.add("throw"); + throw new ServletException("throw"); + } + } + response.setStatus(200); + } + + }; + + final Dictionary<String,Object> servletProps = new Hashtable<String,Object>(); + + servletProps.put(HTTP_WHITEBOARD_SERVLET_PATTERN, new String[] {"/servlet"}); + servletProps.put(HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=context1)"); + registrations.add(context.registerService(Servlet.class, new AServlet(), servletProps)); + + servletProps.put(HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=context2)"); + registrations.add(context.registerService(Servlet.class, new AServlet(), servletProps)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java new file mode 100644 index 000000000..22a3683a5 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import javax.servlet.FilterChain; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockPreprocessor; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.http.runtime.dto.PreprocessorDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; +import org.osgi.service.http.whiteboard.Preprocessor; + +public class PreprocessorTestCase extends BaseTest { + + @Test + public void testPreprocessorInitParameters() throws Exception { + Dictionary<String,Object> properties = new Hashtable<>(); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param1", "value1"); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param2", "value2"); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param3", 345l); + + long before = this.getHttpRuntimeChangeCount(); + final ServiceRegistration<Preprocessor> reg = getBundleContext() + .registerService(Preprocessor.class, new MockPreprocessor(), + properties); + registrations.add(reg); + this.waitForRegistration(before); + + final PreprocessorDTO[] dtos = this.getHttpServiceRuntime() + .getRuntimeDTO().preprocessorDTOs; + assertEquals(1, dtos.length); + + assertTrue(dtos[0].initParams.containsKey("param1")); + assertTrue(dtos[0].initParams.containsKey("param2")); + assertFalse(dtos[0].initParams.containsKey("param3")); + assertEquals(getServiceId(reg), dtos[0].serviceId); + } + + @Test + public void testPreprocessorRanking() throws Exception { + // register preprocessor with ranking -5 + Dictionary<String,Object> properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, -5); + + long before = this.getHttpRuntimeChangeCount(); + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("d"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with ranking 8 + properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, 8); + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("a"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with invalid ranking + properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, 3L); // this is invalid -> + // ranking = 0 + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("b"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with no ranking + properties = new Hashtable<>(); + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("c"), properties)); + before = this.waitForRegistration(before); + + // check that we have four preprocessors + final PreprocessorDTO[] dtos = this.getHttpServiceRuntime() + .getRuntimeDTO().preprocessorDTOs; + assertEquals(4, dtos.length); + + // register endpoint + properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/available"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet().content("hello"), properties)); + + assertEquals("abcdhellodcba", requestAdvisor.request("available")); + } + + /** + * Test a request with a servlet registered at that url and check if the + * preprocessor is invoked. Do the same with a non existing url. + */ + @Test + public void testPreprocessorInvocation() throws Exception { + // register preprocessor + final List<String> filterActions = new ArrayList<>(); + long before = this.getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Preprocessor.class.getName(), new MockPreprocessor() { + + @Override + public void doFilter(ServletRequest request, + ServletResponse response, FilterChain chain) + throws IOException, ServletException { + filterActions.add("a"); + super.doFilter(request, new HttpServletResponseWrapper( + (HttpServletResponse) response) { + + private boolean hasStatus = false; + + private void addStatus(final int sc) { + if (!hasStatus) { + hasStatus = true; + filterActions.add(String.valueOf(sc)); + } + } + + @Override + public void setStatus(int sc) { + addStatus(sc); + super.setStatus(sc); + } + + @Override + public void sendError(int sc, String msg) + throws IOException { + addStatus(sc); + super.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + addStatus(sc); + super.sendError(sc); + } + + }, chain); + filterActions.add("b"); + } + + }, null)); + before = this.waitForRegistration(before); + + // register endpoint + Dictionary<String,Object> properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/available"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet().content("hello"), properties)); + + assertEquals("hello", requestAdvisor.request("available")); + assertEquals(2, filterActions.size()); + assertEquals("a", filterActions.get(0)); + assertEquals("b", filterActions.get(1)); + + // request a non existing pattern - this will somehow set the status + // code to 404 + filterActions.clear(); + requestAdvisor.request("foo", null); + assertEquals(3, filterActions.size()); + assertEquals("a", filterActions.get(0)); + assertEquals("404", filterActions.get(1)); + assertEquals("b", filterActions.get(2)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java index 2a835c755..299c6febb 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java @@ -2666,7 +2666,6 @@ public class ServletTest extends BaseTest { List<FileItem> items = null; try { - @SuppressWarnings("unchecked") List<FileItem> parseRequest = upload.parseRequest(req); items = parseRequest; } catch (FileUploadException e) { diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java new file mode 100644 index 000000000..1a550fa1b --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.service.http.runtime.dto.ServletContextDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class TestHttpServiceAndErrorPage extends BaseTest { + + /** + * Registration of error page with http service (allowed) and error page and + * pattern with http service (not allowed) + */ + @Test + public void testHttpServiceAndErrorPage() throws Exception { + registerDummyServletInHttpService(); + try { + final String name1 = "testname1"; + final String name2 = "testname2"; + Dictionary<String,Object> properties = new Hashtable<String,Object>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, + name1); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + long before = getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + properties = new Hashtable<>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/" + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + assertNull(getFailedErrorPageDTOByException(name1)); + assertNotNull("" + getHttpServiceRuntime().getRuntimeDTO(), + getFailedErrorPageDTOByException(name2)); + + final ServletContextDTO scDTO = getServletContextDTOForDummyServlet(); + assertNotNull(getErrorPageDTOByException(scDTO.name, name1)); + assertNull(getErrorPageDTOByException(scDTO.name, name2)); + } finally { + unregisterDummyServletFromHttpService(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java new file mode 100644 index 000000000..ade206faf --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.service.http.runtime.dto.ServletContextDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class TestHttpServiceAndNamedServlet extends BaseTest { + + /** + * Registration of named servlet with http service (allowed) and named + * servlet and pattern with http service (not allowed) + */ + @Test + public void testHttpServiceAndNamedServlet() throws Exception { + registerDummyServletInHttpService(); + try { + final String name1 = "testname1"; + final String name2 = "testname2"; + Dictionary<String,Object> properties = new Hashtable<String,Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, + name1); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + long before = getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/" + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + assertNull(getFailedServletDTOByName(name1)); + assertNotNull("" + getHttpServiceRuntime().getRuntimeDTO(), + getFailedServletDTOByName(name2)); + + final ServletContextDTO scDTO = getServletContextDTOForDummyServlet(); + assertNotNull(getServletDTOByName(scDTO.name, name1)); + assertNull(getServletDTOByName(scDTO.name, name2)); + } finally { + unregisterDummyServletFromHttpService(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java new file mode 100644 index 000000000..ed5804b14 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Part; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; + +public class TestUpload extends BaseTest { + + @Test + public void testUpload() throws Exception { + final CountDownLatch receivedLatch = new CountDownLatch(1); + final Map<String,Long> contents = new HashMap<>(); + setupUploadServlet(receivedLatch, contents); + + postContent(getClass().getResource("resource1.txt"), 201); + assertTrue(receivedLatch.await(5, TimeUnit.SECONDS)); + assertEquals(1, contents.size()); + assertEquals(25L, (long) contents.get("text.txt")); + } + + private void setupUploadServlet(final CountDownLatch receivedLatch, + final Map<String,Long> contents) + throws Exception { + final Dictionary<String,Object> servletProps = new Hashtable<String,Object>(); + servletProps.put(HTTP_WHITEBOARD_SERVLET_PATTERN, "/post"); + servletProps.put(HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED, + Boolean.TRUE); + servletProps.put(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE, 1024L); + + @SuppressWarnings("serial") + final Servlet uploadServlet = new HttpServlet() { + @Override + protected void doPost(HttpServletRequest req, + HttpServletResponse resp) + throws IOException, ServletException { + try { + final Collection<Part> parts = req.getParts(); + for (final Part p : parts) { + contents.put(p.getName(), p.getSize()); + } + resp.setStatus(201); + } finally { + receivedLatch.countDown(); + } + + } + }; + + long before = this.getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class.getName(), uploadServlet, servletProps)); + this.waitForRegistration(before); + } + + private void postContent(final URL resource, final int expectedRT) throws IOException { + Map<String, List<Object>> map = new HashMap<String, List<Object>>(); + + map.put("method", Arrays.<Object>asList("POST")); + map.put("text.txt", Arrays.<Object>asList(resource)); + + Map<String, List<String>> result = requestAdvisor.upload("post", map); + + assertEquals(expectedRT + "", result.get("responseCode").get(0)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java index 08ac3ef5d..3b9dce65d 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java @@ -67,7 +67,7 @@ public class Test_140_4_9 extends BaseTest { invoked.set(false); assertEquals("a", requestAdvisor.request("some/path/b.html")); assertTrue(invoked.get()); - assertEquals("404", requestAdvisor.request("", null).get("responseCode").get(0)); + assertEquals("a", requestAdvisor.request("")); } } diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java new file mode 100644 index 000000000..62c6d72ec --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; +import javax.servlet.http.HttpServlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.osgi.service.http.runtime.dto.RequestInfoDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate extends BaseTest { + + @SuppressWarnings("serial") + @Test + public void test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate() throws Exception { + BundleContext context = getBundleContext(); + + Dictionary<String, Object> properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "blah"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/a"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + RequestInfoDTO requestInfoDTO = calculateRequestInfoDTO("/a"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "true"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/b"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/b"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertTrue(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "false"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/c"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/c"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, 234l); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/d"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/d"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/e"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/e"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java index 7e06520df..bd2d91867 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java @@ -68,7 +68,7 @@ public class Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN extends BaseTest { assertEquals("bab", requestAdvisor.request("a")); assertEquals("bab", requestAdvisor.request("a.html")); assertEquals("bab", requestAdvisor.request("some/path/b.html")); - assertEquals("a", requestAdvisor.request("")); + assertEquals("bab", requestAdvisor.request("")); properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, ""); sr.setProperties(properties); diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java new file mode 100644 index 000000000..f4edb2350 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * 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. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests.util; + +import org.osgi.service.http.whiteboard.Preprocessor; + +public class MockPreprocessor extends MockFilter implements Preprocessor { + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java index 6d03d4015..a5f82a12b 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java @@ -281,6 +281,10 @@ public class ServletRequestAdvisor extends Object { connection.setReadTimeout(150 * 1000); if (headers != null) { + if (headers.containsKey("method")) { + connection.setRequestMethod((String)headers.remove("method").get(0)); + } + for(Map.Entry<String, List<Object>> entry : headers.entrySet()) { for(Object entryValue : entry.getValue()) { if (entryValue instanceof String) { @@ -339,7 +343,9 @@ public class ServletRequestAdvisor extends Object { writer.append("--" + boundary); writer.append(CRLF); - writer.append("Content-Disposition: form-data; name=\"file\"; filename=\""); + writer.append("Content-Disposition: form-data; name=\""); + writer.append(param); + writer.append("\"; filename=\""); writer.append(fileName); writer.append("\""); writer.append(CRLF); diff --git a/bundles/org.eclipse.equinox.http.servlet/.classpath b/bundles/org.eclipse.equinox.http.servlet/.classpath index 121e527a9..3bc247511 100644 --- a/bundles/org.eclipse.equinox.http.servlet/.classpath +++ b/bundles/org.eclipse.equinox.http.servlet/.classpath @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/bundles/org.eclipse.equinox.http.servlet/.settings/.api_filters b/bundles/org.eclipse.equinox.http.servlet/.settings/.api_filters index e2bd7154e..94630a559 100644 --- a/bundles/org.eclipse.equinox.http.servlet/.settings/.api_filters +++ b/bundles/org.eclipse.equinox.http.servlet/.settings/.api_filters @@ -8,4 +8,19 @@ </message_arguments> </filter> </resource> + <resource path="src/org/eclipse/equinox/http/servlet/internal/HttpServiceImpl.java" type="org.eclipse.equinox.http.servlet.internal.HttpServiceImpl"> + <filter id="574619656"> + <message_arguments> + <message_argument value="HttpService"/> + <message_argument value="HttpServiceImpl"/> + </message_arguments> + </filter> + <filter id="574668824"> + <message_arguments> + <message_argument value="ExtendedHttpService"/> + <message_argument value="HttpServiceImpl"/> + <message_argument value="HttpService"/> + </message_arguments> + </filter> + </resource> </component> diff --git a/bundles/org.eclipse.equinox.http.servlet/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.http.servlet/.settings/org.eclipse.jdt.core.prefs index e9c7c1250..303a5d60f 100644 --- a/bundles/org.eclipse.equinox.http.servlet/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/org.eclipse.equinox.http.servlet/.settings/org.eclipse.jdt.core.prefs @@ -16,9 +16,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullable.secondary= org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.7 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -120,7 +120,7 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=error org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.7 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=32 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 diff --git a/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF index 2c4d64375..38e4f6edc 100644 --- a/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF @@ -3,10 +3,10 @@ Bundle-ManifestVersion: 2 Bundle-Name: %bundleName Bundle-Vendor: %providerName Bundle-SymbolicName: org.eclipse.equinox.http.servlet -Bundle-Version: 1.5.300.qualifier +Bundle-Version: 1.6.0.qualifier Bundle-Activator: org.eclipse.equinox.http.servlet.internal.Activator Bundle-Localization: plugin -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Export-Package: org.eclipse.equinox.http.servlet;version="1.2.0", org.eclipse.equinox.http.servlet.context;version="1.0.0";x-internal:=true, org.eclipse.equinox.http.servlet.session;version="1.0.0";x-internal:=true, @@ -14,19 +14,19 @@ Export-Package: org.eclipse.equinox.http.servlet;version="1.2.0", Import-Package: org.apache.commons.fileupload;version="[1.2.2, 2.0.0)";resolution:=optional, org.apache.commons.fileupload.disk;version="[1.2.2, 2.0.0)";resolution:=optional, org.apache.commons.fileupload.servlet;version="[1.2.2, 2.0.0)";resolution:=optional, - javax.servlet;version="[2.3.0,5.0.0)", - javax.servlet.annotation;version="[2.6.0,5.0.0)";resolution:=optional, - javax.servlet.descriptor;version="[2.6.0,5.0.0)";resolution:=optional, - javax.servlet.http;version="[2.3.0,5.0.0)", + javax.servlet;version="[3.1.0,5.0.0)", + javax.servlet.annotation;version="[3.1.0,5.0.0)";resolution:=optional, + javax.servlet.descriptor;version="[3.1.0,5.0.0)";resolution:=optional, + javax.servlet.http;version="[3.1.0,5.0.0)", org.osgi.dto;version="[1.0.0,2.0)", org.osgi.framework;version="[1.3.0,2.0)", org.osgi.framework.dto; version="[1.8.0,2.0)", org.osgi.framework.wiring;version="[1.1.0,2.0)", org.osgi.service.http;version="[1.2,1.3)", - org.osgi.service.http.context;version="[1.0,1.1)", - org.osgi.service.http.runtime;version="[1.0,1.1)", - org.osgi.service.http.runtime.dto;version="[1.0,1.1)", - org.osgi.service.http.whiteboard;version="[1.0,1.1)", + org.osgi.service.http.context;version="[1.1,1.2)", + org.osgi.service.http.runtime;version="[1.1,1.2)", + org.osgi.service.http.runtime.dto;version="[1.1,1.2)", + org.osgi.service.http.whiteboard;version="[1.1,1.2)", org.osgi.util.tracker;version="[1.5,2.0)" Comment-Header: Both Eclipse-LazyStart and Bundle-ActivationPolicy are specified for compatibility with 3.2 Eclipse-LazyStart: true @@ -34,7 +34,7 @@ Bundle-ActivationPolicy: lazy Provide-Capability: osgi.implementation; osgi.implementation="osgi.http"; uses:="javax.servlet, javax.servlet.http, org.osgi.service.http.context, org.osgi.service.http.whiteboard"; - version:Version="1.0", + version:Version="1.1", osgi.service; objectClass:List<String>="org.osgi.service.http.HttpService"; uses:="org.osgi.service.http", diff --git a/bundles/org.eclipse.equinox.http.servlet/build.properties b/bundles/org.eclipse.equinox.http.servlet/build.properties index 0dca0665a..2e23860bf 100644 --- a/bundles/org.eclipse.equinox.http.servlet/build.properties +++ b/bundles/org.eclipse.equinox.http.servlet/build.properties @@ -20,3 +20,4 @@ bin.includes = META-INF/,\ src.includes = about.html jars.extra.classpath = osgi/osgi.annotation.jar +jre.compilation.profile = JavaSE-1.7 diff --git a/bundles/org.eclipse.equinox.http.servlet/pom.xml b/bundles/org.eclipse.equinox.http.servlet/pom.xml index a50ce572c..68717ad68 100644 --- a/bundles/org.eclipse.equinox.http.servlet/pom.xml +++ b/bundles/org.eclipse.equinox.http.servlet/pom.xml @@ -20,6 +20,6 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.http.servlet</artifactId> - <version>1.5.300-SNAPSHOT</version> + <version>1.6.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedFailedServletDTO.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedFailedServletDTO.java index e68aaad65..99aba1f1b 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedFailedServletDTO.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedFailedServletDTO.java @@ -20,31 +20,7 @@ import org.osgi.service.http.runtime.dto.FailedServletDTO; * This type may become irrelevant if the properties appear as part of a * future OSGi Http Whiteboard specification. */ +@Deprecated public class ExtendedFailedServletDTO extends FailedServletDTO { - - /** - * Specifies whether multipart support is enabled. - */ - public boolean multipartEnabled; - - /** - * Specifies the size threshold after which the file will be written to disk. - */ - public int multipartFileSizeThreshold; - - /** - * Specifies the location where the files can be stored on disk. - */ - public String multipartLocation; - - /** - * Specifies the maximum size of a file being uploaded. - */ - public long multipartMaxFileSize; - - /** - * Specifies the maximum request size. - */ - public long multipartMaxRequestSize; - + // ignore }
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedServletDTO.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedServletDTO.java index 5a509a99e..e1fd833f9 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedServletDTO.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/dto/ExtendedServletDTO.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Raymond Augé. + * Copyright (c) 2016, 2019 Raymond Augé. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -20,31 +20,7 @@ import org.osgi.service.http.runtime.dto.ServletDTO; * This type may become irrelevant if the properties appear as part of a * future OSGi Http Whiteboard specification. */ +@Deprecated public class ExtendedServletDTO extends ServletDTO { - - /** - * Specifies whether multipart support is enabled. - */ - public boolean multipartEnabled; - - /** - * Specifies the size threshold after which the file will be written to disk. - */ - public int multipartFileSizeThreshold; - - /** - * Specifies the location where the files can be stored on disk. - */ - public String multipartLocation; - - /** - * Specifies the maximum size of a file being uploaded. - */ - public long multipartMaxFileSize; - - /** - * Specifies the maximum request size. - */ - public long multipartMaxRequestSize; - + // deprecated }
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java index 02eba5344..b96d57927 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java @@ -167,21 +167,25 @@ public class Activator BundleContext trackingContext = useSystemContext ? context.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).getBundleContext() : context; HttpServiceRuntimeImpl httpServiceRuntime = new HttpServiceRuntimeImpl( trackingContext, context, servletContext, serviceProperties); + httpServiceRuntime.open(); proxyServlet.setHttpServiceRuntimeImpl(httpServiceRuntime); // imperative API support; // the http service must be registered first so we can get its service id - HttpServiceFactory httpServiceFactory = new HttpServiceFactory( - httpServiceRuntime); + HttpServiceFactory httpServiceFactory = new HttpServiceFactory(httpServiceRuntime); ServiceRegistration<?> hsfRegistration = context.registerService( HTTP_SERVICES_CLASSES, httpServiceFactory, serviceProperties); serviceProperties.put(HttpServiceRuntimeConstants.HTTP_SERVICE_ID, Collections.singletonList(hsfRegistration.getReference().getProperty(Constants.SERVICE_ID))); + ServiceRegistration<HttpServiceRuntime> hsrRegistration = context.registerService( HttpServiceRuntime.class, httpServiceRuntime, serviceProperties); + + httpServiceRuntime.setHsrRegistration(hsrRegistration); + return new HttpTuple( proxyServlet, httpServiceFactory, hsfRegistration, httpServiceRuntime, hsrRegistration); @@ -243,18 +247,6 @@ public class Activator } } - int majorVersion = servletContext.getMajorVersion(); - - if (majorVersion < 3) { - servletContext.log( - "The http container does not support servlet 3.0+. " + - "Therefore, the value of " + - HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT + - " cannot be calculated."); - - return new String[0]; - } - contextPath = servletContext.getContextPath(); ServletRegistration servletRegistration = null; 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 296235d45..8b023bd06 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 @@ -16,23 +16,22 @@ package org.eclipse.equinox.http.servlet.internal; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + import java.security.*; import java.util.Dictionary; 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 javax.servlet.*; import org.eclipse.equinox.http.servlet.ExtendedHttpService; +import org.eclipse.equinox.http.servlet.internal.context.HttpContextHolder; 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.*; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceRegistration; 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 { @@ -42,15 +41,11 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { final HttpServiceRuntimeImpl httpServiceRuntime; private volatile boolean shutdown = false; // We prevent use of this instance if HttpServiceFactory.ungetService has called unregisterAliases. - 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); } /** @@ -59,9 +54,10 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { public synchronized HttpContext createDefaultHttpContext() { checkShutdown(); - DefaultServletContextHelper defaultServletContextHelper = bundle.getBundleContext().getService(defaultHttpContextReference); - - contextMap.putIfAbsent(defaultServletContextHelper, defaultHttpContextReference); + DefaultServletContextHelper defaultServletContextHelper = bundle.getBundleContext().getService(httpServiceRuntime.defaultContextReg.getReference()); + HttpContextHolder httpContextHolder = new HttpContextHolder(defaultServletContextHelper, httpServiceRuntime.defaultContextReg); + httpContextHolder.incrementUseCount(); + httpServiceRuntime.legacyContextMap.putIfAbsent(defaultServletContextHelper, httpContextHolder); return defaultServletContextHelper; } @@ -78,12 +74,12 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { checkShutdown(); httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); - final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); + final HttpContextHolder httpContextHolder = httpServiceRuntime.legacyContextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override - public Void run() throws ServletException { - httpServiceRuntime.registerHttpServiceFilter(bundle, alias, filter, initparams, serviceReference); + public Void run() { + httpServiceRuntime.registerHttpServiceFilter(bundle, alias, filter, initparams, httpContextHolder); return null; } }); @@ -104,12 +100,12 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { checkShutdown(); httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); - final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); + final HttpContextHolder httpContextHolder = httpServiceRuntime.legacyContextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws NamespaceException { - httpServiceRuntime.registerHttpServiceResources(bundle, alias, name, serviceReference); + httpServiceRuntime.registerHttpServiceResources(bundle, alias, name, httpContextHolder); return null; } }); @@ -126,17 +122,17 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { */ public synchronized void registerServlet( final String alias, final Servlet servlet, - final Dictionary initparams, HttpContext httpContext) + final Dictionary<?, ?> initparams, HttpContext httpContext) throws ServletException, NamespaceException { checkShutdown(); httpContext = httpContext == null ? createDefaultHttpContext() : registerContext(httpContext); - final ServiceReference<DefaultServletContextHelper> serviceReference = contextMap.get(httpContext); + final HttpContextHolder httpContextHolder = httpServiceRuntime.legacyContextMap.get(httpContext); try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws NamespaceException, ServletException { - httpServiceRuntime.registerHttpServiceServlet(bundle, alias, servlet, initparams, serviceReference); + httpServiceRuntime.registerHttpServiceServlet(bundle, alias, servlet, initparams, httpContextHolder); return null; } }); @@ -182,20 +178,24 @@ public class HttpServiceImpl implements HttpService, ExtendedHttpService { } private HttpContext registerContext(HttpContext httpContext) { - ServiceReference<? extends HttpContext> serviceReference = contextMap.get(httpContext); + HttpContextHolder httpContextHolder = httpServiceRuntime.legacyContextMap.get(httpContext); - if (serviceReference == null) { + if (httpContextHolder == null) { + String legacyId = httpContext.getClass().getName().replaceAll("[^a-zA-Z_0-9\\-]", "_") + "-" + generateLegacyId(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 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(HTTP_WHITEBOARD_CONTEXT_NAME, legacyId); + props.put(HTTP_WHITEBOARD_CONTEXT_PATH, "/"); //$NON-NLS-1$ + props.put(HTTP_WHITEBOARD_TARGET, httpServiceRuntime.getTargetFilter()); + props.put(HTTP_SERVICE_CONTEXT_PROPERTY, legacyId); 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); + httpContextHolder = new HttpContextHolder(httpContext, registration); + httpContextHolder.incrementUseCount(); - contextMap.put(httpContext, registration.getReference()); + httpServiceRuntime.legacyContextMap.put(httpContext, httpContextHolder); } 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 c78adbfc9..7a56eadb6 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 @@ -15,18 +15,21 @@ package org.eclipse.equinox.http.servlet.internal; +import org.eclipse.equinox.http.servlet.internal.context.HttpContextHolder; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceRegistration; public class HttpServiceObjectRegistration { public final Object serviceKey; public final ServiceRegistration<?> registration; + public final HttpContextHolder httpContextHolder; public final Bundle bundle; public HttpServiceObjectRegistration( Object serviceKey, ServiceRegistration<?> registration, - Bundle bundle) { + HttpContextHolder httpContextHolder, Bundle bundle) { this.serviceKey = serviceKey; this.registration = registration; + this.httpContextHolder = httpContextHolder; 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 a69f1117a..cc3fcae95 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 @@ -14,34 +14,36 @@ package org.eclipse.equinox.http.servlet.internal; +import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + import java.io.IOException; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.*; import javax.servlet.Filter; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionListener; +import javax.servlet.http.*; import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer; -import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO; -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.context.*; 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.registration.PreprocessorRegistration; import org.eclipse.equinox.http.servlet.internal.servlet.HttpSessionTracker; import org.eclipse.equinox.http.servlet.internal.servlet.Match; 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; -import org.osgi.service.http.runtime.HttpServiceRuntimeConstants; import org.osgi.service.http.runtime.dto.*; -import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; +import org.osgi.service.http.whiteboard.Preprocessor; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; @@ -53,6 +55,7 @@ public class HttpServiceRuntimeImpl HttpServiceRuntime, ServiceTrackerCustomizer<ServletContextHelper, AtomicReference<ContextController>> { + @SuppressWarnings("unchecked") public HttpServiceRuntimeImpl( BundleContext trackingContext, BundleContext consumingContext, ServletContext parentServletContext, Dictionary<String, Object> attributes) { @@ -60,10 +63,11 @@ public class HttpServiceRuntimeImpl this.trackingContext = trackingContext; this.consumingContext = consumingContext; + this.errorPageServiceFilter = createErrorPageFilter(consumingContext); this.servletServiceFilter = createServletFilter(consumingContext); this.resourceServiceFilter = createResourceFilter(consumingContext); this.filterServiceFilter = createFilterFilter(consumingContext); - this.listenerServiceFilter = createListenerFilter(consumingContext, parentServletContext); + this.listenerServiceFilter = createListenerFilter(consumingContext); this.parentServletContext = parentServletContext; this.attributes = new UMDictionaryMap<String, Object>(attributes); @@ -75,22 +79,30 @@ public class HttpServiceRuntimeImpl new ServiceTracker<ServletContextHelper, AtomicReference<ContextController>>( trackingContext, ServletContextHelper.class, this); + preprocessorServiceTracker = + new ServiceTracker<Preprocessor, AtomicReference<PreprocessorRegistration>>( + trackingContext, Preprocessor.class, new PreprocessorCustomizer(this)); + contextPathCustomizerHolder = new ContextPathCustomizerHolder(consumingContext, contextServiceTracker); contextPathAdaptorTracker = new ServiceTracker<ContextPathCustomizer, ContextPathCustomizer>( consumingContext, ContextPathCustomizer.class, contextPathCustomizerHolder); - contextPathAdaptorTracker.open(); - - contextServiceTracker.open(); Hashtable<String, Object> defaultContextProps = new Hashtable<String, Object>(); - defaultContextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME); + defaultContextProps.put(HTTP_WHITEBOARD_CONTEXT_NAME, HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME); 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( + defaultContextProps.put(HTTP_WHITEBOARD_CONTEXT_PATH, Const.SLASH); + defaultContextProps.put(HTTP_WHITEBOARD_TARGET, this.targetFilter); + defaultContextProps.put(HTTP_SERVICE_CONTEXT_PROPERTY, HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME); + defaultContextReg = (ServiceRegistration<DefaultServletContextHelper>) consumingContext.registerService( new String [] {ServletContextHelper.class.getName(), DefaultServletContextHelper.class.getName()}, new DefaultServletContextHelperFactory(), defaultContextProps); } + public synchronized void open() { + contextPathAdaptorTracker.open(); + contextServiceTracker.open(); + preprocessorServiceTracker.open(); + } + @Override public synchronized AtomicReference<ContextController> addingService( ServiceReference<ServletContextHelper> serviceReference) { @@ -118,6 +130,9 @@ public class HttpServiceRuntimeImpl recordFailedServletContextDTO(serviceReference, 0, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); } + finally { + incrementServiceChangecount(); + } return result; } @@ -140,6 +155,10 @@ public class HttpServiceRuntimeImpl return contextPath; } + public BundleContext getConsumingContext() { + return consumingContext; + } + public String getDefaultContextSelectFilter(ServiceReference<?> httpWhiteBoardService) { ContextPathCustomizer pathAdaptor = contextPathCustomizerHolder.getHighestRanked(); if (pathAdaptor != null) { @@ -156,6 +175,18 @@ public class HttpServiceRuntimeImpl return thisReference.equals(contextReference); } + public boolean isFailedResourceDTO(ServiceReference<?> serviceReference) { + return failedResourceDTOs.containsKey(serviceReference); + } + + public boolean isFailedServletDTO(ServiceReference<?> serviceReference) { + return failedServletDTOs.containsKey(serviceReference); + } + + public boolean isFailedErrorPageDTO(ServiceReference<?> serviceReference) { + return failedErrorPageDTOs.containsKey(serviceReference); + } + @Override public synchronized RequestInfoDTO calculateRequestInfoDTO(String path) { RequestInfoDTO requestInfoDTO = new RequestInfoDTO(); @@ -174,30 +205,34 @@ public class HttpServiceRuntimeImpl public synchronized void destroy() { invalidatorReg.unregister(); - defaultContextReg.unregister(); + + try { + defaultContextReg.unregister(); + } + catch (IllegalStateException ise) { + // ignore + } contextServiceTracker.close(); contextPathAdaptorTracker.close(); + preprocessorServiceTracker.close(); controllerMap.clear(); + preprocessorMap.clear(); registeredObjects.clear(); + legacyContextMap.clear(); + failedErrorPageDTOs.clear(); failedFilterDTOs.clear(); failedListenerDTOs.clear(); + failedPreprocessorDTOs.clear(); failedResourceDTOs.clear(); failedServletContextDTOs.clear(); failedServletDTOs.clear(); httpSessionTracker.clear(); registeredObjects.clear(); - - httpSessionTracker = null; - attributes = null; - trackingContext = null; - consumingContext = null; - parentServletContext = null; - contextServiceTracker = null; - contextPathCustomizerHolder = null; + scheduledExecutor.shutdown(); } public DispatchTargets getDispatchTargets( @@ -220,7 +255,7 @@ public class HttpServiceRuntimeImpl requestInfoDTO); } - if (dispatchTargets == null && !Const.SLASH.equals(pathString)) { + if (dispatchTargets == null) { // regex match dispatchTargets = getDispatchTargets( requestURI, null, queryString, Match.REGEX, requestInfoDTO); @@ -257,10 +292,13 @@ public class HttpServiceRuntimeImpl return targetFilter; } + public ServletContext getParentServletContext() { + return parentServletContext; + } + public List<String> getHttpServiceEndpoints() { return StringPlus.from( - attributes.get( - HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT)); + attributes.get(HTTP_SERVICE_ENDPOINT)); } @Override @@ -270,9 +308,11 @@ public class HttpServiceRuntimeImpl runtimeDTO.failedErrorPageDTOs = getFailedErrorPageDTOs(); runtimeDTO.failedFilterDTOs = getFailedFilterDTOs(); runtimeDTO.failedListenerDTOs = getFailedListenerDTOs(); + runtimeDTO.failedPreprocessorDTOs = getFailedPreprocessorDTOs(); runtimeDTO.failedResourceDTOs = getFailedResourceDTOs(); runtimeDTO.failedServletContextDTOs = getFailedServletContextDTO(); runtimeDTO.failedServletDTOs = getFailedServletDTOs(); + runtimeDTO.preprocessorDTOs = getPreprocessorDTOs(); runtimeDTO.serviceDTO = getServiceDTO(); runtimeDTO.servletContextDTOs = getServletContextDTOs(); @@ -313,8 +353,7 @@ public class HttpServiceRuntimeImpl } public boolean matches(ServiceReference<?> serviceReference) { - String target = (String)serviceReference.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET); + String target = (String)serviceReference.getProperty(HTTP_WHITEBOARD_TARGET); if (target == null) { return true; @@ -360,19 +399,24 @@ public class HttpServiceRuntimeImpl ServiceReference<ServletContextHelper> serviceReference, AtomicReference<ContextController> contextControllerRef) { - 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(); + try { + 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(); } - contextController.destroy(); + failedServletContextDTOs.remove(serviceReference); + controllerMap.remove(serviceReference); + trackingContext.ungetService(serviceReference); + } + finally { + incrementServiceChangecount(); } - failedServletContextDTOs.remove(serviceReference); - controllerMap.remove(serviceReference); - trackingContext.ungetService(serviceReference); } Collection<ContextController> getContextControllers(String requestURI) { @@ -491,7 +535,7 @@ public class HttpServiceRuntimeImpl return copies.toArray(new FailedListenerDTO[0]); } - public FailedResourceDTO[] getFailedResourceDTOs() { + private FailedResourceDTO[] getFailedResourceDTOs() { Collection<FailedResourceDTO> frDTOs = failedResourceDTOs.values(); List<FailedResourceDTO> copies = new ArrayList<FailedResourceDTO>(); @@ -516,17 +560,29 @@ public class HttpServiceRuntimeImpl } private FailedServletDTO[] getFailedServletDTOs() { - Collection<ExtendedFailedServletDTO> fsDTOs = failedServletDTOs.values(); + Collection<FailedServletDTO> fsDTOs = failedServletDTOs.values(); List<FailedServletDTO> copies = new ArrayList<FailedServletDTO>(); - for (ExtendedFailedServletDTO failedServletDTO : fsDTOs) { + for (FailedServletDTO failedServletDTO : fsDTOs) { copies.add(DTOUtil.clone(failedServletDTO)); } return copies.toArray(new FailedServletDTO[0]); } + private FailedPreprocessorDTO[] getFailedPreprocessorDTOs() { + Collection<FailedPreprocessorDTO> fpDTOs = failedPreprocessorDTOs.values(); + + List<FailedPreprocessorDTO> copies = new ArrayList<FailedPreprocessorDTO>(); + + for (FailedPreprocessorDTO failedPreprocessorDTO : fpDTOs) { + copies.add(DTOUtil.clone(failedPreprocessorDTO)); + } + + return copies.toArray(new FailedPreprocessorDTO[0]); + } + public ServletContextDTO[] getServletContextDTOs() { List<ServletContextDTO> servletContextDTOs = new ArrayList<ServletContextDTO>(); @@ -537,8 +593,22 @@ public class HttpServiceRuntimeImpl return servletContextDTOs.toArray(new ServletContextDTO[0]); } + public PreprocessorDTO[] getPreprocessorDTOs() { + List<PreprocessorDTO> pDTOs = new ArrayList<PreprocessorDTO>(); + + for (PreprocessorRegistration registration : preprocessorMap.values()) { + pDTOs.add(registration.getD()); + } + + return pDTOs.toArray(new PreprocessorDTO[0]); + } + + public Map<ServiceReference<Preprocessor>, PreprocessorRegistration> getPreprocessorRegistrations() { + return preprocessorMap; + } + public void registerHttpServiceFilter( - Bundle bundle, String alias, Filter filter, Dictionary<String, String> initparams, ServiceReference<? extends ServletContextHelper> serviceReference) { + Bundle bundle, String alias, Filter filter, Dictionary<String, String> initparams, HttpContextHolder httpContextHolder) { if (alias == null) { throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ @@ -575,21 +645,23 @@ public class HttpServiceRuntimeImpl ServiceRegistration<Filter> registration = null; try { Dictionary<String, Object> props = new Hashtable<String, Object>(); - 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, getFilter(serviceReference)); + props.put(HTTP_WHITEBOARD_TARGET, targetFilter); + props.put(HTTP_WHITEBOARD_FILTER_PATTERN, alias); + props.put(HTTP_WHITEBOARD_FILTER_NAME, filterName); + props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference())); 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); + fillInitParams(props, initparams, HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX); LegacyFilterFactory filterFactory = new LegacyFilterFactory(filter); + registration = bundle.getBundleContext().registerService(Filter.class, filterFactory, props); // check that init got called and did not throw an exception filterFactory.checkForError(); + httpContextHolder.incrementUseCount(); - objectRegistration = new HttpServiceObjectRegistration(filter, registration, bundle); + objectRegistration = new HttpServiceObjectRegistration(filter, registration, httpContextHolder, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { objectRegistrations = new HashSet<HttpServiceObjectRegistration>(); @@ -600,6 +672,7 @@ public class HttpServiceRuntimeImpl } finally { if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) { // something bad happened above (likely going to throw a runtime exception) + decrementFactoryUseCount(httpContextHolder); if (registration != null) { registration.unregister(); } @@ -610,11 +683,11 @@ public class HttpServiceRuntimeImpl private void fillInitParams( Dictionary<String, Object> props, - Dictionary<String, String> initparams, String prefix) { + Dictionary<?, ?> initparams, String prefix) { if (initparams != null) { - for (Enumeration<String> eKeys = initparams.keys(); eKeys.hasMoreElements();) { - String key = eKeys.nextElement(); - String value = initparams.get(key); + for (Enumeration<?> eKeys = initparams.keys(); eKeys.hasMoreElements();) { + String key = String.valueOf(eKeys.nextElement()); + String value = String.valueOf(initparams.get(key)); if (value != null) { props.put(prefix + key, value); } @@ -649,7 +722,7 @@ public class HttpServiceRuntimeImpl } public void registerHttpServiceResources( - Bundle bundle, String alias, String name, ServiceReference<? extends ServletContextHelper> serviceReference) throws NamespaceException { + Bundle bundle, String alias, String name, HttpContextHolder httpContextHolder) throws NamespaceException { if (alias == null) { throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ } @@ -672,20 +745,22 @@ public class HttpServiceRuntimeImpl HttpServiceObjectRegistration objectRegistration = null; ServiceRegistration<?> registration = null; try { - String fullAlias = getFullAlias(alias, serviceReference); + String fullAlias = getFullAlias(alias, httpContextHolder); HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias); if (existing != null) { throw new PatternInUseException(alias); } Dictionary<String, Object> props = new Hashtable<String, Object>(); - 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, getFilter(serviceReference)); + props.put(HTTP_WHITEBOARD_TARGET, targetFilter); + props.put(HTTP_WHITEBOARD_RESOURCE_PATTERN, pattern); + props.put(HTTP_WHITEBOARD_RESOURCE_PREFIX, name); + props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference())); props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader()); registration = bundle.getBundleContext().registerService(String.class, "resource", props); //$NON-NLS-1$ - objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, bundle); + httpContextHolder.incrementUseCount(); + + objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, httpContextHolder, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { @@ -705,6 +780,7 @@ 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(httpContextHolder); if (registration != null) { registration.unregister(); } @@ -714,12 +790,12 @@ public class HttpServiceRuntimeImpl } 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$ + String ctxName = (String)serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME); + return String.format("(&(%s=%s)(%s=%s))", HTTP_SERVICE_CONTEXT_PROPERTY, ctxName, HTTP_WHITEBOARD_CONTEXT_NAME, ctxName); //$NON-NLS-1$ } public void registerHttpServiceServlet( - Bundle bundle, String alias, Servlet servlet, Dictionary<String, String> initparams, ServiceReference<? extends ServletContextHelper> serviceReference) throws NamespaceException, ServletException{ + Bundle bundle, String alias, Servlet servlet, Dictionary<?, ?> initparams, HttpContextHolder httpContextHolder) throws NamespaceException, ServletException{ if (alias == null) { throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$ } @@ -748,31 +824,32 @@ public class HttpServiceRuntimeImpl HttpServiceObjectRegistration objectRegistration = null; ServiceRegistration<Servlet> registration = null; try { - String fullAlias = getFullAlias(alias, serviceReference); + String fullAlias = getFullAlias(alias, httpContextHolder); HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias); if (existing != null) { throw new PatternInUseException(alias); } String servletName = servlet.getClass().getName(); if ((initparams != null) && (initparams.get(Const.SERVLET_NAME) != null)) { - servletName = initparams.get(Const.SERVLET_NAME); + servletName = String.valueOf(initparams.get(Const.SERVLET_NAME)); } Dictionary<String, Object> props = new Hashtable<String, Object>(); - 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, getFilter(serviceReference)); + props.put(HTTP_WHITEBOARD_TARGET, targetFilter); + props.put(HTTP_WHITEBOARD_SERVLET_PATTERN, pattern); + props.put(HTTP_WHITEBOARD_SERVLET_NAME, servletName); + props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference())); 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); + fillInitParams(props, initparams, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); registration = bundle.getBundleContext().registerService(Servlet.class, legacyServlet, props); // check that init got called and did not throw an exception legacyServlet.checkForError(); + httpContextHolder.incrementUseCount(); - objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, bundle); + objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, httpContextHolder, bundle); Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle); if (objectRegistrations == null) { @@ -793,6 +870,7 @@ 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(httpContextHolder); if (registration != null) { registration.unregister(); } @@ -801,9 +879,9 @@ public class HttpServiceRuntimeImpl } } - private String getFullAlias(String alias, ServiceReference<? extends ServletContextHelper> serviceReference) { + private String getFullAlias(String alias, HttpContextHolder httpContextHolder) { @SuppressWarnings("unchecked") - AtomicReference<ContextController> controllerRef = contextServiceTracker.getService((ServiceReference<ServletContextHelper>)serviceReference); + AtomicReference<ContextController> controllerRef = contextServiceTracker.getService((ServiceReference<ServletContextHelper>)httpContextHolder.getServiceReference()); if (controllerRef != null) { ContextController controller = controllerRef.get(); if (controller != null) { @@ -835,6 +913,7 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } + decrementFactoryUseCount(objectRegistration.httpContextHolder); legacyMappings.remove(aliasCustomization); } @@ -856,6 +935,7 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } + decrementFactoryUseCount(objectRegistration.httpContextHolder); legacyMappings.remove(filter); } } @@ -871,19 +951,43 @@ public class HttpServiceRuntimeImpl } catch (IllegalStateException e) { // ignore; already unregistered } + decrementFactoryUseCount(objectRegistration.httpContextHolder); legacyMappings.remove(objectRegistration.serviceKey); } } } } + private void decrementFactoryUseCount(HttpContextHolder holder) { + synchronized (legacyContextMap) { + if (holder.decrementUseCount() == 0) { + legacyContextMap.remove(holder.getHttpContext()); + } + } + } + + private static org.osgi.framework.Filter createErrorPageFilter(BundleContext context) { + StringBuilder sb = new StringBuilder(); + + sb.append("("); //$NON-NLS-1$ + sb.append(HTTP_WHITEBOARD_SERVLET_ERROR_PAGE); + sb.append("=*)"); //$NON-NLS-1$ + + try { + return context.createFilter(sb.toString()); + } + catch (InvalidSyntaxException ise) { + throw new IllegalArgumentException(ise); + } + } + private static org.osgi.framework.Filter createResourceFilter(BundleContext context) { StringBuilder sb = new StringBuilder(); sb.append("(&("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX); + sb.append(HTTP_WHITEBOARD_RESOURCE_PREFIX); sb.append("=*)("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN); + sb.append(HTTP_WHITEBOARD_RESOURCE_PATTERN); sb.append("=*))"); //$NON-NLS-1$ try { @@ -900,11 +1004,9 @@ public class HttpServiceRuntimeImpl sb.append("(&(objectClass="); //$NON-NLS-1$ sb.append(Servlet.class.getName()); sb.append(")(|("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE); - sb.append("=*)("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); + sb.append(HTTP_WHITEBOARD_SERVLET_NAME); sb.append("=*)("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN); + sb.append(HTTP_WHITEBOARD_SERVLET_PATTERN); sb.append("=*)))"); //$NON-NLS-1$ try { @@ -921,11 +1023,11 @@ public class HttpServiceRuntimeImpl sb.append("(&(objectClass="); //$NON-NLS-1$ sb.append(Filter.class.getName()); sb.append(")(|("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN); + sb.append(HTTP_WHITEBOARD_FILTER_PATTERN); sb.append("=*)("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_REGEX); + sb.append(HTTP_WHITEBOARD_FILTER_REGEX); sb.append("=*)("); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_SERVLET); + sb.append(HTTP_WHITEBOARD_FILTER_SERVLET); sb.append("=*)))"); //$NON-NLS-1$ try { @@ -936,11 +1038,11 @@ public class HttpServiceRuntimeImpl } } - private static org.osgi.framework.Filter createListenerFilter(BundleContext context, ServletContext servletContext) { + private static org.osgi.framework.Filter createListenerFilter(BundleContext context) { StringBuilder sb = new StringBuilder(); sb.append("(&"); //$NON-NLS-1$ - sb.append("(").append(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER).append("=*)"); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append("(").append(HTTP_WHITEBOARD_LISTENER).append("=*)"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("(|"); //$NON-NLS-1$ sb.append("(objectClass=").append(ServletContextListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("(objectClass=").append(ServletContextAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -948,11 +1050,7 @@ public class HttpServiceRuntimeImpl sb.append("(objectClass=").append(ServletRequestAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("(objectClass=").append(HttpSessionListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("(objectClass=").append(HttpSessionAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ - - if ((servletContext.getMajorVersion() >= 3) && (servletContext.getMinorVersion() > 0)) { - sb.append("(objectClass=").append(javax.servlet.http.HttpSessionIdListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - + sb.append("(objectClass=").append(HttpSessionIdListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(")"); //$NON-NLS-1$ sb.append(")"); //$NON-NLS-1$ @@ -968,6 +1066,10 @@ public class HttpServiceRuntimeImpl return listenerServiceFilter; } + public org.osgi.framework.Filter getErrorPageFilter() { + return errorPageServiceFilter; + } + public org.osgi.framework.Filter getFilterFilter() { return filterServiceFilter; } @@ -1029,14 +1131,14 @@ public class HttpServiceRuntimeImpl ExtendedFailedServletContextDTO failedServletContextDTO = new ExtendedFailedServletContextDTO(); failedServletContextDTO.attributes = Collections.emptyMap(); - failedServletContextDTO.contextPath = String.valueOf(serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH)); + failedServletContextDTO.contextPath = String.valueOf(serviceReference.getProperty(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); + serviceReference, HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX); failedServletContextDTO.listenerDTOs = new ListenerDTO[0]; - failedServletContextDTO.name = String.valueOf(serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME)); + failedServletContextDTO.name = String.valueOf(serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME)); failedServletContextDTO.resourceDTOs = new ResourceDTO[0]; failedServletContextDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); failedServletContextDTO.servletDTOs = new ServletDTO[0]; @@ -1047,7 +1149,7 @@ public class HttpServiceRuntimeImpl public void recordFailedServletDTO( ServiceReference<?> serviceReference, - ExtendedFailedServletDTO failedServletDTO) { + FailedServletDTO failedServletDTO) { if (failedServletDTOs.containsKey(serviceReference)) { return; @@ -1056,6 +1158,17 @@ public class HttpServiceRuntimeImpl failedServletDTOs.put(serviceReference, failedServletDTO); } + public void recordFailedPreprocessorDTO( + ServiceReference<Preprocessor> serviceReference, + FailedPreprocessorDTO failedPreprocessorDTO) { + + if (failedPreprocessorDTOs.containsKey(serviceReference)) { + return; + } + + failedPreprocessorDTOs.put(serviceReference, failedPreprocessorDTO); + } + public void removeFailedErrorPageDTO( ServiceReference<Servlet> serviceReference) { @@ -1086,6 +1199,12 @@ public class HttpServiceRuntimeImpl failedServletDTOs.remove(serviceReference); } + public void removeFailedPreprocessorDTO( + ServiceReference<Preprocessor> serviceReference) { + + failedPreprocessorDTOs.remove(serviceReference); + } + public synchronized void fireSessionIdChanged(String oldSessionId) { for (ContextController contextController : controllerMap.values()) { contextController.fireSessionIdChanged(oldSessionId); @@ -1096,20 +1215,44 @@ public class HttpServiceRuntimeImpl httpSessionTracker.invalidate(sessionId, false); } - private Map<String, Object> attributes; - private final String targetFilter; - private final ServiceRegistration<?> defaultContextReg; - private ServletContext parentServletContext; + public void setHsrRegistration(ServiceRegistration<HttpServiceRuntime> hsrRegistration) { + this.hsrRegistration.set(hsrRegistration); + } - private BundleContext trackingContext; - private BundleContext consumingContext; + ServiceRegistration<HttpServiceRuntime> getHsrRegistration() { + return hsrRegistration.get(); + } + + long getServiceChangecount() { + return serviceChangecount.get(); + } + public void incrementServiceChangecount() { + serviceChangecount.incrementAndGet(); + if (hsrRegistration.get() != null && !scheduledExecutor.isShutdown() && semaphore.tryAcquire()) { + scheduledExecutor.schedule(new ChangeCountTimer(), 100, TimeUnit.MILLISECONDS); + } + } + + Semaphore getSemaphore() { + return semaphore; + } + + private final Map<String, Object> attributes; + private final String targetFilter; + final ServiceRegistration<DefaultServletContextHelper> defaultContextReg; + private final ServletContext parentServletContext; + private final BundleContext trackingContext; + private final BundleContext consumingContext; + private final org.osgi.framework.Filter errorPageServiceFilter; private final org.osgi.framework.Filter servletServiceFilter; private final org.osgi.framework.Filter resourceServiceFilter; private final org.osgi.framework.Filter filterServiceFilter; private final org.osgi.framework.Filter listenerServiceFilter; // BEGIN of old HttpService support + final ConcurrentMap<HttpContext, HttpContextHolder> legacyContextMap = + new ConcurrentHashMap<HttpContext, HttpContextHolder>(); private final Map<Object, HttpServiceObjectRegistration> legacyMappings = Collections.synchronizedMap(new HashMap<Object, HttpServiceObjectRegistration>()); private final Map<Bundle, Set<HttpServiceObjectRegistration>> bundleRegistrations = @@ -1119,27 +1262,52 @@ public class HttpServiceRuntimeImpl private final ConcurrentMap<ServiceReference<ServletContextHelper>, ContextController> controllerMap = new ConcurrentSkipListMap<ServiceReference<ServletContextHelper>, ContextController>(Collections.reverseOrder()); + private final ConcurrentMap<ServiceReference<Preprocessor>, PreprocessorRegistration> preprocessorMap = + new ConcurrentSkipListMap<ServiceReference<Preprocessor>, PreprocessorRegistration>(Collections.reverseOrder()); - private final ConcurrentMap<ServiceReference<?>, FailedErrorPageDTO> failedErrorPageDTOs = + final ConcurrentMap<ServiceReference<?>, FailedErrorPageDTO> failedErrorPageDTOs = new ConcurrentHashMap<ServiceReference<?>, FailedErrorPageDTO>(); - private final ConcurrentMap<ServiceReference<Filter>, FailedFilterDTO> failedFilterDTOs = + final ConcurrentMap<ServiceReference<Filter>, FailedFilterDTO> failedFilterDTOs = new ConcurrentHashMap<ServiceReference<Filter>, FailedFilterDTO>(); - private final ConcurrentMap<ServiceReference<EventListener>, FailedListenerDTO> failedListenerDTOs = + final ConcurrentMap<ServiceReference<EventListener>, FailedListenerDTO> failedListenerDTOs = new ConcurrentHashMap<ServiceReference<EventListener>, FailedListenerDTO>(); - private final ConcurrentMap<ServiceReference<?>, FailedResourceDTO> failedResourceDTOs = + final ConcurrentMap<ServiceReference<?>, FailedResourceDTO> failedResourceDTOs = new ConcurrentHashMap<ServiceReference<?>, FailedResourceDTO>(); - private final ConcurrentMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO> failedServletContextDTOs = + final ConcurrentMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO> failedServletContextDTOs = new ConcurrentHashMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO>(); - private final ConcurrentMap<ServiceReference<?>, ExtendedFailedServletDTO> failedServletDTOs = - new ConcurrentHashMap<ServiceReference<?>, ExtendedFailedServletDTO>(); + final ConcurrentMap<ServiceReference<?>, FailedServletDTO> failedServletDTOs = + new ConcurrentHashMap<ServiceReference<?>, FailedServletDTO>(); + final ConcurrentMap<ServiceReference<?>, FailedPreprocessorDTO> failedPreprocessorDTOs = + new ConcurrentHashMap<ServiceReference<?>, FailedPreprocessorDTO>(); private final Set<Object> registeredObjects = Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>()); - private ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker; - private ServiceTracker<ContextPathCustomizer, ContextPathCustomizer> contextPathAdaptorTracker; - private ContextPathCustomizerHolder contextPathCustomizerHolder; - private HttpSessionTracker httpSessionTracker; + private final ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker; + private final ServiceTracker<Preprocessor, AtomicReference<PreprocessorRegistration>> preprocessorServiceTracker; + private final ServiceTracker<ContextPathCustomizer, ContextPathCustomizer> contextPathAdaptorTracker; + private final ContextPathCustomizerHolder contextPathCustomizerHolder; + private final HttpSessionTracker httpSessionTracker; private final ServiceRegistration<HttpSessionInvalidator> invalidatorReg; + private final AtomicReference<ServiceRegistration<HttpServiceRuntime>> hsrRegistration = new AtomicReference<>(); + + private final AtomicLong serviceChangecount = new AtomicLong(); + private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); + private final Semaphore semaphore = new Semaphore(1); + + class ChangeCountTimer implements Callable<Void> { + @Override + public Void call() { + try { + Dictionary<String,Object> properties = getHsrRegistration().getReference().getProperties(); + properties.put(Constants.SERVICE_CHANGECOUNT, getServiceChangecount()); + getHsrRegistration().setProperties(properties); + return null; + } + finally { + getSemaphore().release(); + } + } + } static class LegacyServiceObject { final AtomicReference<Exception> error = new AtomicReference<Exception>(new ServletException("The init() method was never called.")); //$NON-NLS-1$ @@ -1325,16 +1493,4 @@ 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/PreprocessorCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/PreprocessorCustomizer.java new file mode 100644 index 000000000..20730e6a7 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/PreprocessorCustomizer.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) Feb. 2, 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 static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX; + +import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import org.eclipse.equinox.http.servlet.internal.context.ServiceHolder; +import org.eclipse.equinox.http.servlet.internal.error.HttpWhiteboardFailureException; +import org.eclipse.equinox.http.servlet.internal.registration.PreprocessorRegistration; +import org.eclipse.equinox.http.servlet.internal.servlet.FilterConfigImpl; +import org.eclipse.equinox.http.servlet.internal.util.ServiceProperties; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.runtime.dto.*; +import org.osgi.service.http.whiteboard.Preprocessor; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * @author Raymond Augé + */ +public class PreprocessorCustomizer + implements ServiceTrackerCustomizer<Preprocessor, AtomicReference<PreprocessorRegistration>> { + + public PreprocessorCustomizer(HttpServiceRuntimeImpl httpServiceRuntime) { + this.httpServiceRuntime = httpServiceRuntime; + } + + @Override + public AtomicReference<PreprocessorRegistration> addingService( + ServiceReference<Preprocessor> serviceReference) { + + AtomicReference<PreprocessorRegistration> result = new AtomicReference<PreprocessorRegistration>(); + if (!httpServiceRuntime.matches(serviceReference)) { + return result; + } + + try { + removeFailed(serviceReference); + + result.set(addPreprocessorRegistration(serviceReference)); + } + catch (HttpWhiteboardFailureException hwfe) { + httpServiceRuntime.log(hwfe.getMessage(), hwfe); + + recordFailed(serviceReference, hwfe.getFailureReason()); + } + catch (Exception e) { + httpServiceRuntime.log(e.getMessage(), e); + + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); + } + + return result; + } + + @Override + public void modifiedService( + ServiceReference<Preprocessor> serviceReference, AtomicReference<PreprocessorRegistration> reference) { + + removedService(serviceReference, reference); + AtomicReference<PreprocessorRegistration> added = addingService(serviceReference); + reference.set(added.get()); + } + + @Override + public void removedService( + ServiceReference<Preprocessor> serviceReference, AtomicReference<PreprocessorRegistration> reference) { + try { + PreprocessorRegistration registration = reference.get(); + if (registration != null) { + registration.destroy(); + } + + removeFailed(serviceReference); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); + } + } + + void removeFailed(ServiceReference<Preprocessor> serviceReference) { + httpServiceRuntime.removeFailedPreprocessorDTO(serviceReference); + } + + private void recordFailed( + ServiceReference<Preprocessor> serviceReference, int failureReason) { + + FailedPreprocessorDTO failedPreprocessorDTO = new FailedPreprocessorDTO(); + + failedPreprocessorDTO.failureReason = failureReason; + failedPreprocessorDTO.initParams = ServiceProperties.parseInitParams( + serviceReference, HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX); + failedPreprocessorDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); + + httpServiceRuntime.recordFailedPreprocessorDTO(serviceReference, failedPreprocessorDTO); + } + + private PreprocessorRegistration addPreprocessorRegistration( + ServiceReference<Preprocessor> preprocessorRef) throws ServletException { + + ServiceHolder<Preprocessor> preprocessorHolder = new ServiceHolder<Preprocessor>(httpServiceRuntime.getConsumingContext().getServiceObjects(preprocessorRef)); + Preprocessor preprocessor = preprocessorHolder.get(); + PreprocessorRegistration registration = null; + boolean addedRegisteredObject = false; + try { + if (preprocessor == null) { + throw new IllegalArgumentException("Preprocessor cannot be null"); //$NON-NLS-1$ + } + addedRegisteredObject = httpServiceRuntime.getRegisteredObjects().add(preprocessor); + if (!addedRegisteredObject) { + throw new HttpWhiteboardFailureException("Multiple registration of instance detected. Prototype scope is recommended: " + preprocessorRef, DTOConstants.FAILURE_REASON_SERVICE_IN_USE); //$NON-NLS-1$ + } + registration = doAddPreprocessorRegistration(preprocessorHolder, preprocessorRef); + } finally { + if (registration == null) { + preprocessorHolder.release(); + if (addedRegisteredObject) { + httpServiceRuntime.getRegisteredObjects().remove(preprocessor); + } + } + } + return registration; + } + + private PreprocessorRegistration doAddPreprocessorRegistration( + ServiceHolder<Preprocessor> preprocessorHolder, + ServiceReference<Preprocessor> preprocessorRef) throws ServletException { + + PreprocessorDTO preprocessorDTO = new PreprocessorDTO(); + + preprocessorDTO.initParams = ServiceProperties.parseInitParams( + preprocessorRef, HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX); + preprocessorDTO.serviceId = preprocessorHolder.getServiceId(); + + PreprocessorRegistration newRegistration = new PreprocessorRegistration( + preprocessorHolder, preprocessorDTO, httpServiceRuntime); + FilterConfig filterConfig = new FilterConfigImpl( + preprocessorHolder.get().getClass().getCanonicalName(), + preprocessorDTO.initParams, + httpServiceRuntime.getParentServletContext()); + + newRegistration.init(filterConfig); + + httpServiceRuntime.getPreprocessorRegistrations().put(preprocessorHolder.getServiceReference(), newRegistration); + + return newRegistration; + } + + private final HttpServiceRuntimeImpl httpServiceRuntime; + +} 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 16f115b5f..2a2f40463 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 @@ -14,6 +14,8 @@ package org.eclipse.equinox.http.servlet.internal.context; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + import java.net.URI; import java.net.URISyntaxException; import java.security.AccessController; @@ -25,8 +27,6 @@ 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; @@ -40,7 +40,6 @@ import org.eclipse.equinox.http.servlet.internal.util.*; import org.osgi.framework.*; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.dto.*; -import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.util.tracker.ServiceTracker; /** @@ -48,84 +47,6 @@ import org.osgi.util.tracker.ServiceTracker; */ public class ContextController { - public static final class ServiceHolder<S> implements Comparable<ServiceHolder<?>> { - final ServiceObjects<S> serviceObjects; - final S service; - 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.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, 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; - } - - public Bundle getBundle() { - return bundle; - } - - public ClassLoader getLegacyTCCL() { - return legacyTCCL; - } - - public void release() { - if (serviceObjects != null && service != null) { - try { - serviceObjects.ungetService(service); - } 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 - // the bundle forgot to unregister on stop - } - } - } - - public ServiceReference<S> getServiceReference() { - return serviceObjects == null ? null : serviceObjects.getServiceReference(); - } - @Override - public int compareTo(ServiceHolder<?> o) { - final int thisRanking = serviceRanking; - final int otherRanking = o.serviceRanking; - if (thisRanking != otherRanking) { - if (thisRanking < otherRanking) { - return 1; - } - return -1; - } - final long thisId = this.serviceId; - final long otherId = o.serviceId; - if (thisId == otherId) { - return 0; - } - if (thisId < otherId) { - return -1; - } - return 1; - } - } - public ContextController( BundleContext trackingContextParam, BundleContext consumingContext, ServiceReference<ServletContextHelper> serviceReference, @@ -142,7 +63,7 @@ public class ContextController { this.servletContextHelperRefFilter = createFilter(contextServiceId); this.initParams = ServiceProperties.parseInitParams( - serviceReference, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX, parentServletContext); + serviceReference, HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX, parentServletContext); listenerServiceTracker = new ServiceTracker<EventListener, AtomicReference<ListenerRegistration>>( trackingContext, httpServiceRuntime.getListenerFilter(), @@ -158,6 +79,13 @@ public class ContextController { filterServiceTracker.open(); + errorPageServiceTracker = new ServiceTracker<Servlet, AtomicReference<ErrorPageRegistration>>( + trackingContext, httpServiceRuntime.getErrorPageFilter(), + new ContextErrorPageTrackerCustomizer( + trackingContext, httpServiceRuntime, this)); + + errorPageServiceTracker.open(); + servletServiceTracker = new ServiceTracker<Servlet, AtomicReference<ServletRegistration>>( trackingContext, httpServiceRuntime.getServletFilter(), new ContextServletTrackerCustomizer( @@ -173,9 +101,77 @@ public class ContextController { resourceServiceTracker.open(); } - public FilterRegistration addFilterRegistration(ServiceReference<Filter> filterRef) throws ServletException { - checkShutdown(); + public ErrorPageRegistration addErrorPageRegistration(ServiceReference<Servlet> servletRef) { + ServiceHolder<Servlet> servletHolder = new ServiceHolder<Servlet>(consumingContext.getServiceObjects(servletRef)); + Servlet servlet = servletHolder.get(); + ErrorPageRegistration registration = null; + //boolean addedRegisteredObject = false; + try { + if (servlet == null) { + throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$ + } + //addedRegisteredObject = httpServiceRuntime.getRegisteredObjects().add(servlet); + //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 = doAddErrorPageRegistration(servletHolder, servletRef); + } finally { + if (registration == null) { + // Always attempt to release here; even though destroy() may have been called + // on the registration while failing to add. There are cases where no + // ServletRegistration may have even been created at all to call destory() on. + // Also, addedRegisteredObject may be false which means we never call doAddServletRegistration + servletHolder.release(); + //if (addedRegisteredObject) { + // httpServiceRuntime.getRegisteredObjects().remove(servlet); + //} + } + } + return registration; + } + + private ErrorPageRegistration doAddErrorPageRegistration(ServiceHolder<Servlet> servletHolder, ServiceReference<Servlet> servletRef) { + ExtendedErrorPageDTO errorPageDTO = DTOUtil.assembleErrorPageDTO(servletRef, getServiceId(), true); + errorPageDTO.servletInfo = servletHolder.get().getServletInfo(); + errorPageDTO.serviceId = servletHolder.getServiceId(); + + if (((errorPageDTO.errorCodes == null) || (errorPageDTO.errorCodes.length == 0)) && + ((errorPageDTO.exceptions == null) || (errorPageDTO.exceptions.length == 0))) { + + throw new HttpWhiteboardFailureException("'errorPage' expects String, String[] or Collection<String>.", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + if (errorPageDTO.name == null) { + errorPageDTO.name = servletHolder.get().getClass().getName(); + } + + ServletContextHelper curServletContextHelper = getServletContextHelper( + servletHolder.getBundle()); + + ServletContext servletContext = createServletContext( + servletHolder.getBundle(), curServletContextHelper); + ErrorPageRegistration errorPageRegistration = new ErrorPageRegistration( + servletHolder, errorPageDTO, curServletContextHelper, this); + ServletConfig servletConfig = new ServletConfigImpl( + errorPageDTO.name, errorPageDTO.initParams, servletContext); + + try { + errorPageRegistration.init(servletConfig); + } + catch (Throwable t) { + errorPageRegistration.destroy(); + + return Throw.unchecked(t); + } + + recordErrorPageShadowing(errorPageRegistration); + + endpointRegistrations.add(errorPageRegistration); + return errorPageRegistration; + } + + public FilterRegistration addFilterRegistration(ServiceReference<Filter> filterRef) throws ServletException { ServiceHolder<Filter> filterHolder = new ServiceHolder<Filter>(consumingContext.getServiceObjects(filterRef)); Filter filter = filterHolder.get(); FilterRegistration registration = null; @@ -201,13 +197,12 @@ public class ContextController { } private FilterRegistration doAddFilterRegistration(ServiceHolder<Filter> filterHolder, ServiceReference<Filter> filterRef) throws ServletException { - boolean asyncSupported = ServiceProperties.parseBoolean( - filterRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED); + filterRef, HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED); List<String> dispatcherList = StringPlus.from( filterRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_DISPATCHER)); + HTTP_WHITEBOARD_FILTER_DISPATCHER)); String[] dispatchers = dispatcherList.toArray(new String[0]); Integer filterPriority = (Integer)filterRef.getProperty( Constants.SERVICE_RANKING); @@ -215,24 +210,22 @@ public class ContextController { filterPriority = Integer.valueOf(0); } Map<String, String> filterInitParams = ServiceProperties.parseInitParams( - filterRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX); + filterRef, HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX); List<String> patternList = StringPlus.from( filterRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN)); + HTTP_WHITEBOARD_FILTER_PATTERN)); String[] patterns = patternList.toArray(new String[0]); List<String> regexList = StringPlus.from( filterRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_REGEX)); + HTTP_WHITEBOARD_FILTER_REGEX)); String[] regexs = regexList.toArray(new String[0]); List<String> servletList = StringPlus.from( filterRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_SERVLET)); + HTTP_WHITEBOARD_FILTER_SERVLET)); String[] servletNames = servletList.toArray(new String[0]); String name = ServiceProperties.parseName(filterRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME), filterHolder.get()); - - Filter filter = filterHolder.get(); + HTTP_WHITEBOARD_FILTER_NAME), filterHolder.get()); if (((patterns == null) || (patterns.length == 0)) && ((regexs == null) || (regexs.length == 0)) && @@ -254,20 +247,12 @@ public class ContextController { } } - if (filter == null) { - throw new HttpWhiteboardFailureException("Filter cannot be null", DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE); //$NON-NLS-1$ - } + Filter filter = filterHolder.get(); if (name == null) { name = filter.getClass().getName(); } - for (FilterRegistration filterRegistration : filterRegistrations) { - if (filterRegistration.getT().equals(filter)) { - throw new RegisteredFilterException(filter); - } - } - dispatchers = checkDispatcher(dispatchers); FilterDTO filterDTO = new FilterDTO(); @@ -278,7 +263,7 @@ public class ContextController { filterDTO.name = name; filterDTO.patterns = sort(patterns); filterDTO.regexs = regexs; - filterDTO.serviceId = filterHolder.serviceId; + filterDTO.serviceId = filterHolder.getServiceId(); filterDTO.servletContextId = contextServiceId; filterDTO.servletNames = sort(servletNames); @@ -299,9 +284,6 @@ public class ContextController { } public ListenerRegistration addListenerRegistration(ServiceReference<EventListener> listenerRef) throws ServletException { - - checkShutdown(); - ServiceHolder<EventListener> listenerHolder = new ServiceHolder<EventListener>(consumingContext.getServiceObjects(listenerRef)); EventListener listener = listenerHolder.get(); ListenerRegistration registration = null; @@ -339,7 +321,7 @@ public class ContextController { ListenerDTO listenerDTO = new ListenerDTO(); - listenerDTO.serviceId = listenerHolder.serviceId; + listenerDTO.serviceId = listenerHolder.getServiceId(); listenerDTO.servletContextId = contextServiceId; listenerDTO.types = asStringArray(classes); @@ -367,13 +349,10 @@ public class ContextController { } public ResourceRegistration addResourceRegistration(ServiceReference<?> resourceRef) { - - checkShutdown(); - 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(); - Object patternObj = resourceRef.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN); + Object patternObj = resourceRef.getProperty(HTTP_WHITEBOARD_RESOURCE_PATTERN); if (!(patternObj instanceof String) && !(patternObj instanceof String[]) && !(patternObj instanceof Collection)) { @@ -388,7 +367,7 @@ public class ContextController { serviceId = -serviceId; } Object prefixObj = resourceRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX); + HTTP_WHITEBOARD_RESOURCE_PREFIX); checkPrefix(prefixObj); String prefix = (String)prefixObj; @@ -441,8 +420,6 @@ public class ContextController { } public ServletRegistration addServletRegistration(ServiceReference<Servlet> servletRef) { - checkShutdown(); - ServiceHolder<Servlet> servletHolder = new ServiceHolder<Servlet>(consumingContext.getServiceObjects(servletRef)); Servlet servlet = servletHolder.get(); ServletRegistration registration = null; @@ -472,118 +449,25 @@ public class ContextController { } private ServletRegistration doAddServletRegistration(ServiceHolder<Servlet> servletHolder, ServiceReference<Servlet> servletRef) { - boolean asyncSupported = ServiceProperties.parseBoolean( - servletRef, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); - List<String> errorPageList = StringPlus.from( - servletRef.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE)); - 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[0]); - String servletNameFromProperties = (String)servletRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); - String generatedServletName = ServiceProperties.parseName( - servletRef.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME), servletHolder.get()); - boolean multipartEnabled = ServiceProperties.parseBoolean( - servletRef, Const.EQUINOX_HTTP_MULTIPART_ENABLED); - Integer multipartFileSizeThreshold = (Integer)servletRef.getProperty( - Const.EQUINOX_HTTP_MULTIPART_FILESIZETHRESHOLD); - String multipartLocation = (String)servletRef.getProperty( - Const.EQUINOX_HTTP_MULTIPART_LOCATION); - Long multipartMaxFileSize = (Long)servletRef.getProperty( - Const.EQUINOX_HTTP_MULTIPART_MAXFILESIZE); - Long multipartMaxRequestSize = (Long)servletRef.getProperty( - Const.EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE); + ServletDTO servletDTO = DTOUtil.assembleServletDTO(servletRef, getServiceId(), true); + servletDTO.servletInfo = servletHolder.get().getServletInfo(); + servletDTO.serviceId = servletHolder.getServiceId(); - if (((patterns == null) || (patterns.length == 0)) && - ((errorPages == null) || errorPages.length == 0) && - (servletNameFromProperties == null)) { + if (((servletDTO.patterns == null) || (servletDTO.patterns.length == 0)) && + (servletDTO.name == null)) { StringBuilder sb = new StringBuilder(); sb.append("One of the service properties "); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE); + sb.append(HTTP_WHITEBOARD_SERVLET_NAME); sb.append(", "); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME); - sb.append(", "); //$NON-NLS-1$ - sb.append(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN); + sb.append(HTTP_WHITEBOARD_SERVLET_PATTERN); sb.append(" must contain a value."); //$NON-NLS-1$ - throw new IllegalArgumentException(sb.toString()); + throw new HttpWhiteboardFailureException(sb.toString(), DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } - if (patterns != null) { - for (String pattern : patterns) { - checkPattern(pattern); - } - } - - ExtendedServletDTO servletDTO = new ExtendedServletDTO(); - - servletDTO.asyncSupported = asyncSupported; - servletDTO.initParams = servletInitParams; - servletDTO.multipartEnabled = multipartEnabled; - servletDTO.multipartFileSizeThreshold = (multipartFileSizeThreshold != null ? multipartFileSizeThreshold : 0); - servletDTO.multipartLocation = (multipartLocation != null ? multipartLocation : Const.BLANK); - servletDTO.multipartMaxFileSize = (multipartMaxFileSize != null ? multipartMaxFileSize : -1L); - servletDTO.multipartMaxRequestSize = (multipartMaxRequestSize != null ? multipartMaxRequestSize : -1L); - servletDTO.name = generatedServletName; - servletDTO.patterns = sort(patterns); - servletDTO.serviceId = servletHolder.serviceId; - servletDTO.servletContextId = contextServiceId; - servletDTO.servletInfo = servletHolder.get().getServletInfo(); - - ExtendedErrorPageDTO errorPageDTO = null; - - if ((errorPages != null) && (errorPages.length > 0)) { - errorPageDTO = new ExtendedErrorPageDTO(); - - errorPageDTO.asyncSupported = asyncSupported; - List<String> exceptions = new ArrayList<String>(); - // Not sure if it is important to maintain order of insertion or natural ordering here. - // Using insertion ordering with linked hash set. - Set<Long> errorCodeSet = new LinkedHashSet<Long>(); - - 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 if (errorPage.length() == 3) { - errorPageDTO.erroCodeType = ErrorCodeType.SPECIFIC; - long code = Long.parseLong(errorPage); - errorCodeSet.add(code); - } else { - exceptions.add(errorPage); - } - } - catch (NumberFormatException nfe) { - exceptions.add(errorPage); - } - } - - long[] errorCodes = new long[errorCodeSet.size()]; - int i = 0; - for(Long code : errorCodeSet) { - errorCodes[i] = code; - i++; - } - errorPageDTO.errorCodes = errorCodes; - errorPageDTO.exceptions = exceptions.toArray(new String[0]); - errorPageDTO.initParams = servletInitParams; - errorPageDTO.name = generatedServletName; - errorPageDTO.serviceId = servletHolder.serviceId; - errorPageDTO.servletContextId = contextServiceId; - errorPageDTO.servletInfo = servletHolder.get().getServletInfo(); + if (servletDTO.name == null) { + servletDTO.name = servletHolder.get().getClass().getName(); } ServletContextHelper curServletContextHelper = getServletContextHelper( @@ -592,10 +476,10 @@ public class ContextController { ServletContext servletContext = createServletContext( servletHolder.getBundle(), curServletContextHelper); ServletRegistration servletRegistration = new ServletRegistration( - servletHolder, servletDTO, errorPageDTO, curServletContextHelper, this, + servletHolder, servletDTO, curServletContextHelper, this, servletContext); ServletConfig servletConfig = new ServletConfigImpl( - generatedServletName, servletInitParams, servletContext); + servletDTO.name, servletDTO.initParams, servletContext); try { servletRegistration.init(servletConfig); @@ -607,7 +491,6 @@ public class ContextController { } recordEndpointShadowing(servletRegistration); - recordErrorPageShadowing(servletRegistration, errorPageDTO); endpointRegistrations.add(servletRegistration); @@ -635,7 +518,7 @@ public class ContextController { } for (EndpointRegistration<?> shadowedReg : shadowedRegs) { if (shadowedReg instanceof ServletRegistration) { - recordFailedServletDTO(shadowedReg.getServiceReference(), (ExtendedServletDTO)shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); + recordFailedServletDTO(shadowedReg.getServiceReference(), (ServletDTO)shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); } else { recordFailedResourceDTO(shadowedReg.getServiceReference(), (ResourceDTO)shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); @@ -643,72 +526,70 @@ public class ContextController { } } - private void recordErrorPageShadowing(ServletRegistration servletRegistration, ExtendedErrorPageDTO newErrorPageDTO) { - if (newErrorPageDTO == null) { - return; - } - Set<ServletRegistration> shadowedEPs = new HashSet<ServletRegistration>(); + private void recordErrorPageShadowing(ErrorPageRegistration newRegistration) { + Set<ErrorPageRegistration> shadowedEPs = new HashSet<ErrorPageRegistration>(); for (EndpointRegistration<?> existingRegistration : endpointRegistrations) { - if (!(existingRegistration instanceof ServletRegistration)) { + if (!(existingRegistration instanceof ErrorPageRegistration)) { continue; } - ServletRegistration existingSRegistration = (ServletRegistration)existingRegistration; - ExtendedErrorPageDTO existingErrorPageDTO = existingSRegistration.getErrorPageDTO(); + ErrorPageRegistration existingSRegistration = (ErrorPageRegistration)existingRegistration; + ExtendedErrorPageDTO existingErrorPageDTO = existingSRegistration.getD(); if ((existingErrorPageDTO == null) || - (((existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_4XX) || (existingErrorPageDTO.erroCodeType == ErrorCodeType.RANGE_5XX)) && (newErrorPageDTO.erroCodeType == ErrorCodeType.SPECIFIC))) { + (((existingErrorPageDTO.errorCodeType == ErrorCodeType.RANGE_4XX) || (existingErrorPageDTO.errorCodeType == ErrorCodeType.RANGE_5XX)) && (newRegistration.getD().errorCodeType == 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) { + if (((existingErrorPageDTO.errorCodeType == ErrorCodeType.RANGE_4XX) && (newRegistration.getD().errorCodeType == ErrorCodeType.RANGE_4XX)) || + ((existingErrorPageDTO.errorCodeType == ErrorCodeType.RANGE_5XX) && (newRegistration.getD().errorCodeType == ErrorCodeType.RANGE_5XX))) { + if (newRegistration.compareTo(existingSRegistration) < 0) { shadowedEPs.add(existingSRegistration); } // the new reg is shadowed by existing reg else { - shadowedEPs.add(servletRegistration); + shadowedEPs.add(newRegistration); } continue; } - for (long newErrorCode : newErrorPageDTO.errorCodes) { + for (long newErrorCode : newRegistration.getD().errorCodes) { for (long existingCode : existingErrorPageDTO.errorCodes) { if (newErrorCode == existingCode) { // the new reg is shadowing an existing reg - if (servletRegistration.compareTo(existingSRegistration) < 0) { + if (newRegistration.compareTo(existingSRegistration) < 0) { shadowedEPs.add(existingSRegistration); } // the new reg is shadowed by existing reg else { - shadowedEPs.add(servletRegistration); + shadowedEPs.add(newRegistration); } // 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 newException : newRegistration.getD().exceptions) { for (String existingException : existingErrorPageDTO.exceptions) { if (newException.equals(existingException)) { // the new reg is shadowing an existing reg - if (servletRegistration.compareTo(existingSRegistration) < 0) { + if (newRegistration.compareTo(existingSRegistration) < 0) { shadowedEPs.add(existingSRegistration); } // the new reg is shadowed by existing reg else { - shadowedEPs.add(servletRegistration); + shadowedEPs.add(newRegistration); } // 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); + for (ErrorPageRegistration shadowedReg : shadowedEPs) { + recordFailedErrorPageDTO(shadowedReg.getServiceReference(), shadowedReg.getD(), DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE); } } - public void destroy() { + public synchronized void destroy() { flushActiveSessions(); resourceServiceTracker.close(); servletServiceTracker.close(); + errorPageServiceTracker.close(); filterServiceTracker.close(); listenerServiceTracker.close(); @@ -721,6 +602,10 @@ public class ContextController { shutdown = true; } + public boolean isLegacyContext() { + return serviceReference.getProperty(HTTP_SERVICE_CONTEXT_PROPERTY) != null; + } + public String getContextName() { checkShutdown(); @@ -988,7 +873,7 @@ public class ContextController { public boolean matches(ServiceReference<?> whiteBoardService) { String contextSelector = (String) whiteBoardService.getProperty( - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT); + HTTP_WHITEBOARD_CONTEXT_SELECT); // make sure the context helper is either one of the built-in ones registered by this http whiteboard implementation; // or is visible to the whiteboard registering bundle. if (!visibleContextHelper(whiteBoardService)) { @@ -998,14 +883,14 @@ public class ContextController { contextSelector = httpServiceRuntime.getDefaultContextSelectFilter(whiteBoardService); if (contextSelector == null) { contextSelector = "(" + //$NON-NLS-1$ - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=" //$NON-NLS-1$ - + HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME + ")"; //$NON-NLS-1$ + HTTP_WHITEBOARD_CONTEXT_NAME + "=" //$NON-NLS-1$ + + HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME + ")"; //$NON-NLS-1$ } } if (!contextSelector.startsWith(Const.OPEN_PAREN)) { contextSelector = Const.OPEN_PAREN + - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + + HTTP_WHITEBOARD_CONTEXT_NAME + Const.EQUAL + contextSelector + Const.CLOSE_PAREN; } @@ -1178,7 +1063,7 @@ public class ContextController { } } - private void checkShutdown() { + public synchronized void checkShutdown() { if (shutdown) { throw new IllegalStateException( "Context is already shutdown"); //$NON-NLS-1$ @@ -1214,21 +1099,18 @@ public class ContextController { for (EndpointRegistration<?> endpointRegistration : endpointRegistrations) { if (endpointRegistration instanceof ResourceRegistration) { - if (!httpServiceRuntime.failedResourceDTO(endpointRegistration.getServiceReference())) { + if (!httpServiceRuntime.isFailedResourceDTO(endpointRegistration.getServiceReference())) { resourceDTOs.add(DTOUtil.clone((ResourceDTO)endpointRegistration.getD())); } } - else { - ServletRegistration servletRegistration = (ServletRegistration)endpointRegistration; - if (!httpServiceRuntime.failedServletDTO(servletRegistration.getServiceReference())) { - servletDTOs.add(DTOUtil.clone(servletRegistration.getD())); + else if (endpointRegistration instanceof ErrorPageRegistration) { + if (!httpServiceRuntime.isFailedErrorPageDTO(endpointRegistration.getServiceReference())) { + errorPageDTOs.add(DTOUtil.clone((ExtendedErrorPageDTO)endpointRegistration.getD())); } - - ErrorPageDTO errorPageDTO = servletRegistration.getErrorPageDTO(); - if ((errorPageDTO != null) && - !httpServiceRuntime.failedErrorPageDTO(servletRegistration.getServiceReference())) { - - errorPageDTOs.add(DTOUtil.clone(errorPageDTO)); + } + else { + if (!httpServiceRuntime.isFailedServletDTO(endpointRegistration.getServiceReference())) { + servletDTOs.add(DTOUtil.clone((ServletDTO)endpointRegistration.getD())); } } } @@ -1472,76 +1354,37 @@ public class ContextController { getHttpServiceRuntime().recordFailedResourceDTO(resourceReference, failedResourceDTO); } - public void recordFailedServletDTO( - ServiceReference<?> servletReference, ExtendedServletDTO servletDTO, int failureReason) { + public void recordFailedServletDTO(ServiceReference<?> servletReference, ServletDTO servletDTO, int failureReason) { + FailedServletDTO failedServletDTO = new FailedServletDTO(); - 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; - } + 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; getHttpServiceRuntime().recordFailedServletDTO(servletReference, failedServletDTO); } private String validateName() { - Object contextNameObj = serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME); + Object contextNameObj = serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME); if (contextNameObj == null) { throw new IllegalContextNameException( - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + " is null. Ignoring!", //$NON-NLS-1$ + 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$ + HTTP_WHITEBOARD_CONTEXT_NAME + " is not String. Ignoring!", //$NON-NLS-1$ DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } @@ -1569,16 +1412,16 @@ public class ContextController { } private String validatePath() { - Object contextPathObj = serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH); + Object contextPathObj = serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_PATH); if (contextPathObj == null) { throw new IllegalContextPathException( - HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + " is null. Ignoring!", //$NON-NLS-1$ + 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$ + HTTP_WHITEBOARD_CONTEXT_PATH + " is not String. Ignoring!", //$NON-NLS-1$ DTOConstants.FAILURE_REASON_VALIDATION_FAILED); } @@ -1629,8 +1472,9 @@ public class ContextController { private boolean shutdown; private String string; + private final ServiceTracker<Servlet, AtomicReference<ErrorPageRegistration>> errorPageServiceTracker; private final ServiceTracker<Filter, AtomicReference<FilterRegistration>> filterServiceTracker; private final ServiceTracker<EventListener, AtomicReference<ListenerRegistration>> listenerServiceTracker; - private final ServiceTracker<Servlet, AtomicReference<ServletRegistration>> servletServiceTracker; private final ServiceTracker<Object, AtomicReference<ResourceRegistration>> resourceServiceTracker; + private final ServiceTracker<Servlet, AtomicReference<ServletRegistration>> servletServiceTracker; }
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java index 2e45f122e..4b5b64316 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java @@ -85,32 +85,30 @@ public class DispatchTargets { setDispatcherType(requestedDispatcherType); - RequestAttributeSetter setter = new RequestAttributeSetter(originalRequest); - - if (dispatcherType == DispatcherType.INCLUDE) { - setter.setAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextController.getFullContextPath()); - setter.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, getPathInfo()); - setter.setAttribute(RequestDispatcher.INCLUDE_QUERY_STRING, getQueryString()); - setter.setAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, getRequestURI()); - setter.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, getServletPath()); - } - else if (dispatcherType == DispatcherType.FORWARD) { - response.resetBuffer(); - - setter.setAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH, originalRequest.getContextPath()); - setter.setAttribute(RequestDispatcher.FORWARD_PATH_INFO, originalRequest.getPathInfo()); - setter.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, originalRequest.getQueryString()); - setter.setAttribute(RequestDispatcher.FORWARD_REQUEST_URI, originalRequest.getRequestURI()); - setter.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, originalRequest.getServletPath()); - } - HttpServletRequest request = originalRequest; HttpServletRequestWrapperImpl requestWrapper = HttpServletRequestWrapperImpl.findHttpRuntimeRequest(originalRequest); HttpServletResponseWrapper responseWrapper = HttpServletResponseWrapperImpl.findHttpRuntimeResponse(response); boolean includeWrapperAdded = false; - try { + try (RequestAttributeSetter setter = new RequestAttributeSetter(originalRequest)) { + if (dispatcherType == DispatcherType.INCLUDE) { + setter.setAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextController.getFullContextPath()); + setter.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, getPathInfo()); + setter.setAttribute(RequestDispatcher.INCLUDE_QUERY_STRING, getQueryString()); + setter.setAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, getRequestURI()); + setter.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, getServletPath()); + } + else if (dispatcherType == DispatcherType.FORWARD) { + response.resetBuffer(); + + setter.setAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH, originalRequest.getContextPath()); + setter.setAttribute(RequestDispatcher.FORWARD_PATH_INFO, originalRequest.getPathInfo()); + setter.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, originalRequest.getQueryString()); + setter.setAttribute(RequestDispatcher.FORWARD_REQUEST_URI, originalRequest.getRequestURI()); + setter.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, originalRequest.getServletPath()); + } + if (requestWrapper == null) { requestWrapper = new HttpServletRequestWrapperImpl(originalRequest); request = requestWrapper; @@ -140,8 +138,6 @@ public class DispatchTargets { } requestWrapper.pop(); - - setter.close(); } } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHolder.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHolder.java new file mode 100644 index 000000000..d73724c8d --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/HttpContextHolder.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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 + * 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.util.concurrent.atomic.AtomicLong; +import org.eclipse.equinox.http.servlet.internal.DefaultServletContextHelper; +import org.osgi.framework.*; +import org.osgi.service.http.HttpContext; +import org.osgi.service.http.context.ServletContextHelper; + +public class HttpContextHolder { + + final HttpContext httpContext; + final ServiceRegistration<? extends ServletContextHelper> registration; + final String filter; + final AtomicLong useCount = new AtomicLong(0); + + public HttpContextHolder(HttpContext httpContext, ServiceRegistration<DefaultServletContextHelper> registration) { + this.httpContext = httpContext; + this.registration = registration; + StringBuilder filterBuilder = new StringBuilder(); + filterBuilder.append('('); + filterBuilder.append(Constants.SERVICE_ID); + filterBuilder.append('='); + filterBuilder.append(registration.getReference().getProperty(Constants.SERVICE_ID)); + filterBuilder.append(')'); + filter = filterBuilder.toString(); + } + + public ServiceReference<? extends ServletContextHelper> getServiceReference() { + try { + return registration.getReference(); + } catch (IllegalStateException e) { + // do nothing + } + return null; + } + + public String getFilter() { + return filter; + } + + public long incrementUseCount() { + return useCount.incrementAndGet(); + } + + public long decrementUseCount() { + long result = useCount.decrementAndGet(); + if (result == 0) { + try { + registration.unregister(); + } catch (IllegalStateException e) { + // ignore; already unregistered + } + } + return result; + } + + public Object getHttpContext() { + return httpContext; + } +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ProxyContext.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ProxyContext.java index 6741914fd..60ffe5458 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ProxyContext.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ProxyContext.java @@ -83,7 +83,7 @@ public class ProxyContext { ContextAttributes contextAttributes = attributesMap.get(controller); if (contextAttributes == null) { - throw new IllegalStateException("too many calls"); + throw new IllegalStateException("too many calls"); //$NON-NLS-1$ } if (contextAttributes.removeReference() == 0) { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ServiceHolder.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ServiceHolder.java new file mode 100644 index 000000000..e82c1569a --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ServiceHolder.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) Feb. 2, 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 org.eclipse.equinox.http.servlet.internal.util.Const; +import org.osgi.framework.*; + +public final class ServiceHolder<S> implements Comparable<ServiceHolder<?>> { + + final ServiceObjects<S> serviceObjects; + final S service; + final Bundle bundle; + final long serviceId; + final int serviceRanking; + final ClassLoader legacyTCCL; + private volatile boolean released = false; + + public ServiceHolder(ServiceObjects<S> serviceObjects) { + this.serviceObjects = serviceObjects; + this.bundle = serviceObjects.getServiceReference().getBundle(); + this.service = serviceObjects.getService(); + 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; + Object rankProp = serviceObjects.getServiceReference().getProperty(Constants.SERVICE_RANKING); + this.serviceRanking = !Integer.class.isInstance(rankProp) ? 0 : ((Integer)rankProp).intValue(); + } + + 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; + } + + public Bundle getBundle() { + return bundle; + } + + public ClassLoader getLegacyTCCL() { + return legacyTCCL; + } + + public long getServiceId() { + return serviceId; + } + + public void release() { + if (!released && (serviceObjects != null) && (service != null)) { + try { + serviceObjects.ungetService(service); + } 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 + // the bundle forgot to unregister on stop + } + finally { + released = true; + } + } + } + + public ServiceReference<S> getServiceReference() { + return serviceObjects == null ? null : serviceObjects.getServiceReference(); + } + + @Override + public int compareTo(ServiceHolder<?> o) { + final int thisRanking = serviceRanking; + final int otherRanking = o.serviceRanking; + if (thisRanking != otherRanking) { + if (thisRanking < otherRanking) { + return 1; + } + return -1; + } + final long thisId = this.getServiceId(); + final long otherId = o.getServiceId(); + if (thisId == otherId) { + return 0; + } + if (thisId < otherId) { + return -1; + } + return 1; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextErrorPageTrackerCustomizer.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextErrorPageTrackerCustomizer.java new file mode 100644 index 000000000..b87ef5f9e --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/customizer/ContextErrorPageTrackerCustomizer.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) Feb. 1, 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.customizer; + +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + +import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.Servlet; +import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; +import org.eclipse.equinox.http.servlet.internal.context.ContextController; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; +import org.eclipse.equinox.http.servlet.internal.error.HttpWhiteboardFailureException; +import org.eclipse.equinox.http.servlet.internal.registration.ErrorPageRegistration; +import org.eclipse.equinox.http.servlet.internal.util.Const; +import org.eclipse.equinox.http.servlet.internal.util.DTOUtil; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.runtime.dto.DTOConstants; + +/** + * @author Raymond Augé + */ +public class ContextErrorPageTrackerCustomizer + extends RegistrationServiceTrackerCustomizer<Servlet, ErrorPageRegistration>{ + + public ContextErrorPageTrackerCustomizer( + BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, + ContextController contextController) { + + super(bundleContext, httpServiceRuntime, contextController); + } + + @Override + public AtomicReference<ErrorPageRegistration> + addingService(ServiceReference<Servlet> serviceReference) { + + AtomicReference<ErrorPageRegistration> result = new AtomicReference<ErrorPageRegistration>(); + if (!httpServiceRuntime.matches(serviceReference)) { + return result; + } + + try { + contextController.checkShutdown(); + + 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; + } + else if (contextController.isLegacyContext() && + (serviceReference.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP) == null) && // IS a whiteboard service + (serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT) != null) && + (((String)serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT))).contains(HTTP_SERVICE_CONTEXT_PROPERTY.concat(Const.EQUAL)) && + (serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_PATTERN) != null)) { + + // don't allow whiteboard Servlets that specifically attempt to bind to a legacy context + throw new HttpWhiteboardFailureException( + "Whiteboard ErrorPages with pattern cannot bind to legacy contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } + + httpServiceRuntime.removeFailedErrorPageDTO(serviceReference); + + result.set(contextController.addErrorPageRegistration(serviceReference)); + } + catch (HttpWhiteboardFailureException hwfe) { + httpServiceRuntime.log(hwfe.getMessage(), hwfe); + + recordFailed(serviceReference, hwfe.getFailureReason()); + } + catch (Throwable t) { + httpServiceRuntime.log(t.getMessage(), t); + + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); + } + + return result; + } + + @Override + void removeFailed(ServiceReference<Servlet> serviceReference) { + contextController.getHttpServiceRuntime().removeFailedErrorPageDTO(serviceReference); + } + + void recordFailed(ServiceReference<?> servletReference, int failureReason) { + ExtendedErrorPageDTO errorPageDTO = DTOUtil.assembleErrorPageDTO(servletReference, contextController.getServiceId(), false); + + contextController.recordFailedErrorPageDTO(servletReference, errorPageDTO, failureReason); + } + +} 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 ee9efa443..3ab68807b 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 @@ -30,15 +30,13 @@ import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; * @author Raymond Augé */ public class ContextFilterTrackerCustomizer - extends RegistrationServiceTrackerCustomizer<Filter, AtomicReference<FilterRegistration>> { + extends RegistrationServiceTrackerCustomizer<Filter, FilterRegistration> { public ContextFilterTrackerCustomizer( BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, ContextController contextController) { - super(bundleContext, httpServiceRuntime); - - this.contextController = contextController; + super(bundleContext, httpServiceRuntime, contextController); } @Override @@ -51,6 +49,8 @@ public class ContextFilterTrackerCustomizer } try { + contextController.checkShutdown(); + if (!contextController.matches(serviceReference)) { // Only the default context will perform the "does anyone match" checks. if (httpServiceRuntime.isDefaultContext(contextController) && @@ -70,41 +70,26 @@ public class ContextFilterTrackerCustomizer catch (HttpWhiteboardFailureException hwfe) { httpServiceRuntime.log(hwfe.getMessage(), hwfe); - recordFailedFilterDTO(serviceReference, hwfe.getFailureReason()); + recordFailed(serviceReference, hwfe.getFailureReason()); } catch (Exception e) { httpServiceRuntime.log(e.getMessage(), e); - recordFailedFilterDTO(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); } return result; } @Override - public void modifiedService( - ServiceReference<Filter> serviceReference, - AtomicReference<FilterRegistration> filterReference) { - - removedService(serviceReference, filterReference); - AtomicReference<FilterRegistration> added = addingService(serviceReference); - filterReference.set(added.get()); - } - - @Override - public void removedService( - ServiceReference<Filter> serviceReference, - AtomicReference<FilterRegistration> filterReference) { - FilterRegistration registration = filterReference.get(); - if (registration != null) { - // Destroy now ungets the object we are using - registration.destroy(); - } - + void removeFailed(ServiceReference<Filter> serviceReference) { contextController.getHttpServiceRuntime().removeFailedFilterDTO(serviceReference); } - private void recordFailedFilterDTO( + private void recordFailed( ServiceReference<Filter> serviceReference, int failureReason) { FailedFilterDTO failedFilterDTO = new FailedFilterDTO(); @@ -129,6 +114,4 @@ public class ContextFilterTrackerCustomizer contextController.getHttpServiceRuntime().recordFailedFilterDTO(serviceReference, failedFilterDTO); } - private ContextController contextController; - } 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 bb6ad17ce..8edc635be 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 @@ -30,15 +30,13 @@ import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; * @author Raymond Augé */ public class ContextListenerTrackerCustomizer - extends RegistrationServiceTrackerCustomizer<EventListener, AtomicReference<ListenerRegistration>> { + extends RegistrationServiceTrackerCustomizer<EventListener, ListenerRegistration> { public ContextListenerTrackerCustomizer( BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, ContextController contextController) { - super(bundleContext, httpServiceRuntime); - - this.contextController = contextController; + super(bundleContext, httpServiceRuntime, contextController); } @Override @@ -51,6 +49,8 @@ public class ContextListenerTrackerCustomizer } try { + contextController.checkShutdown(); + if (!contextController.matches(serviceReference)) { // Only the default context will perform the "does anyone match" checks. if (httpServiceRuntime.isDefaultContext(contextController) && @@ -82,41 +82,26 @@ public class ContextListenerTrackerCustomizer catch (HttpWhiteboardFailureException hwfe) { httpServiceRuntime.log(hwfe.getMessage(), hwfe); - recordFailedListenerDTO(serviceReference, hwfe.getFailureReason()); + recordFailed(serviceReference, hwfe.getFailureReason()); } catch (Exception e) { httpServiceRuntime.log(e.getMessage(), e); - recordFailedListenerDTO(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); } return result; } @Override - public void modifiedService( - ServiceReference<EventListener> serviceReference, - AtomicReference<ListenerRegistration> listenerRegistration) { - - removedService(serviceReference, listenerRegistration); - addingService(serviceReference); - } - - @Override - public void removedService( - ServiceReference<EventListener> serviceReference, - AtomicReference<ListenerRegistration> listenerReference) { - - ListenerRegistration listenerRegistration = listenerReference.get(); - if (listenerRegistration != null) { - // Destroy now ungets the object we are using - listenerRegistration.destroy(); - } - + void removeFailed(ServiceReference<EventListener> serviceReference) { contextController.getHttpServiceRuntime().removeFailedListenerDTO(serviceReference); } - private void recordFailedListenerDTO( + private void recordFailed( ServiceReference<EventListener> serviceReference, int failureReason) { FailedListenerDTO failedListenerDTO = new FailedListenerDTO(); @@ -130,6 +115,4 @@ public class ContextListenerTrackerCustomizer contextController.getHttpServiceRuntime().recordFailedListenerDTO(serviceReference, failedListenerDTO); } - private ContextController contextController; - } 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 61477208e..b146baa25 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 @@ -14,11 +14,15 @@ package org.eclipse.equinox.http.servlet.internal.customizer; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT; + import java.util.concurrent.atomic.AtomicReference; 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.ResourceRegistration; +import org.eclipse.equinox.http.servlet.internal.util.Const; import org.eclipse.equinox.http.servlet.internal.util.StringPlus; import org.osgi.framework.*; import org.osgi.service.http.runtime.dto.DTOConstants; @@ -29,26 +33,27 @@ import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; * @author Raymond Augé */ public class ContextResourceTrackerCustomizer - extends RegistrationServiceTrackerCustomizer<Object, AtomicReference<ResourceRegistration>> { + extends RegistrationServiceTrackerCustomizer<Object, ResourceRegistration> { public ContextResourceTrackerCustomizer( BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, ContextController contextController) { - super(bundleContext, httpServiceRuntime); - - this.contextController = contextController; + super(bundleContext, httpServiceRuntime, contextController); } @Override public AtomicReference<ResourceRegistration> addingService( ServiceReference<Object> serviceReference) { + AtomicReference<ResourceRegistration> result = new AtomicReference<ResourceRegistration>(); if (!httpServiceRuntime.matches(serviceReference)) { return result; } try { + contextController.checkShutdown(); + if (!contextController.matches(serviceReference)) { // Only the default context will perform the "does anyone match" checks. if (httpServiceRuntime.isDefaultContext(contextController) && @@ -60,6 +65,15 @@ public class ContextResourceTrackerCustomizer return result; } + else if (contextController.isLegacyContext() && + (serviceReference.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP) == null) && // IS a whiteboard service + (serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT) != null) && + (((String)serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT))).contains(HTTP_SERVICE_CONTEXT_PROPERTY.concat(Const.EQUAL))) { + + // don't allow whiteboard Servlets that specifically attempt to bind to a legacy context + throw new HttpWhiteboardFailureException( + "Whiteboard resources cannot bind to legacy contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } httpServiceRuntime.removeFailedResourceDTO(serviceReference); @@ -68,41 +82,26 @@ public class ContextResourceTrackerCustomizer catch (HttpWhiteboardFailureException hwfe) { httpServiceRuntime.log(hwfe.getMessage(), hwfe); - recordFailedResourceDTO(serviceReference, hwfe.getFailureReason()); + recordFailed(serviceReference, hwfe.getFailureReason()); } catch (Throwable t) { httpServiceRuntime.log(t.getMessage(), t); - recordFailedResourceDTO(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); } return result; } @Override - public void modifiedService( - ServiceReference<Object> serviceReference, - AtomicReference<ResourceRegistration> resourceReference) { - - removedService(serviceReference, resourceReference); - AtomicReference<ResourceRegistration> added = addingService(serviceReference); - resourceReference.set(added.get()); - } - - @Override - public void removedService( - ServiceReference<Object> serviceReference, - AtomicReference<ResourceRegistration> resourceReference) { - ResourceRegistration registration = resourceReference.get(); - if (registration != null) { - // destroy will unget the service object we were using - registration.destroy(); - } - + void removeFailed(ServiceReference<Object> serviceReference) { contextController.getHttpServiceRuntime().removeFailedResourceDTO(serviceReference); } - private void recordFailedResourceDTO( + private void recordFailed( ServiceReference<Object> serviceReference, int failureReason) { FailedResourceDTO failedResourceDTO = new FailedResourceDTO(); @@ -117,6 +116,4 @@ public class ContextResourceTrackerCustomizer contextController.getHttpServiceRuntime().recordFailedResourceDTO(serviceReference, failedResourceDTO); } - private ContextController contextController; - } 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 cf5044415..e6e862e16 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 @@ -14,29 +14,32 @@ package org.eclipse.equinox.http.servlet.internal.customizer; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + import java.util.concurrent.atomic.AtomicReference; import javax.servlet.Servlet; 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.Const; +import org.eclipse.equinox.http.servlet.internal.util.DTOUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.http.runtime.dto.DTOConstants; +import org.osgi.service.http.runtime.dto.ServletDTO; /** * @author Raymond Augé */ public class ContextServletTrackerCustomizer - extends RegistrationServiceTrackerCustomizer<Servlet, AtomicReference<ServletRegistration>> { + extends RegistrationServiceTrackerCustomizer<Servlet, ServletRegistration> { public ContextServletTrackerCustomizer( BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, ContextController contextController) { - super(bundleContext, httpServiceRuntime); - - this.contextController = contextController; + super(bundleContext, httpServiceRuntime, contextController); } @Override @@ -49,6 +52,8 @@ public class ContextServletTrackerCustomizer } try { + contextController.checkShutdown(); + if (!contextController.matches(serviceReference)) { // Only the default context will perform the "does anyone match" checks. if (httpServiceRuntime.isDefaultContext(contextController) && @@ -60,6 +65,16 @@ public class ContextServletTrackerCustomizer return result; } + else if (contextController.isLegacyContext() && + (serviceReference.getProperty(Const.EQUINOX_LEGACY_TCCL_PROP) == null) && // IS a whiteboard service + (serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT) != null) && + (((String)serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_SELECT))).contains(HTTP_SERVICE_CONTEXT_PROPERTY.concat(Const.EQUAL)) && + (serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_PATTERN) != null)) { + + // don't allow whiteboard Servlets that specifically attempt to bind to a legacy context + throw new HttpWhiteboardFailureException( + "Whiteboard Servlets with pattern cannot bind to legacy contexts. " + serviceReference, DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING); //$NON-NLS-1$ + } httpServiceRuntime.removeFailedServletDTO(serviceReference); @@ -68,41 +83,29 @@ public class ContextServletTrackerCustomizer catch (HttpWhiteboardFailureException hwfe) { httpServiceRuntime.log(hwfe.getMessage(), hwfe); - contextController.recordFailedServletDTO(serviceReference, null, hwfe.getFailureReason()); + recordFailed(serviceReference, hwfe.getFailureReason()); } catch (Throwable t) { httpServiceRuntime.log(t.getMessage(), t); - contextController.recordFailedServletDTO(serviceReference, null, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + recordFailed(serviceReference, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); } return result; } @Override - public void modifiedService( - ServiceReference<Servlet> serviceReference, - AtomicReference<ServletRegistration> servletReference) { - - removedService(serviceReference, servletReference); - AtomicReference<ServletRegistration> added = addingService(serviceReference); - servletReference.set(added.get()); + void removeFailed(ServiceReference<Servlet> serviceReference) { + contextController.getHttpServiceRuntime().removeFailedServletDTO(serviceReference); } - @Override - public void removedService( - ServiceReference<Servlet> serviceReference, - AtomicReference<ServletRegistration> servletReference) { - ServletRegistration registration = servletReference.get(); - if (registration != null) { - // destroy will unget the service object we were using - registration.destroy(); - } + void recordFailed(ServiceReference<?> servletReference, int failureReason) { + ServletDTO servletDTO = DTOUtil.assembleServletDTO(servletReference, contextController.getServiceId(), false); - contextController.getHttpServiceRuntime().removeFailedServletDTO(serviceReference); - contextController.getHttpServiceRuntime().removeFailedErrorPageDTO(serviceReference); + contextController.recordFailedServletDTO(servletReference, servletDTO, failureReason); } - 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 93954b73c..b974df1f6 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 @@ -14,24 +14,62 @@ package org.eclipse.equinox.http.servlet.internal.customizer; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; +import org.eclipse.equinox.http.servlet.internal.context.ContextController; +import org.eclipse.equinox.http.servlet.internal.registration.Registration; +import org.osgi.dto.DTO; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * @author Raymond Augé */ -public abstract class RegistrationServiceTrackerCustomizer<S, T> - implements ServiceTrackerCustomizer<S, T> { +public abstract class RegistrationServiceTrackerCustomizer<S, T extends Registration<?, ? extends DTO>> + implements ServiceTrackerCustomizer<S, AtomicReference<T>> { public RegistrationServiceTrackerCustomizer( - BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime) { + BundleContext bundleContext, HttpServiceRuntimeImpl httpServiceRuntime, ContextController contextController) { this.bundleContext = bundleContext; this.httpServiceRuntime = httpServiceRuntime; + this.contextController = contextController; } - protected BundleContext bundleContext; - protected HttpServiceRuntimeImpl httpServiceRuntime; + @Override + public void modifiedService( + ServiceReference<S> serviceReference, + AtomicReference<T> filterReference) { + + removedService(serviceReference, filterReference); + AtomicReference<T> added = addingService(serviceReference); + filterReference.set(added.get()); + } + + + @Override + public void removedService( + ServiceReference<S> serviceReference, + AtomicReference<T> filterReference) { + + try { + T registration = filterReference.get(); + if (registration != null) { + registration.destroy(); + } + + removeFailed(serviceReference); + } + finally { + httpServiceRuntime.incrementServiceChangecount(); + } + } + + abstract void removeFailed(ServiceReference<S> serviceReference); + + protected final BundleContext bundleContext; + protected final ContextController contextController; + protected final HttpServiceRuntimeImpl httpServiceRuntime; }
\ No newline at end of file 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 index b6f4b31d9..dd105afa9 100644 --- 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 @@ -29,5 +29,5 @@ public class ExtendedErrorPageDTO extends ErrorPageDTO { /** * Indicates the type of error codes defined. This is calculated by the system. */ - public ErrorCodeType erroCodeType; + public ErrorCodeType errorCodeType; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/NullServletContextHelperException.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/NullServletContextHelperException.java index f66e798cd..87f5e8bdd 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/NullServletContextHelperException.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/NullServletContextHelperException.java @@ -22,7 +22,7 @@ public class NullServletContextHelperException extends IllegalArgumentException private static final long serialVersionUID = 8516340810740210836L; public NullServletContextHelperException() { - super("ServletContexHelper cannot be null."); + super("ServletContexHelper cannot be null."); //$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/error/PatternInUseException.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/PatternInUseException.java index 41f2e0843..9fb53303f 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/PatternInUseException.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/PatternInUseException.java @@ -24,6 +24,6 @@ public class PatternInUseException extends NamespaceException { private static final long serialVersionUID = -4196149175131735927L; public PatternInUseException(String pattern) { - super("Pattern already in use: " + pattern); + super("Pattern already in use: " + pattern); //$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/error/RegisteredServletContextHelperException.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredServletContextHelperException.java index 940a139e1..3d0aba890 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredServletContextHelperException.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/RegisteredServletContextHelperException.java @@ -25,7 +25,7 @@ public class RegisteredServletContextHelperException private static final long serialVersionUID = 7301237379456486249L; public RegisteredServletContextHelperException() { - super("ServletContextHelper has already been registered."); + super("ServletContextHelper has already been registered."); //$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/error/ServletAlreadyRegisteredException.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/ServletAlreadyRegisteredException.java index 2af4eec32..522bd5548 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/ServletAlreadyRegisteredException.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/error/ServletAlreadyRegisteredException.java @@ -25,7 +25,7 @@ public class ServletAlreadyRegisteredException extends ServletException { private static final long serialVersionUID = 8838939310124336724L; public ServletAlreadyRegisteredException(Servlet servlet) { - super("Servlet has already been registered: " + servlet); + super("Servlet has already been registered: " + servlet); //$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/multipart/MultipartSupportFactory.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactory.java index 05b03d3d3..0d7066edc 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactory.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactory.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 @@ -14,10 +14,10 @@ package org.eclipse.equinox.http.servlet.internal.multipart; import javax.servlet.ServletContext; -import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; +import org.osgi.service.http.runtime.dto.ServletDTO; public interface MultipartSupportFactory { - MultipartSupport newInstance(ExtendedServletDTO servletDTO, ServletContext servletContext); + MultipartSupport newInstance(ServletDTO servletDTO, ServletContext servletContext); }
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactoryImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactoryImpl.java index cb63bf6a1..d60a08fe6 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactoryImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportFactoryImpl.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 @@ -15,7 +15,7 @@ package org.eclipse.equinox.http.servlet.internal.multipart; import javax.servlet.ServletContext; import org.apache.commons.fileupload.FileUploadException; -import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; +import org.osgi.service.http.runtime.dto.ServletDTO; public class MultipartSupportFactoryImpl implements MultipartSupportFactory { @@ -23,7 +23,7 @@ public class MultipartSupportFactoryImpl public static final Class<?> FAIL_EARLY = FileUploadException.class; @Override - public MultipartSupport newInstance(ExtendedServletDTO servletDTO, ServletContext servletContext) { + public MultipartSupport newInstance(ServletDTO servletDTO, ServletContext servletContext) { return new MultipartSupportImpl(servletDTO, servletContext); } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportImpl.java index e23b27940..7f7c2b74d 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/multipart/MultipartSupportImpl.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 @@ -25,13 +25,13 @@ import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.service.http.runtime.dto.ServletDTO; public class MultipartSupportImpl implements MultipartSupport { - public MultipartSupportImpl(ExtendedServletDTO servletDTO, ServletContext servletContext) { + public MultipartSupportImpl(ServletDTO servletDTO, ServletContext servletContext) { this.servletDTO = servletDTO; // Must return non-null File. See Servlet 3.1 §4.8.1 @@ -107,7 +107,7 @@ public class MultipartSupportImpl implements MultipartSupport { return parts; } - private final ExtendedServletDTO servletDTO; + private final ServletDTO servletDTO; private final ServletFileUpload upload; 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 4f4bd27f4..52044f977 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 @@ -19,7 +19,7 @@ import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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.context.ServiceHolder; import org.eclipse.equinox.http.servlet.internal.servlet.Match; import org.osgi.dto.DTO; import org.osgi.framework.ServiceReference; @@ -81,12 +81,12 @@ public abstract class EndpointRegistration<D extends DTO> EndpointRegistration<?> endpointRegistration = (EndpointRegistration<?>)obj; - return getT().equals(endpointRegistration.getT()); + return getD().equals(endpointRegistration.getD()); } @Override public int hashCode() { - return Long.valueOf(getServiceId()).hashCode(); + return getD().hashCode(); } //Delegate the init call to the actual servlet @@ -123,6 +123,10 @@ public abstract class EndpointRegistration<D extends DTO> String name, String servletPath, String pathInfo, String extension, Match match) { + if (match == Match.ERROR) { + return null; + } + if (name != null) { if (getName().equals(name)) { return name; @@ -169,7 +173,11 @@ public abstract class EndpointRegistration<D extends DTO> @Override public int compareTo(EndpointRegistration<?> o) { - return servletHolder.compareTo(o.servletHolder); + int result = servletHolder.compareTo(o.servletHolder); + if (result == 0) { + result = Long.compare(getD().hashCode(), o.getD().hashCode()); + } + return result; } @Override diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ErrorPageRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ErrorPageRegistration.java new file mode 100644 index 000000000..d833b2b4b --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ErrorPageRegistration.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) Feb. 1, 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.registration; + +import javax.servlet.Servlet; +import org.eclipse.equinox.http.servlet.internal.context.ContextController; +import org.eclipse.equinox.http.servlet.internal.context.ServiceHolder; +import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; +import org.eclipse.equinox.http.servlet.internal.servlet.Match; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.context.ServletContextHelper; + +/** + * @author Raymond Augé + */ +public class ErrorPageRegistration extends EndpointRegistration<ExtendedErrorPageDTO> { + + public ErrorPageRegistration( + ServiceHolder<Servlet> servletHolder, ExtendedErrorPageDTO errorPageDTO, + ServletContextHelper servletContextHelper, + ContextController contextController) { + + super(servletHolder, errorPageDTO, servletContextHelper, contextController); + } + + @Override + public String getName() { + return getD().name; + } + + @Override + public String[] getPatterns() { + return EMPTY; + } + + @Override + public long getServiceId() { + return getD().serviceId; + } + + @Override + public ServiceReference<?> getServiceReference() { + return servletHolder.getServiceReference(); + } + + @Override + public boolean needDecode() { + return false; + } + + @Override + public String match( + String name, String servletPath, String pathInfo, String extension, + Match match) { + + if (match != Match.ERROR) { + return null; + } + + if (name != null) { + for (long errorCode : getD().errorCodes) { + if (String.valueOf(errorCode).equals(name)) { + return name; + } + } + + for (String exception : getD().exceptions) { + if (exception.equals(name)) { + return name; + } + } + } + + return null; + } + + private static final String[] EMPTY = new String[0]; + +} 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 8cc36da4f..6c84a4590 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 @@ -21,7 +21,7 @@ import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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.context.ServiceHolder; 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; @@ -236,10 +236,6 @@ public class FilterRegistration 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 false; diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ListenerRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ListenerRegistration.java index cf79c4d3f..5e4321e67 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ListenerRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/ListenerRegistration.java @@ -19,7 +19,7 @@ import java.util.*; import javax.servlet.*; import javax.servlet.http.*; 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.context.ServiceHolder; import org.eclipse.equinox.http.servlet.internal.servlet.HttpSessionAdaptor; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.http.runtime.dto.ListenerDTO; @@ -131,27 +131,36 @@ public class ListenerRegistration extends Registration<EventListener, ListenerDT contextController); } + ClassLoader getClassLoader() { + return classLoader; + } + + EventListener getDelegate() { + return super.getT(); + } + private class EventListenerInvocationHandler implements InvocationHandler { public EventListenerInvocationHandler() { } @Override - public Object invoke(Object proxy, Method method, Object[] args) + public Object invoke(Object theProxy, Method method, Object[] args) throws Throwable { - ClassLoader original = Thread.currentThread().getContextClassLoader(); + Thread thread = Thread.currentThread(); + ClassLoader original = thread.getContextClassLoader(); try { - Thread.currentThread().setContextClassLoader(classLoader); + thread.setContextClassLoader(getClassLoader()); try { - return method.invoke(ListenerRegistration.super.getT(), args); + return method.invoke(getDelegate(), args); } catch (InvocationTargetException e) { throw e.getCause(); } } finally { - Thread.currentThread().setContextClassLoader(original); + thread.setContextClassLoader(original); } } } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/PreprocessorRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/PreprocessorRegistration.java new file mode 100644 index 000000000..99f018300 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/PreprocessorRegistration.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) Feb. 2, 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.registration; + +import java.io.IOException; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; +import org.eclipse.equinox.http.servlet.internal.context.ServiceHolder; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.wiring.BundleWiring; +import org.osgi.service.http.runtime.dto.PreprocessorDTO; +import org.osgi.service.http.whiteboard.Preprocessor; + +/** + * @author Raymond Augé + */ +public class PreprocessorRegistration extends Registration<Preprocessor, PreprocessorDTO> + implements Comparable<PreprocessorRegistration> { + + private final ServiceHolder<Preprocessor> preprocessorHolder; + private final ClassLoader classLoader; + private final HttpServiceRuntimeImpl httpServiceRuntime; + + public PreprocessorRegistration( + ServiceHolder<Preprocessor> preprocessorHolder, PreprocessorDTO preprocessorDTO, + HttpServiceRuntimeImpl httpServiceRuntime) { + + super(preprocessorHolder.get(), preprocessorDTO); + this.preprocessorHolder = preprocessorHolder; + this.httpServiceRuntime = httpServiceRuntime; + this.classLoader = preprocessorHolder.getBundle().adapt(BundleWiring.class).getClassLoader(); + } + + @Override + public int compareTo(PreprocessorRegistration o) { + ServiceReference<Preprocessor> thisRef = preprocessorHolder.getServiceReference(); + ServiceReference<Preprocessor> otherRef = o.preprocessorHolder.getServiceReference(); + return thisRef.compareTo(otherRef); + } + + public void doFilter( + HttpServletRequest request, HttpServletResponse response, + FilterChain chain) + throws IOException, ServletException { + + ClassLoader original = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + getT().doFilter(request, response, chain); + } + finally { + Thread.currentThread().setContextClassLoader(original); + } + } + + @Override + public void destroy() { + ClassLoader original = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + httpServiceRuntime.getPreprocessorRegistrations().remove(preprocessorHolder.getServiceReference()); + preprocessorHolder.getBundle().getBundleContext().ungetService(preprocessorHolder.getServiceReference()); + super.destroy(); + getT().destroy(); + } + finally { + Thread.currentThread().setContextClassLoader(original); + preprocessorHolder.release(); + } + } + + @Override + public int hashCode() { + return Long.valueOf(getD().serviceId).hashCode(); + } + + public void init(FilterConfig filterConfig) throws ServletException { + ClassLoader original = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + + getT().init(filterConfig); + } + finally { + Thread.currentThread().setContextClassLoader(original); + } + } + +} 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 5a6e535e4..671f7d49f 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 @@ -16,7 +16,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.eclipse.equinox.http.servlet.internal.context.ServiceHolder; import org.osgi.framework.ServiceReference; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.dto.ResourceDTO; 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 9e61c8e9f..761a39146 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 @@ -20,18 +20,16 @@ import java.util.*; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; 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.context.ServiceHolder; 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.ServletDTO; //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> { +public class ServletRegistration extends EndpointRegistration<ServletDTO> { private static MultipartSupportFactory factory; @@ -52,14 +50,12 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO } public ServletRegistration( - ServiceHolder<Servlet> servletHolder, ExtendedServletDTO servletDTO, ExtendedErrorPageDTO errorPageDTO, + ServiceHolder<Servlet> servletHolder, ServletDTO servletDTO, ServletContextHelper servletContextHelper, ContextController contextController, ServletContext servletContext) { super(servletHolder, servletDTO, servletContextHelper, contextController); - this.errorPageDTO = errorPageDTO; - if (servletDTO.multipartEnabled) { if (factory == null) { throw new IllegalStateException( @@ -73,10 +69,6 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO needDecode = MatchableRegistration.patternsRequireDecode(servletDTO.patterns); } - public ExtendedErrorPageDTO getErrorPageDTO() { - return errorPageDTO; - } - @Override public String getName() { return getD().name; @@ -97,28 +89,6 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO return servletHolder.getServiceReference(); } - @Override - public String match( - String name, String servletPath, String pathInfo, String extension, - Match match) { - - if ((errorPageDTO != null) && (name != null)) { - for (long errorCode : errorPageDTO.errorCodes) { - if (String.valueOf(errorCode).equals(name)) { - return name; - } - } - - for (String exception : errorPageDTO.exceptions) { - if (exception.equals(name)) { - return name; - } - } - } - - return super.match(name, servletPath, pathInfo, extension, match); - } - public Map<String, Part> parseRequest(HttpServletRequest request) throws IOException, ServletException { if (multipartSupport == null) { throw new IOException("Servlet not configured for multipart!"); //$NON-NLS-1$ @@ -132,6 +102,5 @@ public class ServletRegistration extends EndpointRegistration<ExtendedServletDTO } private final boolean needDecode; - 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/FilterChainImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/FilterChainImpl.java index ea3dfeba6..6f9474e69 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/FilterChainImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/FilterChainImpl.java @@ -24,11 +24,11 @@ import org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration public class FilterChainImpl implements FilterChain { - private List<FilterRegistration> matchingFilterRegistrations; - private EndpointRegistration<?> registration; - private DispatcherType dispatcherType; + private final List<FilterRegistration> matchingFilterRegistrations; + private final EndpointRegistration<?> registration; + private final DispatcherType dispatcherType; + private final int filterCount; private int filterIndex = 0; - private int filterCount; public FilterChainImpl( List<FilterRegistration> matchingFilterRegistrations, @@ -41,7 +41,7 @@ public class FilterChainImpl implements FilterChain { } public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - while (filterIndex < filterCount) { + if (filterIndex < filterCount) { FilterRegistration filterRegistration = matchingFilterRegistrations.get(filterIndex++); if (filterRegistration.appliesTo(this)) { @@ -50,6 +50,7 @@ public class FilterChainImpl implements FilterChain { return; } } + registration.service((HttpServletRequest) request, (HttpServletResponse) response); } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletResponseWrapperImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletResponseWrapperImpl.java index 9f8755d93..ede5cefe8 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletResponseWrapperImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletResponseWrapperImpl.java @@ -32,14 +32,14 @@ public class HttpServletResponseWrapperImpl extends HttpServletResponseWrapper { } @Override - public void sendError(int status) { - this.status = status; + public void sendError(int theStatus) { + this.status = theStatus; } @Override - public void sendError(int status, String message) { - this.status = status; - this.message = message; + public void sendError(int theStatus, String theMessage) { + this.status = theStatus; + this.message = theMessage; } public String getMessage() { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/IncludeDispatchResponseWrapper.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/IncludeDispatchResponseWrapper.java index a3a8cf667..5fe6d0235 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/IncludeDispatchResponseWrapper.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/IncludeDispatchResponseWrapper.java @@ -97,6 +97,7 @@ public class IncludeDispatchResponseWrapper extends HttpServletResponseWrapper { } @Override + @SuppressWarnings("deprecation") public void setStatus(int sc, String sm) { return; } 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 ab69bf783..270bb07fd 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 @@ -19,6 +19,6 @@ package org.eclipse.equinox.http.servlet.internal.servlet; */ public enum Match { - EXACT, EXTENSION, REGEX, DEFAULT_SERVLET, CONTEXT_ROOT + EXACT, ERROR, EXTENSION, REGEX, DEFAULT_SERVLET, CONTEXT_ROOT } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/PreprocessorChainImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/PreprocessorChainImpl.java new file mode 100644 index 000000000..47f416fc3 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/PreprocessorChainImpl.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 IBM Corporation and others. + * + * 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: + * IBM Corporation - initial API and implementation + * Raymond Augé <raymond.auge@liferay.com> - Bug 436698 + *******************************************************************************/ +package org.eclipse.equinox.http.servlet.internal.servlet; + +import java.io.IOException; +import java.util.List; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.equinox.http.servlet.internal.registration.PreprocessorRegistration; + +public class PreprocessorChainImpl implements FilterChain { + + private final ProxyServlet proxyServlet; + private final List<PreprocessorRegistration> preprocessors; + private final String alias; + private final DispatcherType dispatcherType; + private final int filterCount; + private int filterIndex = 0; + + public PreprocessorChainImpl( + List<PreprocessorRegistration> preprocessors, + String alias, DispatcherType dispatcherType, ProxyServlet proxyServlet) { + + this.preprocessors = preprocessors; + this.alias = alias; + this.dispatcherType = dispatcherType; + this.proxyServlet = proxyServlet; + this.filterCount = preprocessors.size(); + } + + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + if (filterIndex < filterCount) { + PreprocessorRegistration registration = preprocessors.get(filterIndex++); + + registration.doFilter( + (HttpServletRequest) request, (HttpServletResponse) response, this); + + return; + } + + proxyServlet.dispatch( + (HttpServletRequest) request, (HttpServletResponse) response, alias, dispatcherType); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java index 9e97b0a0e..d56f08259 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java @@ -17,12 +17,19 @@ package org.eclipse.equinox.http.servlet.internal.servlet; import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.*; import javax.servlet.http.*; import org.eclipse.equinox.http.servlet.internal.Activator; import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl; import org.eclipse.equinox.http.servlet.internal.context.DispatchTargets; +import org.eclipse.equinox.http.servlet.internal.registration.PreprocessorRegistration; import org.eclipse.equinox.http.servlet.internal.util.Const; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.whiteboard.Preprocessor; /** * The ProxyServlet is the private side of a Servlet that when registered (and init() called) in a servlet container @@ -88,11 +95,50 @@ public class ProxyServlet extends HttpServlet { alias = Const.SLASH; } + preprocess(request, response, alias, request.getDispatcherType()); + } + + public void preprocess( + HttpServletRequest request, + HttpServletResponse response, String alias, DispatcherType dispatcherType) + throws ServletException, IOException { + + Map<ServiceReference<Preprocessor>, PreprocessorRegistration> registrations = httpServiceRuntimeImpl.getPreprocessorRegistrations(); + + if (registrations.isEmpty()) { + dispatch(request, response, alias, dispatcherType); + } + else { + List<PreprocessorRegistration> preprocessors = new CopyOnWriteArrayList<>(); + + for (Entry<ServiceReference<Preprocessor>, PreprocessorRegistration> entry : registrations.entrySet()) { + PreprocessorRegistration registration = entry.getValue(); + preprocessors.add(registration); + registration.addReference(); + } + + try { + FilterChain chain = new PreprocessorChainImpl(preprocessors, alias, dispatcherType, this); + + chain.doFilter(request, response); + } + finally { + for (PreprocessorRegistration registration : preprocessors) { + registration.removeReference(); + } + } + } + } + + public void dispatch( + HttpServletRequest request, + HttpServletResponse response, String alias, DispatcherType dispatcherType) + throws ServletException, IOException { + DispatchTargets dispatchTargets = httpServiceRuntimeImpl.getDispatchTargets(alias, null); if (dispatchTargets != null) { - dispatchTargets.doDispatch( - request, response, alias, request.getDispatcherType()); + dispatchTargets.doDispatch(request, response, alias, dispatcherType); return; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java index 3bbb79755..c3d23e404 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java @@ -148,9 +148,7 @@ public class ResourceServlet extends HttpServlet { if (contentLength != 0) { // open the input stream - InputStream is = null; - try { - is = connection.getInputStream(); + try (InputStream is = connection.getInputStream()) { // write the resource try { OutputStream os = resp.getOutputStream(); @@ -173,13 +171,6 @@ public class ResourceServlet extends HttpServlet { // SecurityException may indicate the following scenarios // - url is not accessible sendError(resp, HttpServletResponse.SC_FORBIDDEN); - } finally { - if (is != null) - try { - is.close(); - } catch (IOException e) { - // ignore - } } } return Boolean.TRUE; @@ -233,8 +224,7 @@ public class ResourceServlet extends HttpServlet { } } - Reader reader = new InputStreamReader(is); - try { + try (Reader reader = new InputStreamReader(is)) { char[] buffer = new char[8192]; int charsRead = reader.read(buffer); int writtenContentLength = 0; @@ -246,10 +236,6 @@ public class ResourceServlet extends HttpServlet { writtenContentLength += charsRead; charsRead = reader.read(buffer); } - } finally { - if (reader != null) { - reader.close(); // will also close input stream - } } } 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 c3f820753..caffecf6b 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 @@ -62,16 +62,21 @@ public class ResponseStateHandler { } if (endpoint.getServletContextHelper().handleSecurity(request, response)) { - if (filters.isEmpty()) { - endpoint.service(request, response); - } - else { - Collections.sort(filters); + try { + if (filters.isEmpty()) { + endpoint.service(request, response); + } + else { + Collections.sort(filters); - FilterChain chain = new FilterChainImpl( - filters, endpoint, dispatchTargets.getDispatcherType()); + FilterChain chain = new FilterChainImpl( + filters, endpoint, dispatchTargets.getDispatcherType()); - chain.doFilter(request, response); + chain.doFilter(request, response); + } + } + finally { + endpoint.getServletContextHelper().finishSecurity(request, response); } } } @@ -144,14 +149,12 @@ public class ResponseStateHandler { responseWrapper.setCompleted(true); } else { - try { - PrintWriter writer = response.getWriter(); - writer.close(); + try (PrintWriter writer = response.getWriter()) { + // just force a close } catch (IllegalStateException ise1) { - try { - ServletOutputStream outputStream = response.getOutputStream(); - outputStream.close(); + try (ServletOutputStream outputStream = response.getOutputStream()) { + // just force a close } catch (IllegalStateException ise2) { // ignore @@ -219,7 +222,7 @@ public class ResponseStateHandler { do { errorDispatchTargets = contextController.getDispatchTargets( - className, null, null, null, null, null, Match.EXACT, null); + className, null, null, null, null, null, Match.ERROR, null); if (errorDispatchTargets != null) { break; @@ -319,7 +322,7 @@ public class ResponseStateHandler { ContextController contextController = dispatchTargets.getContextController(); DispatchTargets errorDispatchTargets = contextController.getDispatchTargets( - String.valueOf(status), null, null, null, null, null, Match.EXACT, null); + String.valueOf(status), null, null, null, null, null, Match.ERROR, null); if (errorDispatchTargets == null) { wrappedResponse.sendError(status, responseWrapper.getMessage()); diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java index b70a0165a..d72037e56 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java @@ -395,8 +395,8 @@ public class ServletContextAdaptor { Object invoke(Object proxy, Method method, Object[] args) throws Throwable { boolean useThreadLocal = - "removeAttribute".equals(method.getName()) || - "setAttribute".equals(method.getName()); + "removeAttribute".equals(method.getName()) || //$NON-NLS-1$ + "setAttribute".equals(method.getName()); //$NON-NLS-1$ if (useThreadLocal) { servletContextTL.set((ServletContext)proxy); 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 59899f3fc..c7353a7ab 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 @@ -14,11 +14,16 @@ package org.eclipse.equinox.http.servlet.internal.util; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; + import java.lang.reflect.Array; import java.util.*; -import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO; -import org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO; +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.HttpWhiteboardFailureException; import org.osgi.dto.DTO; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; import org.osgi.service.http.runtime.dto.*; /** @@ -26,6 +31,220 @@ import org.osgi.service.http.runtime.dto.*; */ public class DTOUtil { + public static ExtendedErrorPageDTO assembleErrorPageDTO(ServiceReference<?> serviceReference, long contextId, boolean validated) { + Object errorPageObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ERROR_PAGE); + + if (errorPageObj == null) { + return null; + } + + ExtendedErrorPageDTO errorPageDTO = new ExtendedErrorPageDTO(); + + errorPageDTO.asyncSupported = false; + Object asyncSupportedObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); + if (asyncSupportedObj == null) { + // ignored + } + else if (Boolean.class.isInstance(asyncSupportedObj)) { + errorPageDTO.asyncSupported = ((Boolean)asyncSupportedObj).booleanValue(); + } + else if (String.class.isInstance(asyncSupportedObj)) { + errorPageDTO.asyncSupported = Boolean.valueOf((String)asyncSupportedObj); + } + // There is no validation for this scenario, truthiness of any other input is false + + List<String> errorPages = StringPlus.from(errorPageObj); + if (errorPages.isEmpty()) { + throw new HttpWhiteboardFailureException("'errorPage' expects String, String[] or Collection<String>", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + List<String> exceptions = new ArrayList<String>(); + Set<Long> errorCodeSet = new LinkedHashSet<Long>(); + + for(String errorPage : errorPages) { + try { + if ("4xx".equals(errorPage)) { //$NON-NLS-1$ + errorPageDTO.errorCodeType = ErrorCodeType.RANGE_4XX; + for (long code = 400; code < 500; code++) { + errorCodeSet.add(code); + } + } else if ("5xx".equals(errorPage)) { //$NON-NLS-1$ + errorPageDTO.errorCodeType = ErrorCodeType.RANGE_5XX; + for (long code = 500; code < 600; code++) { + errorCodeSet.add(code); + } + } else if (errorPage.matches("\\d{3}")) { //$NON-NLS-1$ + errorPageDTO.errorCodeType = ErrorCodeType.SPECIFIC; + long code = Long.parseLong(errorPage); + errorCodeSet.add(code); + } else { + exceptions.add(errorPage); + } + } + catch (NumberFormatException nfe) { + exceptions.add(errorPage); + } + } + + errorPageDTO.errorCodes = new long[errorCodeSet.size()]; + int i = 0; + for(Long code : errorCodeSet) { + errorPageDTO.errorCodes[i] = code; + i++; + } + + errorPageDTO.exceptions = exceptions.toArray(new String[0]); + + errorPageDTO.initParams = ServiceProperties.parseInitParams( + serviceReference, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); + + Object servletNameObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_NAME); + if (servletNameObj == null) { + // ignore + } + else if (String.class.isInstance(servletNameObj)) { + errorPageDTO.name = (String)servletNameObj; + } + else if (validated) { + throw new HttpWhiteboardFailureException("'name' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + errorPageDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); + errorPageDTO.servletContextId = contextId; + + return errorPageDTO; + } + + @SuppressWarnings("deprecation") + public static org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO assembleServletDTO(ServiceReference<?> serviceReference, long contextId, boolean validated) { + org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO servletDTO = new org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO(); + + servletDTO.asyncSupported = false; + Object asyncSupportedObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); + if (asyncSupportedObj == null) { + // ignored + } + else if (Boolean.class.isInstance(asyncSupportedObj)) { + servletDTO.asyncSupported = ((Boolean)asyncSupportedObj).booleanValue(); + } + else if (String.class.isInstance(asyncSupportedObj)) { + servletDTO.asyncSupported = Boolean.valueOf((String)asyncSupportedObj); + } + // There is no validation for this scenario, truthiness of any other input is false + + servletDTO.initParams = ServiceProperties.parseInitParams( + serviceReference, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); + + servletDTO.multipartEnabled = false; + Object multipartEnabledObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED); + if (multipartEnabledObj == null) { + multipartEnabledObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_ENABLED); + } + if (multipartEnabledObj == null) { + // ignore + } + else if (Boolean.class.isInstance(multipartEnabledObj)) { + servletDTO.multipartEnabled = ((Boolean)multipartEnabledObj).booleanValue(); + } + else if (String.class.isInstance(multipartEnabledObj)) { + servletDTO.multipartEnabled = Boolean.valueOf((String)multipartEnabledObj); + } + // There is no validation for this scenario, truthiness of any other input is false + + servletDTO.multipartFileSizeThreshold = 0; + servletDTO.multipartLocation = Const.BLANK; + servletDTO.multipartMaxFileSize = -1L; + servletDTO.multipartMaxRequestSize = -1L; + + if (servletDTO.multipartEnabled) { + Object multipartFileSizeThresholdObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_FILESIZETHRESHOLD); + if (multipartFileSizeThresholdObj == null) { + multipartFileSizeThresholdObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_FILESIZETHRESHOLD); + } + if (multipartFileSizeThresholdObj == null) { + // ignore + } + else if (Integer.class.isInstance(multipartFileSizeThresholdObj)) { + servletDTO.multipartFileSizeThreshold = ((Integer)multipartFileSizeThresholdObj).intValue(); + } + else if (validated) { + throw new HttpWhiteboardFailureException("'multipartFileSizeThreshold' expects int or Integer", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + Object multipartLocationObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_LOCATION); + if (multipartLocationObj == null) { + multipartLocationObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_LOCATION); + } + if (multipartLocationObj == null) { + // ignore + } + else if (String.class.isInstance(multipartLocationObj)) { + servletDTO.multipartLocation = (String)multipartLocationObj; + } + else if (validated) { + throw new HttpWhiteboardFailureException("'multipartLocation' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + Object multipartMaxFileSizeObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE); + if (multipartMaxFileSizeObj == null) { + multipartMaxFileSizeObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_MAXFILESIZE); + } + if (multipartMaxFileSizeObj == null) { + // ignore + } + else if (Long.class.isInstance(multipartMaxFileSizeObj)) { + servletDTO.multipartMaxFileSize = ((Long)multipartMaxFileSizeObj).longValue(); + } + else if (validated) { + throw new HttpWhiteboardFailureException("'multipartMaxFileSize' expects [L|l]ong", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + Object multipartMaxRequestSizeObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXREQUESTSIZE); + if (multipartMaxRequestSizeObj == null) { + multipartMaxRequestSizeObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE); + } + if (multipartMaxRequestSizeObj == null) { + // ignore + } + else if (Long.class.isInstance(multipartMaxRequestSizeObj)) { + servletDTO.multipartMaxRequestSize = ((Long)multipartMaxRequestSizeObj).longValue(); + } + else if (validated) { + throw new HttpWhiteboardFailureException("'multipartMaxRequestSize' expects [L|l]ong", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + } + + Object servletNameObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_NAME); + if (servletNameObj == null) { + // ignore + } + else if (String.class.isInstance(servletNameObj)) { + servletDTO.name = (String)servletNameObj; + } + else if (validated) { + throw new HttpWhiteboardFailureException("'name' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ + } + + Object patternObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_PATTERN); + if (patternObj == null) { + servletDTO.patterns = new String[0]; + } + else { + servletDTO.patterns = sort(StringPlus.from(patternObj).toArray(new String[0])); + + if (validated && (servletDTO.patterns.length > 0)) { + for (String pattern : servletDTO.patterns) { + checkPattern(pattern); + } + } + } + + servletDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); + servletDTO.servletContextId = contextId; + + return servletDTO; + } + public static ErrorPageDTO clone(ErrorPageDTO original) { ErrorPageDTO clone = new ErrorPageDTO(); @@ -85,6 +304,16 @@ public class DTOUtil { return clone; } + public static FailedPreprocessorDTO clone(FailedPreprocessorDTO original) { + FailedPreprocessorDTO clone = new FailedPreprocessorDTO(); + + clone.failureReason = copy(original.failureReason); + clone.initParams = copyStringMap(original.initParams); + clone.serviceId = copy(original.serviceId); + + return clone; + } + public static FailedResourceDTO clone(FailedResourceDTO original) { FailedResourceDTO clone = new FailedResourceDTO(); @@ -115,8 +344,8 @@ public class DTOUtil { return clone; } - public static ExtendedFailedServletDTO clone(ExtendedFailedServletDTO original) { - ExtendedFailedServletDTO clone = new ExtendedFailedServletDTO(); + public static FailedServletDTO clone(FailedServletDTO original) { + FailedServletDTO clone = new FailedServletDTO(); clone.asyncSupported = copy(original.asyncSupported); clone.failureReason = copy(original.failureReason); @@ -172,8 +401,8 @@ public class DTOUtil { return clone; } - public static ExtendedServletDTO clone(ExtendedServletDTO original) { - ExtendedServletDTO clone = new ExtendedServletDTO(); + public static ServletDTO clone(ServletDTO original) { + ServletDTO clone = new ServletDTO(); clone.asyncSupported = copy(original.asyncSupported); clone.initParams = copyStringMap(original.initParams); @@ -301,6 +530,32 @@ public class DTOUtil { return String.valueOf(v); } + private static void checkPattern(String pattern) { + if (pattern == 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.contains("**")) { //$NON-NLS-1$ + + throw new HttpWhiteboardFailureException( + "Invalid pattern '" + pattern + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + private static Class<?> mapComponentType(Class<?> componentType) { if (componentType.isPrimitive() || componentType.isArray() @@ -335,4 +590,15 @@ public class DTOUtil { private static <K, V> Map<K, V> newMap(int size) { return new HashMap<K, V>(size); } + + private static String[] sort(String[] values) { + if (values == null) { + return null; + } + + Arrays.sort(values); + + return values; + } + } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/EventListeners.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/EventListeners.java index ff1d9fd8c..e19f00e62 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/EventListeners.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/EventListeners.java @@ -26,7 +26,7 @@ public class EventListeners { public <E extends EventListener> List<E> get(Class<E> clazz) { if (clazz == null) { - throw new NullPointerException("clazz can't be null"); + throw new NullPointerException("clazz can't be null"); //$NON-NLS-1$ } List<ListenerRegistration> list = map.get(clazz); @@ -42,7 +42,7 @@ public class EventListeners { Class<E> clazz, ListenerRegistration listenerRegistration) { if (clazz == null) { - throw new NullPointerException("clazz can't be null"); + throw new NullPointerException("clazz can't be null"); //$NON-NLS-1$ } List<ListenerRegistration> list = map.get(clazz); @@ -74,7 +74,7 @@ public class EventListeners { Class<E> clazz, ListenerRegistration listenerRegistration) { if (clazz == null) { - throw new NullPointerException("clazz can't be null"); + throw new NullPointerException("clazz can't be null"); //$NON-NLS-1$ } List<ListenerRegistration> list = map.get(clazz); diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpTuple.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpTuple.java index 016437e51..b7183c9f1 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpTuple.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/util/HttpTuple.java @@ -39,6 +39,7 @@ public class HttpTuple { Activator.unregisterHttpService(proxyServlet); proxyServlet.setHttpServiceRuntimeImpl(null); hsfRegistration.unregister(); + httpServiceRuntime.setHsrRegistration(null); hsrRegistration.unregister(); httpServiceRuntime.destroy(); } |