knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kris...@apache.org
Subject [knox] branch master updated: KNOX-2053 - New REST API to create/read/update/delete service definitions (#164)
Date Fri, 25 Oct 2019 13:23:27 GMT
This is an automated email from the ASF dual-hosted git repository.

krisden pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new 9e55444  KNOX-2053 - New REST API to create/read/update/delete service definitions (#164)
9e55444 is described below

commit 9e55444e03b07d6b3f717f4ce09930b1314cfe93
Author: Sandor Molnar <smolnar@apache.org>
AuthorDate: Fri Oct 25 15:23:17 2019 +0200

    KNOX-2053 - New REST API to create/read/update/delete service definitions (#164)
---
 gateway-provider-identity-assertion-common/pom.xml |   4 +
 .../pom.xml                                        |  52 ++---
 .../filter/rewrite/api/UrlRewriteEnvironment.java  |   0
 .../api/UrlRewriteFilterApplyDescriptor.java       |   0
 .../api/UrlRewriteFilterBufferDescriptor.java      |   0
 .../api/UrlRewriteFilterContentDescriptor.java     |   0
 .../rewrite/api/UrlRewriteFilterDescriptor.java    |   0
 .../api/UrlRewriteFilterDetectDescriptor.java      |   0
 .../api/UrlRewriteFilterGroupDescriptor.java       |   0
 .../api/UrlRewriteFilterPathDescriptor.java        |   0
 .../api/UrlRewriteFilterScopeDescriptor.java       |   0
 .../rewrite/api/UrlRewriteFlowDescriptor.java      |   0
 .../rewrite/api/UrlRewriteFunctionDescriptor.java  |   0
 .../api/UrlRewriteFunctionDescriptorFactory.java   |   0
 .../rewrite/api/UrlRewriteRuleDescriptor.java      |   0
 .../rewrite/api/UrlRewriteRulesDescriptor.java     |   0
 .../rewrite/api/UrlRewriteStepDescriptor.java      |   0
 .../api/UrlRewriteStepDescriptorFactory.java       |   0
 .../filter/rewrite/api/UrlRewriteStepFlow.java     |   0
 .../gateway/filter/rewrite/api/UrlRewriter.java    |   0
 .../filter/rewrite/i18n/UrlRewriteMessages.java    |   0
 .../impl/UrlRewriteFilterApplyDescriptorImpl.java  |   0
 .../impl/UrlRewriteFilterBufferDescriptorImpl.java |   0
 .../UrlRewriteFilterContentDescriptorImpl.java     |   0
 .../impl/UrlRewriteFilterDescriptorImpl.java       |   0
 .../impl/UrlRewriteFilterDetectDescriptorImpl.java |   0
 .../impl/UrlRewriteFilterGroupDescriptorBase.java  |   0
 .../impl/UrlRewriteFilterScopeDescriptorImpl.java  |   0
 .../UrlRewriteFilterSelectorDescriptorBase.java    |   0
 .../rewrite/impl/UrlRewriteRuleDescriptorImpl.java |   0
 .../impl/UrlRewriteRulesDescriptorImpl.java        |   0
 .../rewrite/impl/xml/XmlRewriteRulesDigester.java  |   4 +-
 .../rewrite/impl/xml/XmlRewriteRulesTags.java      |   0
 .../impl/xml/XmlUrlRewriteRulesExporter.java       |  11 +-
 .../impl/xml/XmlUrlRewriteRulesImporter.java       |   0
 .../rewrite/spi/UrlRewriteFlowDescriptorBase.java  |   0
 .../rewrite/spi/UrlRewriteRulesExporter.java       |   2 +-
 .../rewrite/spi/UrlRewriteRulesImporter.java       |   0
 .../rewrite/spi/UrlRewriteStepDescriptorBase.java  |   0
 .../filter/rewrite/spi/UrlRewriteStepStatus.java   |   0
 .../pom.xml                                        |   4 +
 .../pom.xml                                        |   4 +
 .../pom.xml                                        |   4 +
 gateway-provider-rewrite-step-encrypt-uri/pom.xml  |   4 +
 gateway-provider-rewrite-step-secure-query/pom.xml |   4 +
 gateway-provider-rewrite/pom.xml                   |   4 +
 gateway-server/pom.xml                             |  13 +-
 .../org/apache/knox/gateway/GatewayMessages.java   |   3 +
 .../org/apache/knox/gateway/GatewayServer.java     |   4 +
 .../knox/gateway/deploy/DeploymentFactory.java     |   3 +-
 .../impl/ApplicationDeploymentContributor.java     |   4 +-
 .../impl/DefaultServiceDefinitionRegistry.java     | 224 +++++++++++++++++++--
 .../topology/impl/DefaultTopologyService.java      |  18 +-
 .../gateway/util/ServiceDefinitionsLoader.java     |  61 +++---
 .../gateway/util/ServiceDefinitionsLoaderTest.java |  30 ++-
 gateway-service-admin/pom.xml                      |  14 +-
 .../ServiceDefinitionCollectionMarshaller.java     |  70 +++++++
 .../admin/ServiceDefinitionUnmarshaller.java       |  64 ++++++
 .../service/admin/ServiceDefinitionsResource.java  | 175 ++++++++++++++++
 .../service/definition/ServiceDefinition.java      |   7 +
 .../ServiceDefinitionChangeListener.java           |   7 +-
 .../definition/ServiceDefinitionComparator.java    |  44 ++++
 .../ServiceDefinitionComparatorTest.java           |  56 ++++++
 gateway-spi/pom.xml                                |  16 +-
 .../service/definition/ServiceDefinitionPair.java  |  61 ++++++
 .../ServiceDefinitionPairComparator.java           |  33 +--
 .../UrlRewriteRulesDescriptorAdapter.java          |  67 ++++++
 .../registry/ServiceDefinitionRegistry.java        |  14 ++
 ...ava => ServiceDefinitionRegistryException.java} |  10 +-
 .../gateway/services/topology/TopologyService.java |   3 +-
 gateway-test/pom.xml                               |   5 +
 .../gateway/SimpleDescriptorHandlerFuncTest.java   |   7 +
 .../apache/knox/gateway/util/CollectionUtils.java  |  46 +++--
 .../org/apache/knox/gateway/util/XmlUtils.java     |   6 +-
 .../knox/gateway/util/CollectionUtilsTest.java     |  61 ++++++
 pom.xml                                            |   6 +
 76 files changed, 1064 insertions(+), 165 deletions(-)

diff --git a/gateway-provider-identity-assertion-common/pom.xml b/gateway-provider-identity-assertion-common/pom.xml
index cc53a2b..365d388 100644
--- a/gateway-provider-identity-assertion-common/pom.xml
+++ b/gateway-provider-identity-assertion-common/pom.xml
@@ -43,6 +43,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-common</artifactId>
         </dependency>
         <dependency>
diff --git a/gateway-provider-rewrite-step-secure-query/pom.xml b/gateway-provider-rewrite-common/pom.xml
similarity index 52%
copy from gateway-provider-rewrite-step-secure-query/pom.xml
copy to gateway-provider-rewrite-common/pom.xml
index 2946732..1a9020b 100644
--- a/gateway-provider-rewrite-step-secure-query/pom.xml
+++ b/gateway-provider-rewrite-common/pom.xml
@@ -15,70 +15,44 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <artifactId>gateway</artifactId>
         <groupId>org.apache.knox</groupId>
+        <artifactId>gateway</artifactId>
         <version>1.4.0-SNAPSHOT</version>
     </parent>
 
-    <artifactId>gateway-provider-rewrite-step-secure-query</artifactId>
-    <name>gateway-provider-rewrite-step-secure-query</name>
-    <description>An extension of the gateway that supports securing query parameters.</description>
+    <artifactId>gateway-provider-rewrite-common</artifactId>
+    <name>gateway-provider-rewrite-common</name>
+    <description>Common interfaces/implementations for the URL-rewrite framework</description>
 
     <dependencies>
         <dependency>
             <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-util-common</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-util-urltemplate</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-i18n</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-i18n-logging-log4j</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-spi</artifactId>
+            <artifactId>gateway-util-common</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-provider-rewrite</artifactId>
+            <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
 
         <dependency>
-            <groupId>commons-codec</groupId>
-            <artifactId>commons-codec</artifactId>
+            <groupId>com.sun.activation</groupId>
+            <artifactId>javax.activation</artifactId>
         </dependency>
-
         <dependency>
-            <groupId>org.jboss.shrinkwrap</groupId>
-            <artifactId>shrinkwrap-api</artifactId>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
         </dependency>
-
-        <!-- ********** ********** ********** ********** ********** ********** -->
-        <!-- ********** Test Dependencies                           ********** -->
-        <!-- ********** ********** ********** ********** ********** ********** -->
-
         <dependency>
-            <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-test-utils</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-server</artifactId>
-            <scope>test</scope>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-digester3</artifactId>
         </dependency>
     </dependencies>
 </project>
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteEnvironment.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteEnvironment.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteEnvironment.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteEnvironment.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterApplyDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterApplyDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterApplyDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterApplyDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterBufferDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterBufferDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterBufferDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterBufferDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterContentDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterContentDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterContentDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterContentDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDetectDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDetectDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDetectDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterDetectDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterGroupDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterGroupDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterGroupDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterGroupDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java
similarity index 100%
copy from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java
copy to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterScopeDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterScopeDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterScopeDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterScopeDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFlowDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFlowDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFlowDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFlowDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptorFactory.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptorFactory.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptorFactory.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFunctionDescriptorFactory.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRuleDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRuleDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRuleDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRuleDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRulesDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRulesDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRulesDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteRulesDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptor.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptor.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptor.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptor.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptorFactory.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptorFactory.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptorFactory.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepDescriptorFactory.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepFlow.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepFlow.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepFlow.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteStepFlow.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriter.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriter.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriter.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriter.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/i18n/UrlRewriteMessages.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/i18n/UrlRewriteMessages.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/i18n/UrlRewriteMessages.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/i18n/UrlRewriteMessages.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java
similarity index 100%
copy from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java
copy to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterBufferDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterBufferDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterBufferDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterBufferDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterContentDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterContentDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterContentDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterContentDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDetectDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDetectDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDetectDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterDetectDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterGroupDescriptorBase.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterGroupDescriptorBase.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterGroupDescriptorBase.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterGroupDescriptorBase.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterScopeDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterScopeDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterScopeDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterScopeDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterSelectorDescriptorBase.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterSelectorDescriptorBase.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterSelectorDescriptorBase.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterSelectorDescriptorBase.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRuleDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRuleDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRuleDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRuleDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRulesDescriptorImpl.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRulesDescriptorImpl.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRulesDescriptorImpl.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRulesDescriptorImpl.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
similarity index 98%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
index e6cd4cc..af6f4c7 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
+++ b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
@@ -29,12 +29,12 @@ import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFlowDescriptor;
 import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
 import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRuleDescriptor;
 import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
-import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
 import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptorFactory;
 import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterApplyDescriptorImpl;
 import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterBufferDescriptorImpl;
 import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterDetectDescriptorImpl;
 import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterScopeDescriptorImpl;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteRulesDescriptorImpl;
 import org.xml.sax.Attributes;
 
 public class XmlRewriteRulesDigester extends AbstractRulesModule implements XmlRewriteRulesTags {
@@ -86,7 +86,7 @@ public class XmlRewriteRulesDigester extends AbstractRulesModule implements XmlR
   private static class RulesFactory extends FactoryRule {
     @Override
     public Object create( String namespace, String name, Attributes attributes ) {
-      return UrlRewriteRulesDescriptorFactory.create();
+      return new UrlRewriteRulesDescriptorImpl();
     }
   }
 
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
similarity index 95%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
index d4c8d80..63c85a8 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
+++ b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
@@ -59,7 +59,11 @@ public class XmlUrlRewriteRulesExporter implements UrlRewriteRulesExporter, XmlR
   }
 
   @Override
-  public void store( UrlRewriteRulesDescriptor descriptor, Writer writer ) throws IOException {
+  public Object store(UrlRewriteRulesDescriptor descriptor, Writer writer) throws IOException {
+    return store(descriptor, writer, false);
+  }
+
+  public Object store( UrlRewriteRulesDescriptor descriptor, Writer writer, boolean omitXmlHeader ) throws IOException {
     try {
       Document document = XmlUtils.createDocument();
 
@@ -89,12 +93,15 @@ public class XmlUrlRewriteRulesExporter implements UrlRewriteRulesExporter, XmlR
         }
       }
 
-      XmlUtils.writeXml( document, writer );
+      XmlUtils.writeXml( document, writer, omitXmlHeader);
+
+      return document;
 
     } catch( ParserConfigurationException | TransformerException e ) {
       throw new IOException( e );
     } catch( InvocationTargetException | IllegalAccessException | IntrospectionException | NoSuchMethodException e ) {
       LOG.failedToWriteRulesDescriptor( e );
+      return null;
     }
   }
 
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
similarity index 92%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
index a54a26c..61449de 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
+++ b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
@@ -26,6 +26,6 @@ public interface UrlRewriteRulesExporter {
 
   String getFormat();
 
-  void store( UrlRewriteRulesDescriptor rules, Writer writer ) throws IOException;
+  Object store( UrlRewriteRulesDescriptor rules, Writer writer ) throws IOException;
 
 }
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java b/gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
similarity index 100%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
rename to gateway-provider-rewrite-common/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
diff --git a/gateway-provider-rewrite-func-hostmap-static/pom.xml b/gateway-provider-rewrite-func-hostmap-static/pom.xml
index 3998144..0b23fa3 100644
--- a/gateway-provider-rewrite-func-hostmap-static/pom.xml
+++ b/gateway-provider-rewrite-func-hostmap-static/pom.xml
@@ -44,6 +44,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
 
diff --git a/gateway-provider-rewrite-func-inbound-query-param/pom.xml b/gateway-provider-rewrite-func-inbound-query-param/pom.xml
index bdab6dd..7f981e3 100644
--- a/gateway-provider-rewrite-func-inbound-query-param/pom.xml
+++ b/gateway-provider-rewrite-func-inbound-query-param/pom.xml
@@ -41,6 +41,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
 
diff --git a/gateway-provider-rewrite-func-service-registry/pom.xml b/gateway-provider-rewrite-func-service-registry/pom.xml
index 51e64d2..1decce4 100644
--- a/gateway-provider-rewrite-func-service-registry/pom.xml
+++ b/gateway-provider-rewrite-func-service-registry/pom.xml
@@ -48,6 +48,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-provider-ha</artifactId>
         </dependency>
         <dependency>
diff --git a/gateway-provider-rewrite-step-encrypt-uri/pom.xml b/gateway-provider-rewrite-step-encrypt-uri/pom.xml
index 912c368..938803b 100644
--- a/gateway-provider-rewrite-step-encrypt-uri/pom.xml
+++ b/gateway-provider-rewrite-step-encrypt-uri/pom.xml
@@ -54,6 +54,10 @@
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-provider-rewrite</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>commons-codec</groupId>
diff --git a/gateway-provider-rewrite-step-secure-query/pom.xml b/gateway-provider-rewrite-step-secure-query/pom.xml
index 2946732..702e4e1 100644
--- a/gateway-provider-rewrite-step-secure-query/pom.xml
+++ b/gateway-provider-rewrite-step-secure-query/pom.xml
@@ -54,6 +54,10 @@
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-provider-rewrite</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>commons-codec</groupId>
diff --git a/gateway-provider-rewrite/pom.xml b/gateway-provider-rewrite/pom.xml
index ff6bacf..f450cef 100644
--- a/gateway-provider-rewrite/pom.xml
+++ b/gateway-provider-rewrite/pom.xml
@@ -35,6 +35,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
         <dependency>
diff --git a/gateway-server/pom.xml b/gateway-server/pom.xml
index c2a6a65..91b8287 100644
--- a/gateway-server/pom.xml
+++ b/gateway-server/pom.xml
@@ -61,7 +61,10 @@
             <groupId>org.glassfish</groupId>
             <artifactId>javax.json</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-i18n</artifactId>
@@ -80,6 +83,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-service-definitions</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-spi</artifactId>
         </dependency>
         <dependency>
@@ -224,6 +231,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-server-xforwarded-filter</artifactId>
         </dependency>
         <dependency>
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
index 0656842..430ecc2 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
@@ -667,4 +667,7 @@ public interface GatewayMessages {
 
   @Message(level = MessageLevel.INFO, text = "Stopping service: {0}")
   void stoppingService(String serviceTypeName);
+
+  @Message(level = MessageLevel.INFO, text = "Redeploying topology {0} due to service definition change {1} / {2} / {3}")
+  void redeployingTopologyOnServiceDefinitionChange(String topologyName, String serviceName, String role, String version);
 }
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 6e8777e..db699fc 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -38,6 +38,7 @@ import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistry;
 import org.apache.knox.gateway.services.registry.ServiceRegistry;
 import org.apache.knox.gateway.services.security.AliasServiceException;
 import org.apache.knox.gateway.services.security.SSLService;
@@ -629,6 +630,9 @@ public class GatewayServer {
       }
     }
 
+    final ServiceDefinitionRegistry serviceDefinitionRegistry = services.getService(ServiceType.SERVICE_DEFINITION_REGISTRY);
+    serviceDefinitionRegistry.addServiceDefinitionChangeListener(monitor);
+
     final Collection<Topology> topologies = monitor.getTopologies();
     final Map<String, Integer> topologyPortMap = config.getGatewayPortMappings();
 
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
index 43188dc..844ea85 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
@@ -703,8 +703,7 @@ public abstract class DeploymentFactory {
     String stacks = config.getGatewayServicesDir();
     log.usingServicesDirectory(stacks);
     File stacksDir = new File(stacks);
-    Set<ServiceDeploymentContributor> deploymentContributors = ServiceDefinitionsLoader
-        .loadServiceDefinitions(stacksDir);
+    Set<ServiceDeploymentContributor> deploymentContributors = ServiceDefinitionsLoader.loadServiceDefinitionDeploymentContributors(stacksDir);
     addServiceDeploymentContributors(deploymentContributors.iterator());
   }
 
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
index 8ea6787..eac88d8 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
@@ -58,8 +58,8 @@ import java.util.Map;
 public class ApplicationDeploymentContributor extends ServiceDeploymentContributorBase {
   private static final JAXBContext jaxbContext = getJAXBContext();
 
-  private static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
-  private static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
+  public static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
+  public static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
   private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
   private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
   private static final String COOKIE_SCOPING_FILTER_NAME = "CookieScopeServletFilter";
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
index e2e43fc..4c93fd8 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
@@ -17,46 +17,91 @@
  */
 package org.apache.knox.gateway.services.registry.impl;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.nio.file.Files.newBufferedWriter;
+import static org.apache.knox.gateway.deploy.impl.ApplicationDeploymentContributor.REWRITE_RULES_FILE_NAME;
+import static org.apache.knox.gateway.deploy.impl.ApplicationDeploymentContributor.SERVICE_DEFINITION_FILE_NAME;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
 import org.apache.knox.gateway.GatewayMessages;
 import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.impl.xml.XmlUrlRewriteRulesExporter;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.service.definition.Route;
 import org.apache.knox.gateway.service.definition.ServiceDefinition;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionChangeListener;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
 import org.apache.knox.gateway.services.Service;
 import org.apache.knox.gateway.services.ServiceLifecycleException;
 import org.apache.knox.gateway.services.registry.ServiceDefEntry;
 import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistry;
+import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistryException;
 import org.apache.knox.gateway.util.ServiceDefinitionsLoader;
 import org.apache.knox.gateway.util.urltemplate.Matcher;
 import org.apache.knox.gateway.util.urltemplate.Parser;
 import org.apache.knox.gateway.util.urltemplate.Template;
 
-import java.io.File;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 public class DefaultServiceDefinitionRegistry implements ServiceDefinitionRegistry, Service {
 
-  private static GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
+  private static GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
+
+  private final ReadWriteLock lock = new ReentrantReadWriteLock();
+  private final Lock writeLock = lock.writeLock();
+  private final Lock readLock = lock.readLock();
+  private final Collection<ServiceDefinitionChangeListener> listeners = new HashSet<>();
+  private final XmlUrlRewriteRulesExporter xmlRewriteRulesExporter = new XmlUrlRewriteRulesExporter();
 
+  private GatewayConfig gatewayConfig;
   private Matcher<ServiceDefEntry> entries = new Matcher<>();
+  private Set<ServiceDefinitionPair> serviceDefinitions;
+  private JAXBContext jaxbContext;
 
   @Override
-  public void init(GatewayConfig config, Map<String, String> options) throws
-      ServiceLifecycleException {
-    String stacks = config.getGatewayServicesDir();
-    File stacksDir = new File(stacks);
-    Set<ServiceDefinition> serviceDefinitions = ServiceDefinitionsLoader.getServiceDefinitions(stacksDir);
+  public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
+    this.gatewayConfig = config;
+    writeLock.lock();
+    try {
+      populateServiceDefinitions();
+    } finally {
+      writeLock.unlock();
+    }
+  }
+
+  private void populateServiceDefinitions() {
+    serviceDefinitions = ServiceDefinitionsLoader.loadServiceDefinitions(new File(gatewayConfig.getGatewayServicesDir()));
 
-    for (ServiceDefinition serviceDefinition : serviceDefinitions) {
+    for (ServiceDefinition serviceDefinition : getServices()) {
       List<Route> routes = serviceDefinition.getRoutes();
       for (Route route : routes) {
         try {
           Template template = Parser.parseTemplate(route.getPath());
           addServiceDefEntry(template, serviceDefinition);
-        } catch ( URISyntaxException e ) {
+        } catch (URISyntaxException e) {
           LOG.failedToParsePath(route.getPath(), e);
         }
       }
@@ -82,15 +127,152 @@ public class DefaultServiceDefinitionRegistry implements ServiceDefinitionRegist
 
   @Override
   public ServiceDefEntry getMatchingService(String urlPattern) {
-    Matcher<ServiceDefEntry>.Match match = null;
+    readLock.lock();
+    try {
+      Matcher<ServiceDefEntry>.Match match = null;
+      try {
+        match = entries.match(Parser.parseLiteral(urlPattern));
+      } catch (URISyntaxException e) {
+        LOG.failedToParsePath(urlPattern, e);
+      }
+      if (match != null) {
+        return match.getValue();
+      }
+      return null;
+    } finally {
+      readLock.unlock();
+    }
+  }
+
+  @Override
+  public Set<ServiceDefinitionPair> getServiceDefinitions() {
+    readLock.lock();
     try {
-      match = entries.match(Parser.parseLiteral(urlPattern));
-    } catch ( URISyntaxException e ) {
-      LOG.failedToParsePath(urlPattern, e);
+      return serviceDefinitions;
+    } finally {
+      readLock.unlock();
+    }
+  }
+
+  @Override
+  public void saveServiceDefinition(ServiceDefinitionPair serviceDefinition) throws ServiceDefinitionRegistryException {
+    saveOrUpdateServiceDefinition(serviceDefinition, false);
+  }
+
+  @Override
+  public void saveOrUpdateServiceDefinition(ServiceDefinitionPair serviceDefinition) throws ServiceDefinitionRegistryException {
+    saveOrUpdateServiceDefinition(serviceDefinition, true);
+  }
+
+  public void saveOrUpdateServiceDefinition(ServiceDefinitionPair serviceDefinition, boolean allowUpdate) throws ServiceDefinitionRegistryException {
+    final ServiceDefinition service = serviceDefinition.getService();
+    final Optional<ServiceDefinition> persistedServiceDefinition = findServiceDefinition(service.getName(), service.getRole(), service.getVersion());
+    if (persistedServiceDefinition.isPresent() && !allowUpdate) {
+      throw new ServiceDefinitionRegistryException("The requested service definition (" + serviceDefinition.toString() + ") already exists!");
+    } else {
+      writeLock.lock();
+      try {
+        final Path serviceDefinitionFolderPath = createServiceDefinitionFolders(service.getName(), service.getVersion());
+        writeOutServiceDefinitionFile(service, serviceDefinitionFolderPath);
+        if (serviceDefinition.getRewriteRules() != null) {
+          writeOutRewriteRules(serviceDefinition.getRewriteRules(), serviceDefinitionFolderPath);
+        }
+        populateServiceDefinitions();
+      } catch (JAXBException | IOException e) {
+        throw new ServiceDefinitionRegistryException("Error while persisting service definition " + serviceDefinition.toString(), e);
+      } finally {
+        writeLock.unlock();
+      }
+      notifyListeners(service.getName(), service.getRole(), service.getVersion());
+    }
+  }
+
+  private Path createServiceDefinitionFolders(String name, String version) throws IOException {
+    final Path serviceDefinitionPath = Paths.get(gatewayConfig.getGatewayServicesDir(), name, version);
+    return Files.createDirectories(serviceDefinitionPath);
+  }
+
+  private void writeOutServiceDefinitionFile(ServiceDefinition serviceDefinition, Path serviceDefinitionFolderPath) throws JAXBException, IOException {
+    final Marshaller marshaller = getJaxbContext().createMarshaller();
+    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+    try (BufferedWriter serviceDefinitionXmlFileWriter = newBufferedWriter(Paths.get(serviceDefinitionFolderPath.toAbsolutePath().toString(), SERVICE_DEFINITION_FILE_NAME),
+        UTF_8);) {
+      marshaller.marshal(serviceDefinition, serviceDefinitionXmlFileWriter);
+    }
+  }
+
+  private void writeOutRewriteRules(UrlRewriteRulesDescriptor rewriteRules, Path serviceDefinitionFolderPath) throws IOException {
+    try (BufferedWriter rewriteRuleXmlFileWriter = newBufferedWriter(Paths.get(serviceDefinitionFolderPath.toAbsolutePath().toString(), REWRITE_RULES_FILE_NAME), UTF_8);) {
+      xmlRewriteRulesExporter.store(rewriteRules, rewriteRuleXmlFileWriter, true);
+    }
+  }
+
+  private JAXBContext getJaxbContext() throws JAXBException {
+    if (jaxbContext == null) {
+      jaxbContext = JAXBContext.newInstance(ServiceDefinition.class);
+    }
+    return jaxbContext;
+  }
+
+  @Override
+  public void deleteServiceDefinition(String name, String role, String version) throws ServiceDefinitionRegistryException {
+    final Optional<ServiceDefinition> serviceDefinition = findServiceDefinition(name, role, version);
+    if (serviceDefinition.isPresent()) {
+      writeLock.lock();
+      try {
+        removeServiceDefinitionFolders(name, version);
+        populateServiceDefinitions();
+      } catch (IOException e) {
+        throw new ServiceDefinitionRegistryException("Error while deleting service definition " + serviceDefinition.toString(), e);
+      } finally {
+        writeLock.unlock();
+      }
+      notifyListeners(name, role, version);
+    } else {
+      throw new ServiceDefinitionRegistryException("There is no service definition with the given attributes: " + name + "," + role + "," + version);
     }
-    if (match != null) {
-      return match.getValue();
+  }
+
+  private Set<ServiceDefinition> getServices() {
+    return serviceDefinitions.stream().map(serviceDefinitionPair -> serviceDefinitionPair.getService()).collect(Collectors.toSet());
+  }
+
+  private Optional<ServiceDefinition> findServiceDefinition(String name, String role, String version) {
+    return getServices().stream().filter(sd -> sd.getName().equalsIgnoreCase(name) && sd.getRole().equalsIgnoreCase(role) && sd.getVersion().equalsIgnoreCase(version)).findFirst();
+  }
+
+  private void removeServiceDefinitionFolders(String name, String version) throws IOException {
+    // removing the given version folder and its content
+    final Path serviceDefinitionPath = Paths.get(gatewayConfig.getGatewayServicesDir(), name, version);
+    Files.walkFileTree(serviceDefinitionPath, new SimpleFileVisitor<Path>() {
+      @Override
+      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+        Files.delete(file);
+        return FileVisitResult.CONTINUE;
+      }
+
+      @Override
+      public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+        Files.delete(dir);
+        return FileVisitResult.CONTINUE;
+      }
+    });
+
+    // if there was no more versions for the given service the service folder can be
+    // removed too
+    final Path serviceFolderPath = Paths.get(gatewayConfig.getGatewayServicesDir(), name).toAbsolutePath();
+    final File serviceFolder = serviceFolderPath.toFile();
+    if (serviceFolder.isDirectory() && serviceFolder.listFiles().length == 0) {
+      Files.delete(serviceFolderPath);
     }
-    return null;
+  }
+
+  @Override
+  public void addServiceDefinitionChangeListener(ServiceDefinitionChangeListener listener) {
+    listeners.add(listener);
+  }
+
+  private void notifyListeners(String name, String role, String version) {
+    listeners.forEach(listener -> listener.onServiceDefinitionChange(name, role, version));
   }
 }
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
index e39125c..274f693 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
@@ -36,17 +36,20 @@ import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.service.definition.ServiceDefinition;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionChangeListener;
 import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.ServiceLifecycleException;
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.topology.TopologyService;
 import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
+import org.apache.knox.gateway.topology.Service;
 import org.apache.knox.gateway.topology.Topology;
 import org.apache.knox.gateway.topology.TopologyEvent;
 import org.apache.knox.gateway.topology.TopologyListener;
 import org.apache.knox.gateway.topology.TopologyMonitor;
 import org.apache.knox.gateway.topology.TopologyProvider;
+import org.apache.knox.gateway.topology.Version;
 import org.apache.knox.gateway.topology.builder.TopologyBuilder;
 import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
@@ -86,7 +89,7 @@ import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
 
 public class DefaultTopologyService
     extends FileAlterationListenerAdaptor
-    implements TopologyService, TopologyMonitor, TopologyProvider, FileFilter, FileAlterationListener {
+    implements TopologyService, TopologyMonitor, TopologyProvider, FileFilter, FileAlterationListener, ServiceDefinitionChangeListener {
 
   private static final JAXBContext jaxbContext = getJAXBContext();
 
@@ -531,6 +534,19 @@ public class DefaultTopologyService
   }
 
   @Override
+  public void onServiceDefinitionChange(String name, String role, String version) {
+    getTopologies().stream().filter(topology -> topology.getServices().stream().anyMatch(service -> isRelevantService(service, role, name, version))).forEach(topology -> {
+      log.redeployingTopologyOnServiceDefinitionChange(topology.getName(), name, role, version);
+      redeployTopology(topology);
+    });
+  }
+
+  private boolean isRelevantService(Service service, String role, String name, String version) {
+    return service.getRole().equalsIgnoreCase(role)
+        && (service.getName() == null || service.getName().equalsIgnoreCase(name) && (service.getVersion() == null || service.getVersion().equals(new Version(version))));
+  }
+
+  @Override
   public void startMonitor() throws Exception {
     // Start the local configuration monitors
     for (FileAlterationMonitor monitor : monitors) {
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceDefinitionsLoader.java b/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceDefinitionsLoader.java
index 9944168..36492c6 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceDefinitionsLoader.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceDefinitionsLoader.java
@@ -27,6 +27,9 @@ import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
 import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.service.definition.ServiceDefinition;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionComparator;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPairComparator;
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
@@ -42,6 +45,7 @@ import java.nio.file.Files;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.TreeSet;
 
 public class ServiceDefinitionsLoader {
   private static final JAXBContext jaxbContext = getJAXBContext();
@@ -68,42 +72,43 @@ public class ServiceDefinitionsLoader {
     }
   }
 
-  public static Set<ServiceDeploymentContributor> loadServiceDefinitions(File servicesDir) {
-    Set<ServiceDeploymentContributor> contributors = new HashSet<>();
-    if ( servicesDir.exists() && servicesDir.isDirectory() ) {
-      Unmarshaller unmarshaller = createUnmarshaller();
-
-      for ( File file : getFileList(servicesDir) ) {
-        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
-          ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(inputStream);
-          //look for rewrite rules as a sibling (for now)
-          UrlRewriteRulesDescriptor rewriteRulesDescriptor = loadRewriteRules(file.getParentFile());
-          contributors.add(new ServiceDefinitionDeploymentContributor(definition, rewriteRulesDescriptor));
-          log.addedServiceDefinition(definition.getName(), definition.getRole(), definition.getVersion());
+  public static Set<ServiceDeploymentContributor> loadServiceDefinitionDeploymentContributors(File servicesDir) {
+    final Set<ServiceDeploymentContributor> contributors = new HashSet<>();
+    loadServiceDefinitions(servicesDir).forEach(
+        serviceDefinitionPair -> contributors.add(new ServiceDefinitionDeploymentContributor(serviceDefinitionPair.getService(), serviceDefinitionPair.getRewriteRules())));
+    return contributors;
+  }
+
+  public static Set<ServiceDefinitionPair> loadServiceDefinitions(File servicesDir) {
+    final Set<ServiceDefinitionPair> serviceDefinitions = new TreeSet<>(new ServiceDefinitionPairComparator());
+    if (servicesDir.exists() && servicesDir.isDirectory()) {
+      final Unmarshaller unmarshaller = createUnmarshaller();
+      getFileList(servicesDir).forEach(serviceFile -> {
+        try {
+          serviceDefinitions.add(loadServiceDefinition(unmarshaller, serviceFile));
         } catch (FileNotFoundException e) {
-          log.failedToFindServiceDefinitionFile(file.getAbsolutePath(), e);
+          log.failedToFindServiceDefinitionFile(serviceFile.getAbsolutePath(), e);
         } catch (IOException | JAXBException e) {
-          log.failedToLoadServiceDefinition(file.getAbsolutePath(), e);
+          log.failedToLoadServiceDefinition(serviceFile.getAbsolutePath(), e);
         }
-      }
+      });
     }
-    return contributors;
-  }
 
-  public static Set<ServiceDefinition> getServiceDefinitions(File servicesDir) {
-    Set<ServiceDefinition> definitions = new HashSet<>();
-    Unmarshaller unmarshaller = createUnmarshaller();
-    try {
-      for (File f : getFileList(servicesDir)){
-        ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(f);
-        definitions.add( definition );
-      }
+    return serviceDefinitions;
+  }
 
-    } catch (JAXBException e) {
-      log.failedToLoadServiceDefinition(SERVICE_FILE_NAME, e);
+  private static ServiceDefinitionPair loadServiceDefinition(Unmarshaller unmarshaller, File serviceFile) throws IOException, JAXBException {
+    try (InputStream inputStream = Files.newInputStream(serviceFile.toPath())) {
+      final ServiceDefinition service = (ServiceDefinition) unmarshaller.unmarshal(serviceFile);
+      final UrlRewriteRulesDescriptor rewriteRules = loadRewriteRules(serviceFile.getParentFile());
+      return new ServiceDefinitionPair(service, rewriteRules);
     }
+  }
 
-    return definitions;
+  public static Set<ServiceDefinition> getServiceDefinitions(File servicesDir) {
+    final Set<ServiceDefinition> services = new TreeSet<>(new ServiceDefinitionComparator());
+    loadServiceDefinitions(servicesDir).forEach(serviceDefinitionPair -> services.add(serviceDefinitionPair.getService()));
+    return services;
   }
 
   private static Collection<File> getFileList(File servicesDir) {
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/util/ServiceDefinitionsLoaderTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/util/ServiceDefinitionsLoaderTest.java
index 59eec19..726383f 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/util/ServiceDefinitionsLoaderTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/util/ServiceDefinitionsLoaderTest.java
@@ -18,35 +18,43 @@
 package org.apache.knox.gateway.util;
 
 import org.apache.knox.gateway.deploy.ServiceDeploymentContributor;
+import org.apache.knox.gateway.service.definition.ServiceDefinition;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionComparator;
 import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.File;
 import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
 public class ServiceDefinitionsLoaderTest {
 
   @Test
   public void testServiceDefinitionLoading() {
+    final List<String> barVersions = Arrays.asList("1.0.0", "2.0.0");
     URL url = ClassLoader.getSystemResource("services");
-    Set<ServiceDeploymentContributor> contributors = ServiceDefinitionsLoader.loadServiceDefinitions(new File(url.getFile()));
-    assertNotNull(contributors);
-    assertEquals(2, contributors.size());
+    Set<ServiceDeploymentContributor> contributors = ServiceDefinitionsLoader.loadServiceDefinitionDeploymentContributors(new File(url.getFile()));
+    Assert.assertNotNull(contributors);
+    Assert.assertEquals(2, contributors.size());
     for (ServiceDeploymentContributor contributor : contributors) {
       if (contributor.getName().equals("foo")) {
         Assert.assertEquals("1.0.0", contributor.getVersion().toString());
-        assertEquals("FOO", contributor.getRole());
+        Assert.assertEquals("FOO", contributor.getRole());
       } else if (contributor.getName().equals("bar")) {
-        Assert.assertEquals("2.0.0", contributor.getVersion().toString());
-        assertEquals("BAR", contributor.getRole());
+        Assert.assertTrue(barVersions.contains(contributor.getVersion().toString()));
+        Assert.assertEquals("BAR", contributor.getRole());
       } else {
-        fail("the loaded services don't match the test input");
+        Assert.fail("the loaded services don't match the test input");
       }
     }
   }
+
+  @Test
+  public void shouldReturnLoadedServiceDefinitionsOrdered() throws Exception {
+    final URL url = ClassLoader.getSystemResource("services");
+    final Set<ServiceDefinition> serviceDefinitions = ServiceDefinitionsLoader.getServiceDefinitions(new File(url.getFile()));
+    Assert.assertTrue(CollectionUtils.isSorted(serviceDefinitions, new ServiceDefinitionComparator()));
+  }
 }
diff --git a/gateway-service-admin/pom.xml b/gateway-service-admin/pom.xml
index f746429..9476e1c 100644
--- a/gateway-service-admin/pom.xml
+++ b/gateway-service-admin/pom.xml
@@ -43,9 +43,16 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-provider-jersey</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-service-definitions</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.eclipse.persistence</groupId>
             <artifactId>eclipselink</artifactId>
@@ -58,7 +65,10 @@
             <groupId>org.glassfish</groupId>
             <artifactId>javax.json</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.glassfish.hk2.external</groupId>
+            <artifactId>javax.inject</artifactId>
+        </dependency>
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
diff --git a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
new file mode 100644
index 0000000..95f4307
--- /dev/null
+++ b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
@@ -0,0 +1,70 @@
+/*
+ * 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.knox.gateway.service.admin;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.apache.knox.gateway.service.admin.ServiceDefinitionsResource.ServiceDefinitionsWrapper;
+
+@Provider
+@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+public class ServiceDefinitionCollectionMarshaller implements MessageBodyWriter<ServiceDefinitionsResource.ServiceDefinitionsWrapper> {
+
+  private static Marshaller marshaller;
+
+  @Override
+  public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    return ServiceDefinitionsResource.ServiceDefinitionsWrapper.class == type;
+  }
+
+  @Override
+  public long getSize(ServiceDefinitionsWrapper t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    return -1;
+  }
+
+  @Override
+  public void writeTo(ServiceDefinitionsWrapper instance, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+      MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
+    try {
+      getMarshaller().marshal(instance, entityStream);
+    } catch (JAXBException e) {
+      throw new IOException(e);
+    }
+  }
+
+  private synchronized Marshaller getMarshaller() throws JAXBException {
+    if (marshaller == null) {
+      marshaller = JAXBContext.newInstance(ServiceDefinitionsWrapper.class).createMarshaller();
+      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+    }
+    return marshaller;
+  }
+}
diff --git a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionUnmarshaller.java b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionUnmarshaller.java
new file mode 100644
index 0000000..6e15b7e
--- /dev/null
+++ b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionUnmarshaller.java
@@ -0,0 +1,64 @@
+/*
+ * 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.knox.gateway.service.admin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
+
+@Provider
+@Consumes({ MediaType.APPLICATION_XML })
+public class ServiceDefinitionUnmarshaller implements MessageBodyReader<ServiceDefinitionPair> {
+
+  private static Unmarshaller unmarshaller;
+
+  @Override
+  public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    return ServiceDefinitionPair.class == type;
+  }
+
+  @Override
+  public ServiceDefinitionPair readFrom(Class<ServiceDefinitionPair> instance, Type genericType, Annotation[] annotations, MediaType mediaType,
+      MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
+    try {
+      return (ServiceDefinitionPair) getUnmarshaller().unmarshal(entityStream);
+    } catch (JAXBException e) {
+      throw new IOException(e);
+    }
+  }
+
+  private synchronized Unmarshaller getUnmarshaller() throws JAXBException {
+    if (unmarshaller == null) {
+      unmarshaller = JAXBContext.newInstance(ServiceDefinitionPair.class).createUnmarshaller();
+    }
+    return unmarshaller;
+  }
+}
diff --git a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
new file mode 100644
index 0000000..25385ca
--- /dev/null
+++ b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
@@ -0,0 +1,175 @@
+/*
+ * 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.knox.gateway.service.admin;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.serverError;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.inject.Singleton;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistry;
+import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistryException;
+
+@Path("/api/v1")
+@Singleton
+public class ServiceDefinitionsResource {
+
+  private static final String ERROR_CODE_CREATION = "CREATION_ERROR";
+  private static final String ERROR_CODE_CREATION_OR_UPDATE = "CREATION_OR_UPDATE_ERROR";
+  private static final String ERROR_CODE_DELETION = "DELETION_ERROR";
+
+  @Context
+  private HttpServletRequest request;
+
+  private ServiceDefinitionRegistry serviceDefinitionRegistry;
+
+  @GET
+  @Produces({ APPLICATION_JSON, APPLICATION_XML })
+  @Path("servicedefinitions")
+  public ServiceDefinitionsWrapper getServiceDefinitions() {
+    return getServiceDefinitions((Predicate<? super ServiceDefinitionPair>) null);
+  }
+
+  @GET
+  @Produces({ APPLICATION_JSON, APPLICATION_XML })
+  @Path("servicedefinitions/{name}")
+  public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name") String name) {
+    return getServiceDefinitions(serviceDefinitionPair -> serviceDefinitionPair.getService().getName().equalsIgnoreCase(name));
+  }
+
+  @GET
+  @Produces({ APPLICATION_JSON, APPLICATION_XML })
+  @Path("servicedefinitions/{name}/{role}")
+  public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name") String name, @PathParam("role") String role) {
+    return getServiceDefinitions(
+        serviceDefinitionPair -> serviceDefinitionPair.getService().getName().equalsIgnoreCase(name) && serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role));
+  }
+
+  @GET
+  @Produces({ APPLICATION_JSON, APPLICATION_XML })
+  @Path("servicedefinitions/{name}/{role}/{version}")
+  public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name") String name, @PathParam("role") String role, @PathParam("version") String version) {
+    return getServiceDefinitions(serviceDefinitionPair -> serviceDefinitionPair.getService().getName().equalsIgnoreCase(name)
+        && serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role) && serviceDefinitionPair.getService().getVersion().equalsIgnoreCase(version));
+  }
+
+  @POST
+  @Consumes({ APPLICATION_XML })
+  @Produces({ APPLICATION_JSON })
+  @Path("servicedefinitions")
+  public Response saveServiceDefinition(ServiceDefinitionPair serviceDefinition) {
+    try {
+      getServiceDefinitionRegistry().saveServiceDefinition(serviceDefinition);
+      return created(toUri(serviceDefinition)).build();
+    } catch (URISyntaxException | ServiceDefinitionRegistryException e) {
+      return serverError().entity("{ \"" +  ERROR_CODE_CREATION + "\": \"" + e.getMessage() + "\" }").build();
+    }
+  }
+
+  @PUT
+  @Consumes({ APPLICATION_XML })
+  @Produces({ APPLICATION_JSON })
+  @Path("servicedefinitions")
+  public Response saveOrUpdateServiceDefinition(ServiceDefinitionPair serviceDefinition) {
+    try {
+      getServiceDefinitionRegistry().saveOrUpdateServiceDefinition(serviceDefinition);
+      return created(toUri(serviceDefinition)).build();
+    } catch (URISyntaxException | ServiceDefinitionRegistryException e) {
+      return serverError().entity("{ \"" +  ERROR_CODE_CREATION_OR_UPDATE + "\": \"" + e.getMessage() + "\" }").build();
+    }
+  }
+
+  @DELETE
+  @Produces({ APPLICATION_JSON })
+  @Path("servicedefinitions/{name}/{role}/{version}")
+  public Response deleteServiceDefinition(@PathParam("name") String name, @PathParam("role") String role, @PathParam("version") String version) {
+    try {
+      getServiceDefinitionRegistry().deleteServiceDefinition(name, role, version);
+      return ok().location(toUri(name, role, version)).build();
+    } catch (URISyntaxException | ServiceDefinitionRegistryException e) {
+      return serverError().entity("{ \"" +  ERROR_CODE_DELETION + "\": \"" + e.getMessage() + "\" }").build();
+    }
+  }
+
+  private URI toUri(ServiceDefinitionPair serviceDefinition) throws URISyntaxException {
+    return toUri(serviceDefinition.getService().getName(), serviceDefinition.getService().getRole(), serviceDefinition.getService().getVersion());
+  }
+
+  private URI toUri(String name, String role, String version) throws URISyntaxException {
+    return new URI("api/v1/servicedefinitions/" + name + "/" + role + "/" + version);
+  }
+
+  private ServiceDefinitionsWrapper getServiceDefinitions(Predicate<? super ServiceDefinitionPair> predicate) {
+    final ServiceDefinitionsWrapper serviceDefinitionsWrapper = new ServiceDefinitionsWrapper();
+    final Set<ServiceDefinitionPair> serviceDefinitions = getServiceDefinitionRegistry().getServiceDefinitions();
+    serviceDefinitionsWrapper.setServiceDefinitions(predicate == null ? serviceDefinitions : serviceDefinitions.stream().filter(predicate).collect(Collectors.toSet()));
+    return serviceDefinitionsWrapper;
+  }
+
+  private ServiceDefinitionRegistry getServiceDefinitionRegistry() {
+    if (serviceDefinitionRegistry == null) {
+      final GatewayServices gatewayServices = (GatewayServices) request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+      serviceDefinitionRegistry = gatewayServices.getService(ServiceType.SERVICE_DEFINITION_REGISTRY);
+    }
+    return serviceDefinitionRegistry;
+  }
+
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class ServiceDefinitionsWrapper {
+
+    @XmlElement(name="serviceDefinition")
+    @XmlElementWrapper(name = "serviceDefinitions")
+    private Set<ServiceDefinitionPair> serviceDefinitions = new HashSet<>();
+
+    public Set<ServiceDefinitionPair> getServiceDefinitions() {
+      return serviceDefinitions;
+    }
+
+    public void setServiceDefinitions(Set<ServiceDefinitionPair> serviceDefinitions) {
+      this.serviceDefinitions = serviceDefinitions;
+    }
+  }
+}
diff --git a/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinition.java b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinition.java
index f9eeb1e..2415f16 100644
--- a/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinition.java
+++ b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinition.java
@@ -21,6 +21,7 @@ import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
+
 import java.util.List;
 
 @XmlRootElement(name = "service")
@@ -105,4 +106,10 @@ public class ServiceDefinition {
   public void setDispatch(CustomDispatch dispatch) {
     this.dispatch = dispatch;
   }
+
+  @Override
+  public String toString() {
+    return new StringBuilder().append(name).append(", ").append(role).append(", ").append(version).toString();
+  }
+
 }
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionChangeListener.java
similarity index 81%
copy from gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
copy to gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionChangeListener.java
index 1b425ef..c914a37 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
+++ b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionChangeListener.java
@@ -15,11 +15,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.knox.gateway.services.registry;
+package org.apache.knox.gateway.service.definition;
 
-public interface ServiceDefinitionRegistry {
-
-  ServiceDefEntry getMatchingService(String urlPattern);
+public interface ServiceDefinitionChangeListener {
 
+  void onServiceDefinitionChange(String name, String role, String version);
 
 }
diff --git a/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparator.java b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparator.java
new file mode 100644
index 0000000..e55365b
--- /dev/null
+++ b/gateway-service-definitions/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.knox.gateway.service.definition;
+
+import java.util.Comparator;
+
+/**
+ * A {@link Comparator} implementation for {@link ServiceDefinition} using the
+ * following fields in the following order for comparison:
+ * <ol>
+ * <li>name</li>
+ * <li>role</li>
+ * <li>version</li>
+ * </ol>
+ */
+public class ServiceDefinitionComparator implements Comparator<ServiceDefinition> {
+
+  @Override
+  public int compare(ServiceDefinition serviceDefinition, ServiceDefinition otherServiceDefinition) {
+    if (serviceDefinition == null || otherServiceDefinition == null) {
+      throw new IllegalArgumentException("One (or both) of the supplied service definitions is null");
+    }
+    final int byName = serviceDefinition.getName().compareTo(otherServiceDefinition.getName());
+    final int byRole = serviceDefinition.getRole().compareTo(otherServiceDefinition.getRole());
+    final int byVersion = serviceDefinition.getVersion().compareTo(otherServiceDefinition.getVersion());
+    return byName != 0 ? byName : byRole != 0 ? byRole : byVersion;
+  }
+
+}
diff --git a/gateway-service-definitions/src/test/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparatorTest.java b/gateway-service-definitions/src/test/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparatorTest.java
new file mode 100644
index 0000000..9ae69c2
--- /dev/null
+++ b/gateway-service-definitions/src/test/java/org/apache/knox/gateway/service/definition/ServiceDefinitionComparatorTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.knox.gateway.service.definition;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class ServiceDefinitionComparatorTest {
+
+  private final ServiceDefinitionComparator serviceDefinitionComparator = new ServiceDefinitionComparator();
+
+  @Test
+  public void shouldCompareByName() throws Exception {
+    assertEquals(-1, serviceDefinitionComparator.compare(buildServiceDefinition("service1", "role1", "1.0"), buildServiceDefinition("service2", "role1", "1.0")));
+  }
+
+  @Test
+  public void shouldCompareByRole() throws Exception {
+    assertEquals(-1, serviceDefinitionComparator.compare(buildServiceDefinition("service1", "role1", "1.0"), buildServiceDefinition("service1", "role2", "1.0")));
+  }
+
+  @Test
+  public void shouldCompareByVersion() throws Exception {
+    assertEquals(-1, serviceDefinitionComparator.compare(buildServiceDefinition("service1", "role1", "1.0"), buildServiceDefinition("service1", "role1", "2.0")));
+  }
+
+  @Test
+  public void shouldReturnZeroIfAllEquals() throws Exception {
+    assertEquals(0, serviceDefinitionComparator.compare(buildServiceDefinition("service1", "role1", "1.0"), buildServiceDefinition("service1", "role1", "1.0")));
+  }
+
+  private ServiceDefinition buildServiceDefinition(String name, String role, String version) {
+    final ServiceDefinition serviceDefinition = new ServiceDefinition();
+    serviceDefinition.setName(name);
+    serviceDefinition.setRole(role);
+    serviceDefinition.setVersion(version);
+    return serviceDefinition;
+  }
+
+}
diff --git a/gateway-spi/pom.xml b/gateway-spi/pom.xml
index 3ddc691..461b8d8 100644
--- a/gateway-spi/pom.xml
+++ b/gateway-spi/pom.xml
@@ -36,6 +36,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-service-definitions</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-common</artifactId>
         </dependency>
         <dependency>
@@ -44,6 +48,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
 
@@ -136,6 +144,10 @@
             <groupId>com.sun.activation</groupId>
             <artifactId>javax.activation</artifactId>
         </dependency>
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.knox</groupId>
@@ -152,9 +164,5 @@
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-util</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.knox</groupId>
-            <artifactId>gateway-service-definitions</artifactId>
-        </dependency>
     </dependencies>
 </project>
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPair.java b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPair.java
new file mode 100644
index 0000000..856fd5a
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPair.java
@@ -0,0 +1,61 @@
+/*
+ * 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.knox.gateway.service.definition;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+
+@XmlRootElement(name = "serviceDefinition")
+@XmlAccessorType(XmlAccessType.NONE)
+public class ServiceDefinitionPair {
+
+  @XmlElement
+  private final ServiceDefinition service;
+
+  @XmlElement(name = "rules")
+  @XmlJavaTypeAdapter(UrlRewriteRulesDescriptorAdapter.class)
+  private final UrlRewriteRulesDescriptor rewriteRules;
+
+  // having a no-argument constructor is required by JAXB
+  public ServiceDefinitionPair() {
+    this(null, null);
+  }
+
+  public ServiceDefinitionPair(ServiceDefinition service, UrlRewriteRulesDescriptor rewriteRules) {
+    this.service = service;
+    this.rewriteRules = rewriteRules;
+  }
+
+  public ServiceDefinition getService() {
+    return service;
+  }
+
+  public UrlRewriteRulesDescriptor getRewriteRules() {
+    return rewriteRules;
+  }
+
+  @Override
+  public String toString() {
+    return service.toString();
+  }
+}
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPairComparator.java
similarity index 51%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java
rename to gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPairComparator.java
index 22a7817..251a6a3 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteFilterApplyDescriptorImpl.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/ServiceDefinitionPairComparator.java
@@ -15,33 +15,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.knox.gateway.filter.rewrite.impl;
+package org.apache.knox.gateway.service.definition;
 
-import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import java.util.Comparator;
 
-public class UrlRewriteFilterApplyDescriptorImpl
-    extends UrlRewriteFilterSelectorDescriptorBase<UrlRewriteFilterApplyDescriptor>
-    implements UrlRewriteFilterApplyDescriptor {
+public class ServiceDefinitionPairComparator implements Comparator<ServiceDefinitionPair> {
 
-  private String rule;
+  final ServiceDefinitionComparator serviceDefinitionComparator = new ServiceDefinitionComparator();
 
   @Override
-  public String rule() {
-    return rule;
-  }
-
-  @Override
-  public UrlRewriteFilterApplyDescriptor rule( String rule ) {
-    this.rule = rule;
-    return this;
-  }
-
-  public void setRule( String rule ) {
-    this.rule = rule;
-  }
-
-  public String getRule() {
-    return rule;
+  public int compare(ServiceDefinitionPair serviceDefinitionPair, ServiceDefinitionPair otherServiceDefinitionPair) {
+    final ServiceDefinition service = serviceDefinitionPair.getService();
+    final ServiceDefinition otherService = otherServiceDefinitionPair.getService();
+    if (service == null || otherServiceDefinitionPair == null) {
+      throw new IllegalArgumentException("One (or both) of the supplied service definitions is null");
+    }
+    return serviceDefinitionComparator.compare(service, otherService);
   }
 
 }
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/UrlRewriteRulesDescriptorAdapter.java b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/UrlRewriteRulesDescriptorAdapter.java
new file mode 100644
index 0000000..4928fbc
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/service/definition/UrlRewriteRulesDescriptorAdapter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.knox.gateway.service.definition;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.impl.xml.XmlUrlRewriteRulesExporter;
+import org.apache.knox.gateway.filter.rewrite.impl.xml.XmlUrlRewriteRulesImporter;
+import org.w3c.dom.Node;
+
+/**
+ * Serves as a gateway between JAXB marshal/unmarshal and DOM
+ * serializing/digesting.
+ */
+public class UrlRewriteRulesDescriptorAdapter extends XmlAdapter<Object, UrlRewriteRulesDescriptor> {
+
+  private final XmlUrlRewriteRulesExporter xmlRewriteRulesExporter = new XmlUrlRewriteRulesExporter();
+  private final XmlUrlRewriteRulesImporter xmlRewriteRulesImporter = new XmlUrlRewriteRulesImporter();
+
+  @Override
+  public UrlRewriteRulesDescriptor unmarshal(Object value) throws Exception {
+    try (InputStream is = nodeToInputStream((Node) value); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)) {
+      return xmlRewriteRulesImporter.load(isr);
+    }
+  }
+
+  private static InputStream nodeToInputStream(Node node) throws Exception {
+    try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+      TransformerFactory.newInstance().newTransformer().transform(new DOMSource(node), new StreamResult(outputStream));
+      return new ByteArrayInputStream(outputStream.toByteArray());
+    }
+  }
+
+  @Override
+  public Object marshal(UrlRewriteRulesDescriptor value) throws Exception {
+    try (Writer writer = new StringWriter()) {
+      return (Node) xmlRewriteRulesExporter.store(value, writer, true);
+    }
+  }
+}
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
index 1b425ef..a3fa306 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
@@ -17,9 +17,23 @@
  */
 package org.apache.knox.gateway.services.registry;
 
+import java.util.Set;
+
+import org.apache.knox.gateway.service.definition.ServiceDefinitionChangeListener;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
+
 public interface ServiceDefinitionRegistry {
 
   ServiceDefEntry getMatchingService(String urlPattern);
 
+  Set<ServiceDefinitionPair> getServiceDefinitions();
+
+  void saveServiceDefinition(ServiceDefinitionPair serviceDefinition) throws ServiceDefinitionRegistryException;
+
+  void saveOrUpdateServiceDefinition(ServiceDefinitionPair serviceDefinition) throws ServiceDefinitionRegistryException;
+
+  void deleteServiceDefinition(String name, String role, String version) throws ServiceDefinitionRegistryException;
+
+  void addServiceDefinitionChangeListener(ServiceDefinitionChangeListener listener);
 
 }
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistryException.java
similarity index 74%
copy from gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
copy to gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistryException.java
index 1b425ef..c6b4cf7 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistry.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/registry/ServiceDefinitionRegistryException.java
@@ -17,9 +17,15 @@
  */
 package org.apache.knox.gateway.services.registry;
 
-public interface ServiceDefinitionRegistry {
+@SuppressWarnings("serial")
+public class ServiceDefinitionRegistryException extends Exception {
 
-  ServiceDefEntry getMatchingService(String urlPattern);
+  public ServiceDefinitionRegistryException(String message) {
+    super(message);
+  }
 
+  public ServiceDefinitionRegistryException(String message, Throwable throwable) {
+    super(message, throwable);
+  }
 
 }
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/topology/TopologyService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/topology/TopologyService.java
index e1f78fb..3266f48 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/topology/TopologyService.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/topology/TopologyService.java
@@ -18,6 +18,7 @@
 package org.apache.knox.gateway.services.topology;
 
 import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.service.definition.ServiceDefinitionChangeListener;
 import org.apache.knox.gateway.services.Service;
 import org.apache.knox.gateway.topology.Topology;
 import org.apache.knox.gateway.topology.TopologyListener;
@@ -28,7 +29,7 @@ import java.util.List;
 import java.util.Map;
 
 
-public interface TopologyService extends Service {
+public interface TopologyService extends Service, ServiceDefinitionChangeListener {
 
   void reloadTopologies();
 
diff --git a/gateway-test/pom.xml b/gateway-test/pom.xml
index f4d76b0..a215525 100644
--- a/gateway-test/pom.xml
+++ b/gateway-test/pom.xml
@@ -57,6 +57,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-rewrite-common</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
             <artifactId>gateway-provider-security-authc-anon</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
index 8982ed9..ccdb164 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
@@ -19,6 +19,7 @@ package org.apache.knox.gateway;
 import org.apache.commons.io.FileUtils;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistry;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.KeystoreService;
@@ -171,6 +172,12 @@ public class SimpleDescriptorHandlerFuncTest {
       // Setup the Gateway Services
       GatewayServices gatewayServices = EasyMock.createNiceMock(GatewayServices.class);
 
+      //Service Definition Registry
+      final ServiceDefinitionRegistry serviceDefinitionRegistry = EasyMock.createNiceMock(ServiceDefinitionRegistry.class);
+      EasyMock.expect(serviceDefinitionRegistry.getServiceDefinitions()).andReturn(Collections.emptySet()).anyTimes();
+      EasyMock.replay(serviceDefinitionRegistry);
+      EasyMock.expect(gatewayServices.getService(ServiceType.SERVICE_DEFINITION_REGISTRY)).andReturn(serviceDefinitionRegistry).anyTimes();
+
       // Master Service
       MasterService ms = EasyMock.createNiceMock(MasterService.class);
       EasyMock.expect(ms.getMasterSecret()).andReturn(testMasterSecret.toCharArray()).anyTimes();
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/CollectionUtils.java
similarity index 53%
rename from gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java
rename to gateway-util-common/src/main/java/org/apache/knox/gateway/util/CollectionUtils.java
index ad37a46..6c0af20 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/api/UrlRewriteFilterPathDescriptor.java
+++ b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/CollectionUtils.java
@@ -15,25 +15,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.knox.gateway.filter.rewrite.api;
-
-public interface UrlRewriteFilterPathDescriptor<T> {
-
-  String path();
-
-  T path( String path );
-
-  <C> C compiledPath();
-
-  T compiledPath( Object compilePath );
-
-  <C> C compiledPath( Compiler<C> compiler );
-
-  interface Compiler<C> {
-    // The returned compiled version of the expression must be thread safe.
-    // The compiled param will be the result of the last successful call to this method for this instance of
-    // the descriptor node.
-    C compile( String expression, C compiled );
+package org.apache.knox.gateway.util;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+
+public class CollectionUtils {
+
+  public static <T> boolean isSorted(Collection<T> collection, Comparator<T> comparator) {
+    if (collection != null) {
+      if (collection.isEmpty() || collection.size() == 1) {
+        return true;
+      }
+
+      final Iterator<T> iterator = collection.iterator();
+      T current, previous = iterator.next();
+      while (iterator.hasNext()) {
+        current = iterator.next();
+        if (comparator.compare(previous, current) > 0) {
+          return false;
+        }
+        previous = current;
+      }
+      return true;
+    } else {
+      return false;
+    }
   }
 
 }
diff --git a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/XmlUtils.java b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/XmlUtils.java
index 9a15dba..221a5a9 100644
--- a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/XmlUtils.java
+++ b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/XmlUtils.java
@@ -60,7 +60,11 @@ public class XmlUtils {
   }
 
   public static void writeXml( Document document, Writer writer ) throws TransformerException {
-    Transformer t = XmlUtils.getTransformer( false, true, 4, false );
+    writeXml( document, writer, false );
+  }
+
+  public static void writeXml( Document document, Writer writer, boolean omitXmlHeader ) throws TransformerException {
+    Transformer t = XmlUtils.getTransformer( false, true, 4, omitXmlHeader );
     writeXml( document, writer, t );
   }
 
diff --git a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/CollectionUtilsTest.java b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/CollectionUtilsTest.java
new file mode 100644
index 0000000..04c7bf1
--- /dev/null
+++ b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/CollectionUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.knox.gateway.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.junit.Test;
+
+public class CollectionUtilsTest {
+
+  private final Comparator<Integer> integerComparator = Comparator.naturalOrder();
+
+  @Test
+  public void shouldReturnFalseWhenCheckingIfCollectionIsSortedAndGivenCollectionIsNull() throws Exception {
+    assertFalse(CollectionUtils.isSorted(null, integerComparator));
+  }
+
+  @Test
+  public void shouldReturnTrueWhenCheckingIfCollectionIsSortedAndGivenCollectionIsEmpty() throws Exception {
+    assertTrue(CollectionUtils.isSorted(Collections.emptyList(), integerComparator));
+  }
+
+  @Test
+  public void shouldReturnTrueWhenCheckingIfCollectionIsSortedAndGivenCollectionHasOneElement() throws Exception {
+    final List<Integer> list = Arrays.asList(1);
+    assertTrue(CollectionUtils.isSorted(list, integerComparator));
+  }
+
+  @Test
+  public void shouldReturnTrueWhenCheckingIfCollectionIsSortedAndGivenCollectionIsSorted() throws Exception {
+    final List<Integer> list = Arrays.asList(1, 2, 5, 8, 9);
+    assertTrue(CollectionUtils.isSorted(list, integerComparator));
+  }
+
+  @Test
+  public void shouldReturnFalseWhenCheckingIfCollectionIsSortedAndGivenCollectionIsNotSorted() throws Exception {
+    final List<Integer> list = Arrays.asList(1, 5, 2, 8, 9);
+    assertFalse(CollectionUtils.isSorted(list, integerComparator));
+  }
+}
diff --git a/pom.xml b/pom.xml
index 1878085..18bfa5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,7 @@
         <module>gateway-server-launcher</module>
         <module>gateway-server-xforwarded-filter</module>
         <module>gateway-provider-rewrite</module>
+        <module>gateway-provider-rewrite-common</module>
         <module>gateway-provider-rewrite-func-hostmap-static</module>
         <module>gateway-provider-rewrite-func-service-registry</module>
         <module>gateway-provider-rewrite-func-inbound-query-param</module>
@@ -889,6 +890,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.knox</groupId>
+                <artifactId>gateway-provider-rewrite-common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.knox</groupId>
                 <artifactId>gateway-provider-rewrite-func-hostmap-static</artifactId>
                 <version>${project.version}</version>
             </dependency>


Mime
View raw message