You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jl...@apache.org on 2022/01/25 17:17:01 UTC

[tomee] 01/01: Add some fixes and prepare for some refactoring

This is an automated email from the ASF dual-hosted git repository.

jlmonteiro pushed a commit to branch jaxws-improvements
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit f2a77ae409561a26cf450e42c96ee449afc081c8
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Tue Jan 25 18:16:41 2022 +0100

    Add some fixes and prepare for some refactoring
---
 .../tests/jaxws/WebServiceContextEJBTest.java      | 30 ++++++--
 .../main/java/org/apache/openejb/util/Strings.java | 26 ++++++-
 .../java/org/apache/openejb/util/StringsTest.java  | 89 ++++++++++++++++++++++
 .../main/java/org/apache/openejb/jee/WebApp.java   | 14 ++--
 .../openejb/server/webservices/WsService.java      | 14 ++--
 .../apache/tomee/webservices/TomcatWsRegistry.java | 84 +++++---------------
 6 files changed, 176 insertions(+), 81 deletions(-)

diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/WebServiceContextEJBTest.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/WebServiceContextEJBTest.java
index 131d05c..a3c3145 100644
--- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/WebServiceContextEJBTest.java
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/WebServiceContextEJBTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.openejb.arquillian.tests.jaxws;
 
+import org.apache.openejb.loader.IO;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.junit.Arquillian;
 import org.jboss.arquillian.test.api.ArquillianResource;
@@ -26,10 +27,12 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.jboss.shrinkwrap.descriptor.api.Descriptors;
 import org.jboss.shrinkwrap.descriptor.api.webapp31.WebAppDescriptor;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import javax.annotation.Resource;
+import javax.ejb.Stateless;
 import javax.inject.Inject;
 import javax.jws.WebMethod;
 import javax.jws.WebParam;
@@ -73,9 +76,6 @@ public class WebServiceContextEJBTest {
                 .createServletMapping()
                 .servletName("HelloService")
                 .urlPattern("/internal/Hello")
-                .up()
-                .createServletMapping()
-                .servletName("HelloService")
                 .urlPattern("/tomee/Hello")
                 .up()
             ;
@@ -90,21 +90,31 @@ public class WebServiceContextEJBTest {
 
     @Test
     public void invokePojo() throws Exception {
-        // System.out.println(IO.slurp(new URL(url.toExternalForm() + "/ws/Hello?wsdl")));
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/ws/Hello?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/ws/Hello?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         final QName portQName = new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "HelloService");
         assertServiceInvocation(service, portQName);
     }
 
     @Test
+    //@Ignore
     public void invokePojoAlternate() throws Exception {
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/internal/Hello?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/internal/Hello?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         final QName portQName = new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "HelloService");
         assertServiceInvocation(service, portQName);
     }
 
     @Test
+    //@Ignore
     public void invokePojoAlternate2() throws Exception {
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/tomee/Hello?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/tomee/Hello?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         final QName portQName = new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "HelloService");
         assertServiceInvocation(service, portQName);
@@ -123,19 +133,29 @@ public class WebServiceContextEJBTest {
      */
     @Test
     public void invokeEjb() throws Exception {
-        // System.out.println(IO.slurp(new URL(url.toExternalForm() + "/webservices/ws/HelloEjb?wsdl")));
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/webservices/ws/HelloEjb?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/webservices/ws/HelloEjb?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         assertServiceInvocationWithPort(service);
     }
 
     @Test
+    //@Ignore
     public void invokeEjbAlternate() throws Exception {
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/webservices/internal/HelloEjb?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/webservices/internal/HelloEjb?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         assertServiceInvocationWithPort(service);
     }
 
     @Test
+    //@Ignore
     public void invokeEjbAlternate2() throws Exception {
+        System.out.println("----");
+        System.out.println(IO.slurp(new URL(url.toExternalForm() + "/webservices/tomee/HelloEjb?wsdl")));
+        System.out.println("----");
         final Service service = Service.create(new URL(url.toExternalForm() + "/webservices/tomee/HelloEjb?wsdl"), new QName("http://jaxws.tests.arquillian.openejb.apache.org/", "Hello"));
         assertServiceInvocationWithPort(service);
     }
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/util/Strings.java b/container/openejb-core/src/main/java/org/apache/openejb/util/Strings.java
index b568308..4d0edd2 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/util/Strings.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/util/Strings.java
@@ -110,8 +110,32 @@ public class Strings {
     public static String lastPart(final String className, final char sep) {
         final int idx = className.lastIndexOf(sep);
         if (idx >= 0) {
-            return className.substring(idx + 1, className.length());
+            return className.substring(idx + 1);
         }
         return className;
     }
+
+    public static String forceSlash(final String property) {
+        if (property == null) {
+            return "/";
+        }
+        if (!property.startsWith("/")) {
+            return "/" + property;
+        }
+        return property;
+    }
+
+    public static String slashify(final String ... parts) {
+        if (parts == null || parts.length == 0) {
+            return "/";
+        }
+        final StringBuilder path = new StringBuilder();
+        for (String part : parts) {
+            if (path.length() >= 1 && path.charAt(path.length() - 1) == '/') {
+                path.deleteCharAt(path.length() - 1);
+            }
+            path.append(forceSlash(part));
+        }
+        return path.toString();
+    }
 }
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/util/StringsTest.java b/container/openejb-core/src/test/java/org/apache/openejb/util/StringsTest.java
new file mode 100644
index 0000000..677c132
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/util/StringsTest.java
@@ -0,0 +1,89 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.util;
+
+import junit.framework.TestCase;
+
+public class StringsTest extends TestCase {
+
+    public void testForceSlash() {
+        assertEquals("/", Strings.forceSlash(null));
+        assertEquals("/", Strings.forceSlash(""));
+        assertEquals("/", Strings.forceSlash("/"));
+        assertEquals("/hello", Strings.forceSlash("/hello"));
+        assertEquals("/test/", Strings.forceSlash("/test/"));
+        assertEquals("/path/", Strings.forceSlash("path/"));
+    }
+
+    public void testSlashify() {
+
+        // same as previous
+        assertEquals("/", Strings.slashify(null));
+        assertEquals("/", Strings.slashify(""));
+        assertEquals("/", Strings.slashify("/"));
+        assertEquals("/hello", Strings.slashify("/hello"));
+        assertEquals("/test/", Strings.slashify("/test/"));
+        assertEquals("/path/", Strings.slashify("path/"));
+
+        assertEquals("/", Strings.slashify(null, null));
+        assertEquals("/", Strings.slashify(null, ""));
+        assertEquals("/", Strings.slashify(null, "/"));
+        assertEquals("/hello", Strings.slashify(null, "/hello"));
+        assertEquals("/test/", Strings.slashify(null, "/test/"));
+        assertEquals("/path/", Strings.slashify(null, "path/"));
+
+        assertEquals("/", Strings.slashify("", null));
+        assertEquals("/", Strings.slashify("", ""));
+        assertEquals("/", Strings.slashify("", "/"));
+        assertEquals("/hello", Strings.slashify("", "/hello"));
+        assertEquals("/test/", Strings.slashify("", "/test/"));
+        assertEquals("/path/", Strings.slashify("", "path/"));
+
+        assertEquals("/", Strings.slashify("/", null));
+        assertEquals("/", Strings.slashify("/", ""));
+        assertEquals("/", Strings.slashify("/", "/"));
+        assertEquals("/hello", Strings.slashify("/", "/hello"));
+        assertEquals("/test/", Strings.slashify("/", "/test/"));
+        assertEquals("/path/", Strings.slashify("/", "path/"));
+
+        assertEquals("/hello/", Strings.slashify("/hello", null));
+        assertEquals("/hello/", Strings.slashify("/hello", ""));
+        assertEquals("/hello/", Strings.slashify("/hello", "/"));
+        assertEquals("/hello/hello", Strings.slashify("/hello", "/hello"));
+        assertEquals("/hello/test/", Strings.slashify("/hello", "/test/"));
+        assertEquals("/hello/path/", Strings.slashify("/hello", "path/"));
+
+        assertEquals("/test/", Strings.slashify("/test/", null));
+        assertEquals("/test/", Strings.slashify("/test/", ""));
+        assertEquals("/test/", Strings.slashify("/test/", "/"));
+        assertEquals("/test/hello", Strings.slashify("/test/", "/hello"));
+        assertEquals("/test/test/", Strings.slashify("/test/", "/test/"));
+        assertEquals("/test/path/", Strings.slashify("/test/", "path/"));
+
+        assertEquals("/path/", Strings.slashify("path/", null));
+        assertEquals("/path/", Strings.slashify("path/", ""));
+        assertEquals("/path/", Strings.slashify("path/", "/"));
+        assertEquals("/path/hello", Strings.slashify("path/", "/hello"));
+        assertEquals("/path/test/", Strings.slashify("path/", "/test/"));
+        assertEquals("/path/path/", Strings.slashify("path/", "path/"));
+
+        // double slash in the middle of a part should not be altered
+        assertEquals("/path/te//st/", Strings.slashify("path/", "/te//st/"));
+    }
+    
+}
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
index 3f59ece..b604d94 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
@@ -656,27 +656,29 @@ public class WebApp implements WebCommon, Lifecycle, NamedModule {
     }
 
     public List<String> getServletMappings(final String servletName) {
-        if (servletMapping == null || servletName == null) {
+        if (servletName == null || servletMapping == null || servletMapping.isEmpty()) {
             return Collections.emptyList();
         }
+        final List<String> mappings = new ArrayList<>();
         for (final ServletMapping mapping : servletMapping) {
             if (servletName.equals(mapping.getServletName())) {
-                return mapping.getUrlPattern();
+                mappings.addAll(mapping.getUrlPattern());
             }
         }
-        return Collections.emptyList();
+        return mappings;
     }
 
     public List<String> getFilterMappings(final String filterName) {
-        if (filterMapping == null || filterName == null) {
+        if (filterName == null || filterMapping == null || filterMapping.isEmpty()) {
             return Collections.emptyList();
         }
+        final List<String> mappings = new ArrayList<>();
         for (final FilterMapping mapping : filterMapping) {
             if (filterName.equals(mapping.getFilterName())) {
-                return mapping.getUrlPattern();
+                mappings.addAll(mapping.getUrlPattern());
             }
         }
-        return Collections.emptyList();
+        return mappings;
     }
 
     private Servlet findServlet(final String name) {
diff --git a/server/openejb-webservices/src/main/java/org/apache/openejb/server/webservices/WsService.java b/server/openejb-webservices/src/main/java/org/apache/openejb/server/webservices/WsService.java
index 7540cbe..38b960a 100644
--- a/server/openejb-webservices/src/main/java/org/apache/openejb/server/webservices/WsService.java
+++ b/server/openejb-webservices/src/main/java/org/apache/openejb/server/webservices/WsService.java
@@ -438,12 +438,14 @@ public abstract class WsService implements ServerService, SelfManaging {
                     // one of the registered addresses to be the connonical address
                     final String address = HttpUtil.selectSingleAddress(addresses);
 
-                    // add address to global registry
-                    portAddressRegistry.addPort(portInfo.serviceId, portInfo.wsdlService, portInfo.portId, portInfo.wsdlPort, portInfo.seiInterfaceName, address);
-                    setWsdl(container, address);
-                    LOGGER.info("Webservice(wsdl=" + address + ", qname=" + port.getWsdlService() + ") --> Pojo(id=" + portInfo.portId + ")");
-                    servletAddresses.put(webApp.moduleId + "." + servlet.servletName, address);
-                    addressesForApp(webApp.moduleId).add(new EndpointInfo(address, port.getWsdlService(), target.getName()));
+                    if (address != null) {
+                        // add address to global registry
+                        portAddressRegistry.addPort(portInfo.serviceId, portInfo.wsdlService, portInfo.portId, portInfo.wsdlPort, portInfo.seiInterfaceName, address);
+                        setWsdl(container, address);
+                        LOGGER.info("Webservice(wsdl=" + address + ", qname=" + port.getWsdlService() + ") --> Pojo(id=" + portInfo.portId + ")");
+                        servletAddresses.put(webApp.moduleId + "." + servlet.servletName, address);
+                        addressesForApp(webApp.moduleId).add(new EndpointInfo(address, port.getWsdlService(), target.getName()));
+                    }
                 }
             } catch (final Throwable e) {
                 LOGGER.error("Error deploying CXF webservice for servlet " + portInfo.serviceLink, e);
diff --git a/tomee/tomee-webservices/src/main/java/org/apache/tomee/webservices/TomcatWsRegistry.java b/tomee/tomee-webservices/src/main/java/org/apache/tomee/webservices/TomcatWsRegistry.java
index fc03249..0b2e80a 100644
--- a/tomee/tomee-webservices/src/main/java/org/apache/tomee/webservices/TomcatWsRegistry.java
+++ b/tomee/tomee-webservices/src/main/java/org/apache/tomee/webservices/TomcatWsRegistry.java
@@ -37,6 +37,7 @@ import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.server.httpd.HttpListener;
 import org.apache.openejb.server.webservices.WsRegistry;
 import org.apache.openejb.server.webservices.WsServlet;
+import org.apache.openejb.util.Strings;
 import org.apache.tomcat.util.descriptor.web.LoginConfig;
 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
@@ -57,7 +58,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import static java.util.Arrays.asList;
 
 public class TomcatWsRegistry implements WsRegistry {
-    private static final String WEBSERVICE_SUB_CONTEXT = forceSlash(SystemInstance.get().getOptions().get("tomee.jaxws.subcontext", "/webservices"));
+    private static final String WEBSERVICE_SUB_CONTEXT = Strings.slashify(SystemInstance.get().getOptions().get("tomee.jaxws.subcontext", "/webservices"));
 
     private static final boolean WEBSERVICE_OLDCONTEXT_ACTIVE = SystemInstance.get().getOptions().get("tomee.jaxws.oldsubcontext", false);
     private static final String TOMEE_JAXWS_SECURITY_ROLE_PREFIX = "tomee.jaxws.security-role.";
@@ -79,17 +80,6 @@ public class TomcatWsRegistry implements WsRegistry {
         }
     }
 
-    private static String forceSlash(final String property) {
-        if (property == null) {
-            return "/";
-        }
-        if (!property.startsWith("/")) {
-            return "/" + property;
-        }
-        return property;
-    }
-
-
     @Override
     public List<String> setWsContainer(final HttpListener httpListener,
                                        final ClassLoader classLoader,
@@ -103,7 +93,7 @@ public class TomcatWsRegistry implements WsRegistry {
 
         final Container host = engine.findChild(virtualHost);
         if (host == null) {
-            throw new IllegalArgumentException("Invalid virtual host '" + virtualHost + "'.  Do you have a matchiing Host entry in the server.xml?");
+            throw new IllegalArgumentException("Invalid virtual host '" + virtualHost + "'.  Do you have a matching Host entry in the server.xml?");
         }
 
         if ("ROOT".equals(contextRoot)) { // doesn't happen in tomee itself but with all our tooling around
@@ -124,7 +114,7 @@ public class TomcatWsRegistry implements WsRegistry {
         }
 
         // for Pojo web services, we need to change the servlet class which is the service implementation
-        // by the WsServler class
+        // by the WsServlet class
         wrapper.setServletClass(WsServlet.class.getName());
         if (wrapper.getServlet() != null) {
             wrapper.unload(); // deallocate previous one
@@ -138,15 +128,16 @@ public class TomcatWsRegistry implements WsRegistry {
         // add service locations
         final List<String> addresses = new ArrayList<>();
         for (final Connector connector : connectors) {
-            for (final String mapping : wrapper.findMappings()) {
-                final URI address = new URI(connector.getScheme(), null, host.getName(), connector.getPort(), (contextRoot.startsWith("/") ? "" : "/") + contextRoot + mapping, null, null);
+            for (final String mapping : servletInfo.mappings) {
+                final String absoluteMapping = Strings.slashify(contextRoot, mapping);
+                final URI address = new URI(connector.getScheme(), null, host.getName(), connector.getPort(),
+                                            absoluteMapping, null, null);
                 addresses.add(address.toString());
             }
         }
         return addresses;
     }
 
-
     @Override
     public void clearWsContainer(final String contextRoot, String virtualHost, final ServletInfo servletInfo, final String moduleId) {
         if (virtualHost == null) {
@@ -155,7 +146,7 @@ public class TomcatWsRegistry implements WsRegistry {
 
         final Container host = engine.findChild(virtualHost);
         if (host == null) {
-            throw new IllegalArgumentException("Invalid virtual host '" + virtualHost + "'.  Do you have a matchiing Host entry in the server.xml?");
+            throw new IllegalArgumentException("Invalid virtual host '" + virtualHost + "'.  Do you have a matching Host entry in the server.xml?");
         }
 
         final Context context = (Context) host.findChild("/" + contextRoot);
@@ -193,9 +184,7 @@ public class TomcatWsRegistry implements WsRegistry {
         }
 
         // assure context root with a leading slash
-        if (!path.startsWith("/")) {
-            path = "/" + path;
-        }
+        path = Strings.slashify(path);
 
         // find the existing host (we do not auto-create hosts)
         if (virtualHost == null) {
@@ -220,15 +209,11 @@ public class TomcatWsRegistry implements WsRegistry {
 
             if (webAppContext != null) {
                 // sub context = '/' means the service address is provided by webservices
-                if (WEBSERVICE_SUB_CONTEXT.equals("/") && path.startsWith("/")) {
-                    addServlet(host, webAppContext, path, httpListener, path, addresses, false, moduleId);
-                } else if (WEBSERVICE_SUB_CONTEXT.equals("/") && !path.startsWith("/")) {
-                    addServlet(host, webAppContext, '/' + path, httpListener, path, addresses, false, moduleId);
-                } else {
-                    addServlet(host, webAppContext, WEBSERVICE_SUB_CONTEXT + path, httpListener, path, addresses, false, moduleId);
-                }
+                    addServlet(host, webAppContext, Strings.slashify(WEBSERVICE_SUB_CONTEXT, path), httpListener,
+                               path, addresses, false, moduleId);
             } else if (!WEBSERVICE_OLDCONTEXT_ACTIVE) { // deploying in a jar
-                deployInFakeWebapp(path, classLoader, authMethod, transportGuarantee, realmName, host, httpListener, addresses, context);
+                deployInFakeWebapp(path, classLoader, authMethod, transportGuarantee,
+                                   realmName, host, httpListener, addresses, context);
             }
         }
         return addresses;
@@ -271,24 +256,12 @@ public class TomcatWsRegistry implements WsRegistry {
             fakeContextReferences.put(name, ref + 1);
         }
 
-        String mapping = path;
-        if (!mapping.startsWith("/")) { // TODO: check it can happen or move it away
-            mapping = '/' + mapping;
-        }
-        addServlet(host, (Context) context, mapping, httpListener, path, addresses, true, null);
+        addServlet(host, (Context) context, Strings.slashify(path), httpListener, path, addresses, true, null);
     }
 
     private static Context createNewContext(final ClassLoader classLoader, String authMethod, String transportGuarantee, final String realmName, final String name) {
-        String path = name;
-        if (path == null) {
-            path = "/";
-        }
-        if (!path.startsWith("/")) {
-            path = "/" + path;
-        }
-
         final StandardContext context = new IgnoredStandardContext();
-        context.setPath(path);
+        context.setPath(Strings.slashify(name));
         context.setDocBase("");
         context.setParentClassLoader(classLoader);
         context.setDelegate(true);
@@ -371,28 +344,15 @@ public class TomcatWsRegistry implements WsRegistry {
 
         // register wsdl locations for service-ref resolution
         for (final Connector connector : connectors) {
-            final StringBuilder fullContextpath;
+            final String fullContextPath;
             if (!WEBSERVICE_OLDCONTEXT_ACTIVE && !fakeDeployment) {
-                String contextPath = context.getPath();
-                if (contextPath == null ||  !contextPath.isEmpty()) {
-                    if (contextPath != null && !contextPath.startsWith("/")) {
-                        contextPath = "/" + contextPath;
-                    } else if (contextPath == null) {
-                        contextPath = "/";
-                    }
-                }
-
-                fullContextpath = new StringBuilder(contextPath);
-                if (!WEBSERVICE_SUB_CONTEXT.equals("/")) {
-                    fullContextpath.append(WEBSERVICE_SUB_CONTEXT);
-                }
-                fullContextpath.append(path);
+                fullContextPath = Strings.slashify(context.getPath(), WEBSERVICE_SUB_CONTEXT, path);
             } else {
-                fullContextpath = new StringBuilder(context.getPath()).append(path);
+                fullContextPath = Strings.slashify(context.getPath(), path);
             }
 
             try {
-                final URI address = new URI(connector.getScheme(), null, host.getName(), connector.getPort(), fullContextpath.toString(), null, null);
+                final URI address = new URI(connector.getScheme(), null, host.getName(), connector.getPort(), fullContextPath, null, null);
                 addresses.add(address.toString());
             } catch (final URISyntaxException ignored) {
                 // no-op
@@ -407,9 +367,7 @@ public class TomcatWsRegistry implements WsRegistry {
         }
 
         // assure context root with a leading slash
-        if (!path.startsWith("/")) {
-            path = "/" + path;
-        }
+        path = Strings.slashify(path);
 
         if (TomcatHelper.isStopping()) {
             return;