[SCB-1872] change System.setProperty to class loader level property to make run multiple services in container possible
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java
index 318824b..8e941a8 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java
@@ -24,6 +24,7 @@
 import org.apache.servicecomb.core.definition.MicroserviceMeta;
 import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.core.definition.SchemaMeta;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -101,7 +102,7 @@
   }
 
   public void buildProducerPaths() {
-    String urlPrefix = System.getProperty(Const.URL_PREFIX);
+    String urlPrefix = Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX);
     if (StringUtils.isEmpty(urlPrefix)) {
       producerPaths = swaggerPaths;
       producerPaths.printPaths();
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java
index a3c14b0..5ab7559 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java
@@ -19,15 +19,20 @@
 
 import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.api.Const;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class TestServicePathManager {
+  @After
+  public void tearDown() {
+    Deployment.clearClassLoaderScopeProperty();
+  }
+
   @Test
   public void testBuildProducerPathsNoPrefix() {
-    System.clearProperty(Const.URL_PREFIX);
-
     SCBEngine scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest()
         .addProducerMeta("sid1", new TestPathSchema())
         .run();
@@ -40,7 +45,7 @@
 
   @Test
   public void testBuildProducerPathsHasPrefix() {
-    System.setProperty(Const.URL_PREFIX, "/root/rest");
+    Deployment.setClassLoaderScopeProperty(Const.URL_PREFIX, "/root/rest");
 
     SCBEngine scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest()
         .addProducerMeta("sid1", new TestPathSchema())
@@ -54,7 +59,5 @@
     spm.producerLocateOperation("/root/rest/dynamicEx/1/", "GET");
 
     scbEngine.destroy();
-
-    System.clearProperty(Const.URL_PREFIX);
   }
 }
diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
index 4b85909..542783a 100644
--- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
+++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
@@ -27,6 +27,7 @@
 import org.apache.servicecomb.core.definition.MicroserviceMeta;
 import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.core.definition.SchemaMeta;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.common.utils.IOUtils;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
@@ -82,7 +83,7 @@
       return;
     }
 
-    String urlPrefix = System.getProperty(Const.URL_PREFIX);
+    String urlPrefix = Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX);
     Map<String, BasePath> basePaths = new LinkedHashMap<>();
     for (SchemaMeta schemaMeta : microserviceMeta.getSchemaMetas().values()) {
       Swagger swagger = schemaMeta.getSwagger();
diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java
index 3cb7c8c..d7694d8 100644
--- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java
+++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java
@@ -30,6 +30,7 @@
 import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.core.definition.SchemaMeta;
 import org.apache.servicecomb.core.executor.ExecutorManager;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.swagger.engine.SwaggerProducer;
@@ -117,7 +118,7 @@
   // call REST service by the full url. e.g. restTemplate.getForObejct("cse://serviceName/root/prefix/health")
   // By default, user's do not need context prefix, e.g. restTemplate.getForObejct("cse://serviceName/health")
   private void registerUrlPrefixToSwagger( Swagger swagger) {
-    String urlPrefix = System.getProperty(Const.URL_PREFIX);
+    String urlPrefix = Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX);
     if (!StringUtils.isEmpty(urlPrefix) && !swagger.getBasePath().startsWith(urlPrefix)
         && DynamicPropertyFactory.getInstance()
         .getBooleanProperty(Const.REGISTER_URL_PREFIX, false).get()) {
diff --git a/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java b/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java
index f26980e..06c075e 100644
--- a/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java
+++ b/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java
@@ -17,11 +17,30 @@
 
 package org.apache.servicecomb.deployment;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 
+import com.google.common.annotations.VisibleForTesting;
+
 public class Deployment {
+  /*
+   * class loader scope property is used when users run java-chassis in an class loader separated environment.
+   *
+   * For examples, deploy two war's to web container, or deploy two bundles in an OSGI container.
+   *
+   * Now java chassis not testing this feature carefully, but we will support users doing so.
+   *
+   * users who using this feature can feed back your problems in issues.
+   *
+   * NOTICEļ¼š this context is better put into module `core`, however now `core` depends on `service-registry`.
+   *
+   * Maybe it's better to refactor project that `service-registry` depends on `core`.
+   */
+  private static final Map<String, String> CLASS_LOADER_SCOPE_CONTEXT = new HashMap<>();
+
   private static List<DeploymentProvider> providerList = SPIServiceUtils.getSortedService(DeploymentProvider.class);
 
   public static SystemBootstrapInfo getSystemBootStrapInfo(String systemKey) {
@@ -32,4 +51,17 @@
     }
     return null;
   }
+
+  public static void setClassLoaderScopeProperty(String key, String value) {
+    CLASS_LOADER_SCOPE_CONTEXT.put(key, value);
+  }
+
+  public static String getClassLoaderScopeProperty(String key) {
+    return CLASS_LOADER_SCOPE_CONTEXT.get(key);
+  }
+
+  @VisibleForTesting
+  public static void clearClassLoaderScopeProperty() {
+    CLASS_LOADER_SCOPE_CONTEXT.clear();
+  }
 }
diff --git a/inspector/src/main/java/org/apache/servicecomb/inspector/internal/InspectorImpl.java b/inspector/src/main/java/org/apache/servicecomb/inspector/internal/InspectorImpl.java
index 1340220..6b94691 100644
--- a/inspector/src/main/java/org/apache/servicecomb/inspector/internal/InspectorImpl.java
+++ b/inspector/src/main/java/org/apache/servicecomb/inspector/internal/InspectorImpl.java
@@ -54,6 +54,7 @@
 import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.common.part.InputStreamPart;
 import org.apache.servicecomb.inspector.internal.model.DynamicPropertyView;
 import org.apache.servicecomb.inspector.internal.model.PriorityPropertyView;
@@ -130,7 +131,7 @@
       return;
     }
 
-    String urlPrefix = System.getProperty(URL_PREFIX);
+    String urlPrefix = Deployment.getClassLoaderScopeProperty(URL_PREFIX);
     if (StringUtils.isEmpty(urlPrefix)) {
       return;
     }
diff --git a/inspector/src/test/java/org/apache/servicecomb/inspector/internal/TestInspectorImpl.java b/inspector/src/test/java/org/apache/servicecomb/inspector/internal/TestInspectorImpl.java
index d460f16..9f8646a 100644
--- a/inspector/src/test/java/org/apache/servicecomb/inspector/internal/TestInspectorImpl.java
+++ b/inspector/src/test/java/org/apache/servicecomb/inspector/internal/TestInspectorImpl.java
@@ -44,6 +44,7 @@
 import org.apache.servicecomb.core.Transport;
 import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
 import org.apache.servicecomb.core.definition.CoreMetaUtils;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace;
 import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
@@ -92,7 +93,7 @@
     if (StringUtils.isNotEmpty(urlPrefix)) {
       Map<String, Transport> transportMap = Deencapsulation.getField(scbEngine.getTransportManager(), "transportMap");
       transportMap.put(RESTFUL, new ServletRestTransport());
-      System.setProperty(URL_PREFIX, urlPrefix);
+      Deployment.setClassLoaderScopeProperty(URL_PREFIX, urlPrefix);
     }
 
     scbEngine.run();
@@ -106,6 +107,7 @@
   public static void teardown() {
     ArchaiusUtils.resetConfig();
     SCBEngine.getInstance().destroy();
+    Deployment.clearClassLoaderScopeProperty();
   }
 
   private Map<String, String> unzip(InputStream is) throws IOException {
@@ -377,6 +379,5 @@
     Assert.assertTrue(schemas.get("schema1").indexOf("/webroot/rest/metrics") > 0);
 
     inspector.getScbEngine().getPriorityPropertyManager().unregisterConfigObject(inspector.getInspectorConfig());
-    System.clearProperty(URL_PREFIX);
   }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java
index 9d2ca05..4cbb918 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java
@@ -25,6 +25,7 @@
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.lang.StringUtils;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.BasePath;
 
@@ -72,7 +73,7 @@
   }
 
   private static String buildPath(String path) {
-    String prefix = System.getProperty(Const.URL_PREFIX);
+    String prefix = Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX);
     if (StringUtils.isNotEmpty(prefix)) {
       if (!path.startsWith(prefix)) {
         path = prefix + path;
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java
index a1778ee..ac4dcb3 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java
@@ -23,6 +23,7 @@
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.servicecomb.config.ConfigUtil;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.BasePath;
 import org.junit.Assert;
@@ -31,6 +32,7 @@
 public class TestConfigurePropertyUtils {
   @Test
   public void testGetPropertiesWithPrefix() {
+    Deployment.clearClassLoaderScopeProperty();
     Configuration configuration = ConfigUtil.createLocalConfig();
 
     String prefix = "service_description.properties";
@@ -44,10 +46,11 @@
     Assert.assertEquals(paths.get(0).getPath(), "/test1/testpath");
     Assert.assertEquals(paths.get(0).getProperty().get("checksession"), false);
 
-    System.setProperty(Const.URL_PREFIX, "/webroot");
+    Deployment.setClassLoaderScopeProperty(Const.URL_PREFIX, "/webroot");
     paths = ConfigurePropertyUtils.getMicroservicePaths(configuration);
     Assert.assertEquals(2, paths.size());
     Assert.assertEquals(paths.get(0).getPath(), "/webroot/test1/testpath");
     Assert.assertEquals(paths.get(0).getProperty().get("checksession"), false);
+    Deployment.clearClassLoaderScopeProperty();
   }
 }
diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java
index f04fa66..0c36950 100644
--- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java
+++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java
@@ -22,6 +22,7 @@
 
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.transport.AbstractTransport;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.swagger.invocation.AsyncResponse;
 import org.apache.servicecomb.transport.rest.client.RestTransportClient;
@@ -58,7 +59,7 @@
 
   @Override
   public boolean init() {
-    String urlPrefix = System.getProperty(Const.URL_PREFIX);
+    String urlPrefix = Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX);
     Map<String, String> queryMap = new HashMap<>();
     if (!StringUtils.isEmpty(urlPrefix)) {
       queryMap.put(Const.URL_PREFIX, urlPrefix);
diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java
index 489eba4..98f5830 100644
--- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java
+++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java
@@ -29,6 +29,7 @@
 import javax.servlet.ServletRegistration.Dynamic;
 
 import org.apache.servicecomb.common.rest.UploadConfig;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
@@ -132,7 +133,7 @@
       return;
     }
 
-    System.setProperty(Const.URL_PREFIX, urlPrefix);
+    Deployment.setClassLoaderScopeProperty(Const.URL_PREFIX, urlPrefix);
     LOGGER.info("UrlPrefix of this instance is \"{}\".", urlPrefix);
   }
 
diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java
index 714f81e..a6a3a4b 100644
--- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java
+++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java
@@ -20,12 +20,14 @@
 import java.io.IOException;
 import java.net.ServerSocket;
 
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.serviceregistry.Features;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.transport.rest.client.RestTransportClient;
 import org.apache.servicecomb.transport.rest.client.RestTransportClientManager;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -37,6 +39,11 @@
 public class TestServletRestTransport {
   ServletRestTransport transport = new ServletRestTransport();
 
+  @After
+  public void tearDown() {
+    Deployment.clearClassLoaderScopeProperty();
+  }
+
   @Test
   public void testInitNotPublish(@Mocked RestTransportClient restTransportClient) {
     new MockUp<RestTransportClientManager>() {
@@ -71,8 +78,6 @@
         result = "1.1.1.1:1234";
       }
     };
-    System.clearProperty(Const.URL_PREFIX);
-
     Assert.assertTrue(transport.init());
     Assert.assertEquals("rest://1.1.1.1:1234", transport.getPublishEndpoint().getEndpoint());
   }
@@ -103,12 +108,10 @@
         result = "1.1.1.1:1234";
       }
     };
-    System.setProperty(Const.URL_PREFIX, "/root");
+    Deployment.setClassLoaderScopeProperty(Const.URL_PREFIX, "/root");
 
     Assert.assertTrue(transport.init());
     Assert.assertEquals("rest://1.1.1.1:1234?urlPrefix=/root", transport.getPublishEndpoint().getEndpoint());
-
-    System.clearProperty(Const.URL_PREFIX);
   }
 
   @Test
diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java
index 2850694..8eb0f26 100644
--- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java
+++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java
@@ -36,6 +36,7 @@
 import javax.servlet.http.HttpServlet;
 
 import org.apache.servicecomb.common.rest.RestConst;
+import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
@@ -174,18 +175,18 @@
 
   @Test
   public void testSaveUrlPrefixNull(@Mocked ServletContext servletContext) {
-    System.clearProperty(Const.URL_PREFIX);
+    Deployment.clearClassLoaderScopeProperty();
 
     ServletUtils.saveUrlPrefix(servletContext);
 
-    Assert.assertNull(System.getProperty(Const.URL_PREFIX));
-    System.clearProperty(Const.URL_PREFIX);
+    Assert.assertNull(Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX));
+    Deployment.clearClassLoaderScopeProperty();
   }
 
   @Test
   public void testSaveUrlPrefixNormal(@Mocked ServletContext servletContext,
       @Mocked ServletRegistration servletRegistration) {
-    System.clearProperty(Const.URL_PREFIX);
+    Deployment.clearClassLoaderScopeProperty();
     new Expectations() {
       {
         servletContext.getContextPath();
@@ -201,8 +202,8 @@
 
     ServletUtils.saveUrlPrefix(servletContext);
 
-    Assert.assertThat(System.getProperty(Const.URL_PREFIX), Matchers.is("/root/rest"));
-    System.clearProperty(Const.URL_PREFIX);
+    Assert.assertThat(Deployment.getClassLoaderScopeProperty(Const.URL_PREFIX), Matchers.is("/root/rest"));
+    Deployment.clearClassLoaderScopeProperty();
   }
 
   @Test