You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by ud...@apache.org on 2014/08/15 12:51:19 UTC

[12/51] [abbrv] Clustering changes for stratos

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/tenant/SubscriptionDomainsRemovedEventListener.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/tenant/SubscriptionDomainsRemovedEventListener.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/tenant/SubscriptionDomainsRemovedEventListener.java
new file mode 100644
index 0000000..5c81ad6
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/tenant/SubscriptionDomainsRemovedEventListener.java
@@ -0,0 +1,28 @@
+/*
+ * 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.stratos.messaging.listener.tenant;
+
+import org.apache.stratos.messaging.listener.EventListener;
+
+/**
+ * Tenant subscription domains removed event listener.
+ */
+public abstract class SubscriptionDomainsRemovedEventListener extends EventListener {
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/topology/ClusterMaintenanceModeEventListener.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/topology/ClusterMaintenanceModeEventListener.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/topology/ClusterMaintenanceModeEventListener.java
new file mode 100644
index 0000000..3bd2a19
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/listener/topology/ClusterMaintenanceModeEventListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.stratos.messaging.listener.topology;
+
+import org.apache.stratos.messaging.listener.EventListener;
+
+public abstract class ClusterMaintenanceModeEventListener extends EventListener {
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainAddedMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainAddedMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainAddedMessageProcessor.java
new file mode 100644
index 0000000..79d1e12
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainAddedMessageProcessor.java
@@ -0,0 +1,95 @@
+/*
+ * 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.stratos.messaging.message.processor.tenant;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.messaging.domain.tenant.Subscription;
+import org.apache.stratos.messaging.domain.tenant.SubscriptionDomain;
+import org.apache.stratos.messaging.domain.tenant.Tenant;
+import org.apache.stratos.messaging.event.tenant.SubscriptionDomainAddedEvent;
+import org.apache.stratos.messaging.message.processor.MessageProcessor;
+import org.apache.stratos.messaging.message.receiver.tenant.TenantManager;
+import org.apache.stratos.messaging.util.Util;
+
+/**
+ * Subscription domain added message processor for adding domains to tenant subscriptions.
+ */
+public class SubscriptionDomainAddedMessageProcessor extends MessageProcessor {
+
+    private static final Log log = LogFactory.getLog(SubscriptionDomainAddedMessageProcessor.class);
+
+    private MessageProcessor nextProcessor;
+
+    @Override
+    public void setNext(MessageProcessor nextProcessor) {
+        this.nextProcessor = nextProcessor;
+    }
+
+    @Override
+    public boolean process(String type, String message, Object object) {
+        if (SubscriptionDomainAddedEvent.class.getName().equals(type)) {
+            // Return if tenant manager has not initialized
+            if (!TenantManager.getInstance().isInitialized()) {
+                return false;
+            }
+
+            // Parse complete message and build event
+            SubscriptionDomainAddedEvent event = (SubscriptionDomainAddedEvent) Util.jsonToObject(message, SubscriptionDomainAddedEvent.class);
+
+            try {
+                TenantManager.acquireWriteLock();
+                Tenant tenant = TenantManager.getInstance().getTenant(event.getTenantId());
+                if (tenant == null) {
+                    if (log.isWarnEnabled()) {
+                        log.warn(String.format("Tenant not found: [tenant-id] %d", event.getTenantId()));
+                    }
+                    return false;
+                }
+                Subscription subscription = tenant.getSubscription(event.getServiceName());
+                if (subscription == null) {
+                    if (log.isWarnEnabled()) {
+                        log.warn(String.format("Subscription not found: [tenant-id] %d", event.getTenantId()));
+                    }
+                    return false;
+                }
+                subscription.addSubscriptionDomain(new SubscriptionDomain(event.getDomainName(), event.getApplicationContext()));
+                if (log.isInfoEnabled()) {
+                    log.info(String.format("Domain added to tenant subscription: [tenant-id] %d [tenant-domain] %s " +
+                                    "[service] %s [domain-name] %s [application-context] %s", tenant.getTenantId(),
+                            tenant.getTenantDomain(), event.getServiceName(), event.getDomainName(), event.getApplicationContext()
+                    ));
+                }
+
+                // Notify event listeners
+                notifyEventListeners(event);
+                return true;
+            } finally {
+                TenantManager.releaseWriteLock();
+            }
+        } else {
+            if (nextProcessor != null) {
+                return nextProcessor.process(type, message, object);
+            } else {
+                throw new RuntimeException(String.format("Failed to process tenant message using available message processors: [type] %s [body] %s", type, message));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainRemovedMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainRemovedMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainRemovedMessageProcessor.java
new file mode 100644
index 0000000..ea413cd
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/SubscriptionDomainRemovedMessageProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.stratos.messaging.message.processor.tenant;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.messaging.domain.tenant.Subscription;
+import org.apache.stratos.messaging.domain.tenant.Tenant;
+import org.apache.stratos.messaging.event.tenant.SubscriptionDomainRemovedEvent;
+import org.apache.stratos.messaging.message.processor.MessageProcessor;
+import org.apache.stratos.messaging.message.receiver.tenant.TenantManager;
+import org.apache.stratos.messaging.util.Util;
+
+/**
+ * Subscription domain removed message processor for removing domains from tenant subscriptions.
+ */
+public class SubscriptionDomainRemovedMessageProcessor extends MessageProcessor {
+
+    private static final Log log = LogFactory.getLog(SubscriptionDomainRemovedMessageProcessor.class);
+
+    private MessageProcessor nextProcessor;
+
+    @Override
+    public void setNext(MessageProcessor nextProcessor) {
+        this.nextProcessor = nextProcessor;
+    }
+
+    @Override
+    public boolean process(String type, String message, Object object) {
+        if (SubscriptionDomainRemovedEvent.class.getName().equals(type)) {
+            // Return if tenant manager has not initialized
+            if (!TenantManager.getInstance().isInitialized()) {
+                return false;
+            }
+
+            // Parse complete message and build event
+            SubscriptionDomainRemovedEvent event = (SubscriptionDomainRemovedEvent) Util.jsonToObject(message, SubscriptionDomainRemovedEvent.class);
+
+            try {
+                TenantManager.acquireWriteLock();
+                Tenant tenant = TenantManager.getInstance().getTenant(event.getTenantId());
+                if (tenant == null) {
+                    if (log.isWarnEnabled()) {
+                        log.warn(String.format("Tenant not found: [tenant-id] %d", event.getTenantId()));
+                    }
+                    return false;
+                }
+                Subscription subscription = tenant.getSubscription(event.getServiceName());
+                if (subscription == null) {
+                    if (log.isWarnEnabled()) {
+                        log.warn(String.format("Subscription not found: [tenant-id] %d", event.getTenantId()));
+                    }
+                    return false;
+                }
+                subscription.removeSubscriptionDomain(event.getDomainName());
+                if (log.isInfoEnabled()) {
+                    log.info(String.format("Domain removed from tenant subscription: [tenant-id] %d [tenant-domain] %s " +
+                                    "[service] %s [domain-name] %s", tenant.getTenantId(), tenant.getTenantDomain(),
+                            event.getServiceName(), event.getDomainName()
+                    ));
+                }
+
+                // Notify event listeners
+                notifyEventListeners(event);
+                return true;
+            } finally {
+                TenantManager.releaseWriteLock();
+            }
+        } else {
+            if (nextProcessor != null) {
+                return nextProcessor.process(type, message, object);
+            } else {
+                throw new RuntimeException(String.format("Failed to process tenant message using available message processors: [type] %s [body] %s", type, message));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantMessageProcessorChain.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantMessageProcessorChain.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantMessageProcessorChain.java
index d4c008e..b5edfc1 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantMessageProcessorChain.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantMessageProcessorChain.java
@@ -37,6 +37,8 @@ public class TenantMessageProcessorChain extends MessageProcessorChain {
     private TenantRemovedMessageProcessor tenantRemovedMessageProcessor;
     private TenantSubscribedMessageProcessor tenantSubscribedMessageProcessor;
     private TenantUnSubscribedMessageProcessor tenantUnSubscribedMessageProcessor;
+    private SubscriptionDomainAddedMessageProcessor subscriptionDomainAddedMessageProcessor;
+    private SubscriptionDomainRemovedMessageProcessor subscriptionDomainRemovedMessageProcessor;
 
     public void initialize() {
         // Add tenant event processors
@@ -58,6 +60,12 @@ public class TenantMessageProcessorChain extends MessageProcessorChain {
         tenantUnSubscribedMessageProcessor = new TenantUnSubscribedMessageProcessor();
         add(tenantUnSubscribedMessageProcessor);
 
+        subscriptionDomainAddedMessageProcessor = new SubscriptionDomainAddedMessageProcessor();
+        add(subscriptionDomainAddedMessageProcessor);
+
+        subscriptionDomainRemovedMessageProcessor = new SubscriptionDomainRemovedMessageProcessor();
+        add(subscriptionDomainRemovedMessageProcessor);
+
         if (log.isDebugEnabled()) {
             log.debug("Tenant message processor chain initialized");
         }
@@ -76,6 +84,10 @@ public class TenantMessageProcessorChain extends MessageProcessorChain {
             tenantSubscribedMessageProcessor.addEventListener(eventListener);
         } else if (eventListener instanceof TenantUnSubscribedEventListener) {
             tenantUnSubscribedMessageProcessor.addEventListener(eventListener);
+        } else if (eventListener instanceof SubscriptionDomainsAddedEventListener) {
+            subscriptionDomainAddedMessageProcessor.addEventListener(eventListener);
+        } else if (eventListener instanceof SubscriptionDomainsRemovedEventListener) {
+            subscriptionDomainRemovedMessageProcessor.addEventListener(eventListener);
         }
         else {
             throw new RuntimeException("Unknown event listener");

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantSubscribedMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantSubscribedMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantSubscribedMessageProcessor.java
index aae074b..196bc22 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantSubscribedMessageProcessor.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantSubscribedMessageProcessor.java
@@ -21,6 +21,8 @@ package org.apache.stratos.messaging.message.processor.tenant;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.messaging.domain.tenant.Subscription;
+import org.apache.stratos.messaging.domain.tenant.SubscriptionDomain;
 import org.apache.stratos.messaging.domain.tenant.Tenant;
 import org.apache.stratos.messaging.event.tenant.TenantSubscribedEvent;
 import org.apache.stratos.messaging.message.processor.MessageProcessor;
@@ -62,7 +64,8 @@ public class TenantSubscribedMessageProcessor extends MessageProcessor {
                     }
                     return false;
                 }
-                tenant.addServiceSubscription(event.getServiceName());
+                Subscription subscription = new Subscription(event.getServiceName(), event.getClusterIds());
+                tenant.addSubscription(subscription);
                 if(log.isInfoEnabled()) {
                     log.info(String.format("Tenant subscribed to service: [tenant-id] %d [tenant-domain] %s [service] %s",
                              tenant.getTenantId(), tenant.getTenantDomain(), event.getServiceName()));

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantUnSubscribedMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantUnSubscribedMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantUnSubscribedMessageProcessor.java
index 6c4157c..ee929a3 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantUnSubscribedMessageProcessor.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/tenant/TenantUnSubscribedMessageProcessor.java
@@ -62,7 +62,7 @@ public class TenantUnSubscribedMessageProcessor extends MessageProcessor {
                     }
                     return false;
                 }
-                tenant.removeServiceSubscription(event.getServiceName());
+                tenant.removeSubscription(event.getServiceName());
                 if(log.isInfoEnabled()) {
                     log.info(String.format("Tenant un-subscribed from service: [tenant-id] %d [tenant-domain] %s [service] %s",
                             tenant.getTenantId(), tenant.getTenantDomain(), event.getServiceName()));

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/ClusterMaintenanceModeMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/ClusterMaintenanceModeMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/ClusterMaintenanceModeMessageProcessor.java
new file mode 100644
index 0000000..0300b24
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/ClusterMaintenanceModeMessageProcessor.java
@@ -0,0 +1,115 @@
+/*
+ * 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.stratos.messaging.message.processor.topology;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.messaging.domain.topology.Cluster;
+import org.apache.stratos.messaging.domain.topology.ClusterStatus;
+import org.apache.stratos.messaging.domain.topology.Service;
+import org.apache.stratos.messaging.domain.topology.Topology;
+import org.apache.stratos.messaging.event.topology.ClusterMaintenanceModeEvent;
+import org.apache.stratos.messaging.message.filter.topology.TopologyClusterFilter;
+import org.apache.stratos.messaging.message.filter.topology.TopologyServiceFilter;
+import org.apache.stratos.messaging.message.processor.MessageProcessor;
+import org.apache.stratos.messaging.util.Util;
+
+public class ClusterMaintenanceModeMessageProcessor extends MessageProcessor {
+    private static final Log log = LogFactory.getLog(ClusterMaintenanceModeMessageProcessor.class);
+    private MessageProcessor nextProcessor;
+
+    @Override
+    public void setNext(MessageProcessor nextProcessor) {
+        this.nextProcessor = nextProcessor;
+    }
+
+    @Override
+    public boolean process(String type, String message, Object object) {
+        Topology topology = (Topology) object;
+
+        if (ClusterMaintenanceModeEvent.class.getName().equals(type)) {
+            // Return if topology has not been initialized
+            if (!topology.isInitialized())
+                return false;
+
+            // Parse complete message and build event
+            ClusterMaintenanceModeEvent event = (ClusterMaintenanceModeEvent) Util.
+                                jsonToObject(message, ClusterMaintenanceModeEvent.class);
+
+            // Apply service filter
+            if (TopologyServiceFilter.getInstance().isActive()) {
+                if (TopologyServiceFilter.getInstance().serviceNameExcluded(event.getServiceName())) {
+                    // Service is excluded, do not update topology or fire event
+                    if (log.isDebugEnabled()) {
+                        log.debug(String.format("Service is excluded: [service] %s", event.getServiceName()));
+                    }
+                    return false;
+                }
+            }
+
+            // Apply cluster filter
+            if (TopologyClusterFilter.getInstance().isActive()) {
+                if (TopologyClusterFilter.getInstance().clusterIdExcluded(event.getClusterId())) {
+                    // Cluster is excluded, do not update topology or fire event
+                    if (log.isDebugEnabled()) {
+                        log.debug(String.format("Cluster is excluded: [cluster] %s", event.getClusterId()));
+                    }
+                    return false;
+                }
+            }
+
+            // Validate event against the existing topology
+            Service service = topology.getService(event.getServiceName());
+            if (service == null) {
+                if (log.isWarnEnabled()) {
+                    log.warn(String.format("Service does not exist: [service] %s",
+                            event.getServiceName()));
+                }
+                return false;
+            }
+            Cluster cluster = service.getCluster(event.getClusterId());
+
+            if (cluster == null) {
+                if (log.isWarnEnabled()) {
+                    log.warn(String.format("Cluster not exists in service: [service] %s [cluster] %s", event.getServiceName(),
+                            event.getClusterId()));
+                }
+			} else {
+			    // Apply changes to the topology
+                cluster.setStatus(ClusterStatus.In_Maintenance);
+				if (log.isInfoEnabled()) {
+					log.info(String.format("Cluster updated as maintenance mode: %s",
+							cluster.toString()));
+				}
+			}
+
+            // Notify event listeners
+            notifyEventListeners(event);
+            return true;
+
+        } else {
+            if (nextProcessor != null) {
+                // ask the next processor to take care of the message.
+                return nextProcessor.process(type, message, topology);
+            } else {
+                throw new RuntimeException(String.format("Failed to process message using available message processors: [type] %s [body] %s", type, message));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/InstanceSpawnedMessageProcessor.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/InstanceSpawnedMessageProcessor.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/InstanceSpawnedMessageProcessor.java
index 3bb0532..8e4e1b1 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/InstanceSpawnedMessageProcessor.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/InstanceSpawnedMessageProcessor.java
@@ -114,6 +114,7 @@ public class InstanceSpawnedMessageProcessor extends MessageProcessor {
             	member.setMemberPublicIp(event.getMemberPublicIp());
             	member.setMemberIp(event.getMemberIp());
             	member.setLbClusterId(event.getLbClusterId());
+                member.setProperties(event.getProperties());
             	cluster.addMember(member);
             	
             	if (log.isInfoEnabled()) {

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/TopologyMessageProcessorChain.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/TopologyMessageProcessorChain.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/TopologyMessageProcessorChain.java
index 7415c1f..eac7358 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/TopologyMessageProcessorChain.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/processor/topology/TopologyMessageProcessorChain.java
@@ -35,6 +35,7 @@ public class TopologyMessageProcessorChain extends MessageProcessorChain {
     private ServiceCreatedMessageProcessor serviceCreatedMessageProcessor;
     private ServiceRemovedMessageProcessor serviceRemovedMessageProcessor;
     private ClusterCreatedMessageProcessor clusterCreatedMessageProcessor;
+    private ClusterMaintenanceModeMessageProcessor clusterMaintenanceModeMessageProcessor;
     private ClusterRemovedMessageProcessor clusterRemovedMessageProcessor;
     private InstanceSpawnedMessageProcessor instanceSpawnedMessageProcessor;
     private MemberStartedMessageProcessor memberStartedMessageProcessor;
@@ -58,6 +59,9 @@ public class TopologyMessageProcessorChain extends MessageProcessorChain {
         clusterCreatedMessageProcessor = new ClusterCreatedMessageProcessor();
         add(clusterCreatedMessageProcessor);
 
+        clusterMaintenanceModeMessageProcessor = new ClusterMaintenanceModeMessageProcessor();
+        add(clusterMaintenanceModeMessageProcessor);
+
         clusterRemovedMessageProcessor = new ClusterRemovedMessageProcessor();
         add(clusterRemovedMessageProcessor);
 
@@ -93,6 +97,8 @@ public class TopologyMessageProcessorChain extends MessageProcessorChain {
         } else if (eventListener instanceof ClusterCreatedEventListener) {
             clusterCreatedMessageProcessor.addEventListener(eventListener);
             log.info("Messaging: added ClusterCreatedEventListener");
+        } else if (eventListener instanceof ClusterMaintenanceModeEventListener) {
+            clusterMaintenanceModeMessageProcessor.addEventListener(eventListener);
         } else if (eventListener instanceof ClusterRemovedEventListener) {
             clusterRemovedMessageProcessor.addEventListener(eventListener);
         } else if (eventListener instanceof InstanceSpawnedEventListener) {

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/receiver/tenant/TenantManager.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/receiver/tenant/TenantManager.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/receiver/tenant/TenantManager.java
index 8133b90..4581889 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/receiver/tenant/TenantManager.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/message/receiver/tenant/TenantManager.java
@@ -22,6 +22,7 @@ package org.apache.stratos.messaging.message.receiver.tenant;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.messaging.domain.tenant.Tenant;
+import org.wso2.carbon.base.MultitenantConstants;
 
 import java.util.HashMap;
 import java.util.List;
@@ -78,6 +79,10 @@ public class TenantManager {
     private TenantManager() {
         this.tenantIdTenantMap = new HashMap<Integer, Tenant>();
         this.tenantDomainTenantMap = new HashMap<String, Tenant>();
+        Tenant superTenant = new Tenant(MultitenantConstants.SUPER_TENANT_ID, 
+        		MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
+        this.tenantIdTenantMap.put(MultitenantConstants.SUPER_TENANT_ID, superTenant);
+        this.tenantDomainTenantMap.put(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, superTenant);
     }
 
     public static TenantManager getInstance() {

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/util/Constants.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/util/Constants.java b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/util/Constants.java
index 8b3c814..a44489f 100644
--- a/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/util/Constants.java
+++ b/components/org.apache.stratos.messaging/src/main/java/org/apache/stratos/messaging/util/Constants.java
@@ -63,4 +63,6 @@ public class Constants {
     public static final String DEVICE_NAME = "volume.device.name";
 	public static final String GRACEFUL_SHUTDOWN_TIMEOUT = "graceful.shutdown.timeout";
 
+    public static final String IS_PRIMARY = "PRIMARY";
+
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.messaging/src/test/java/org/apache/stratos/messaging/test/TenantDomainTest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/src/test/java/org/apache/stratos/messaging/test/TenantDomainTest.java b/components/org.apache.stratos.messaging/src/test/java/org/apache/stratos/messaging/test/TenantDomainTest.java
new file mode 100644
index 0000000..fae8b79
--- /dev/null
+++ b/components/org.apache.stratos.messaging/src/test/java/org/apache/stratos/messaging/test/TenantDomainTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.stratos.messaging.test;
+
+import junit.framework.Assert;
+import org.apache.stratos.messaging.domain.tenant.Subscription;
+import org.apache.stratos.messaging.domain.tenant.Tenant;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashSet;
+
+/**
+ * Tenant domain model test.
+ */
+@RunWith(JUnit4.class)
+public class TenantDomainTest {
+    @Test
+    public void testSubscriptionModel() {
+        Tenant tenant = new Tenant(1, "domain.org");
+        Subscription subscription = new Subscription("subscription1", new HashSet<String>());
+        tenant.addSubscription(subscription);
+        Assert.assertTrue("Subscription not added", tenant.isSubscribed("subscription1"));
+        tenant.removeSubscription("subscription1");
+        Assert.assertTrue("Subscription not removed", !tenant.isSubscribed("subscription1"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/CartridgeInfoBean.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/CartridgeInfoBean.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/CartridgeInfoBean.java
index e29d028..1bce7fb 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/CartridgeInfoBean.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/CartridgeInfoBean.java
@@ -19,6 +19,8 @@
 package org.apache.stratos.rest.endpoint.bean;
 
 import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
 
 @XmlRootElement
 public class CartridgeInfoBean {
@@ -38,6 +40,11 @@ public class CartridgeInfoBean {
     private String size;
     private boolean removeOnTermination;
     private String serviceGroup;
+    private List<String> domains;
+
+    public CartridgeInfoBean() {
+        this.domains = new ArrayList<String>();
+    }
 
     public String getCartridgeType() {
         return cartridgeType;
@@ -159,4 +166,8 @@ public class CartridgeInfoBean {
 		this.serviceGroup = serviceGroup;
 	}
     
+    public List<String> getDomains() { return domains; }
+
+    public void setDomains(List<String> domains) { this.domains = domains; }
+
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/SubscriptionDomainRequest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/SubscriptionDomainRequest.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/SubscriptionDomainRequest.java
new file mode 100644
index 0000000..6e0d6ae
--- /dev/null
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/SubscriptionDomainRequest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.stratos.rest.endpoint.bean;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
+
+/**
+ * Defines subscription domain post request.
+ */
+@XmlRootElement
+public class SubscriptionDomainRequest {
+    public List<SubscriptionDomainBean> domains;
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/subscription/domain/SubscriptionDomainBean.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/subscription/domain/SubscriptionDomainBean.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/subscription/domain/SubscriptionDomainBean.java
new file mode 100644
index 0000000..1b053bf
--- /dev/null
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/subscription/domain/SubscriptionDomainBean.java
@@ -0,0 +1,29 @@
+/*
+ * 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.stratos.rest.endpoint.bean.subscription.domain;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "domains")
+public class SubscriptionDomainBean {
+    public String domainName;
+    public String applicationContext;
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/util/converter/PojoConverter.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/util/converter/PojoConverter.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/util/converter/PojoConverter.java
index 1208967..efb2960 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/util/converter/PojoConverter.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/bean/util/converter/PojoConverter.java
@@ -21,12 +21,14 @@ package org.apache.stratos.rest.endpoint.bean.util.converter;
 
 import org.apache.stratos.cloud.controller.stub.pojo.*;
 import org.apache.stratos.manager.deploy.service.Service;
+import org.apache.stratos.manager.subscription.SubscriptionDomain;
 import org.apache.stratos.messaging.domain.topology.Cluster;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.Partition;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.PartitionGroup;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.autoscale.*;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.deployment.DeploymentPolicy;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.*;
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
 import org.apache.stratos.rest.endpoint.bean.topology.Member;
 
 import java.util.ArrayList;
@@ -412,6 +414,34 @@ public class PojoConverter {
 
         return partitionBeans;
     }
+    
+	public static List<SubscriptionDomainBean> populateSubscriptionDomainPojos(List<SubscriptionDomain> subscriptionDomains) {
+
+		List<SubscriptionDomainBean> subscriptionDomainBeans = new ArrayList<SubscriptionDomainBean>();
+		
+		if (subscriptionDomains == null) {
+			return subscriptionDomainBeans;
+		}
+		
+		for (SubscriptionDomain subscriptionDomain : subscriptionDomains) {
+			subscriptionDomainBeans.add(populateSubscriptionDomainPojo(subscriptionDomain));
+		}
+
+		return subscriptionDomainBeans;
+	}
+    
+	public static SubscriptionDomainBean populateSubscriptionDomainPojo(SubscriptionDomain subscriptionDomain) {
+
+		SubscriptionDomainBean subscriptionDomainBean = new SubscriptionDomainBean();
+		
+		if (subscriptionDomain == null) {
+			return subscriptionDomainBean;
+		}
+		subscriptionDomainBean.domainName = subscriptionDomain.getDomainName();
+		subscriptionDomainBean.applicationContext = subscriptionDomain.getApplicationContext();
+
+		return subscriptionDomainBean;
+	}
 
     private static List<PropertyBean> getPropertyBeans (Properties properties) {
 

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/CustomThrowableExceptionMapper.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/CustomThrowableExceptionMapper.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/CustomThrowableExceptionMapper.java
new file mode 100644
index 0000000..0f08728
--- /dev/null
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/CustomThrowableExceptionMapper.java
@@ -0,0 +1,39 @@
+package org.apache.stratos.rest.endpoint.handlers;/*
+ * 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.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.rest.endpoint.Utils;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+public class CustomThrowableExceptionMapper implements ExceptionMapper<Throwable> {
+    private static Log log = LogFactory.getLog(CustomThrowableExceptionMapper.class);
+
+    public Response toResponse(Throwable throwable) {
+        if(log.isDebugEnabled()){
+            log.debug("Internal server error", throwable);
+        }
+
+        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).type(MediaType.APPLICATION_JSON).
+                entity(Utils.buildMessage(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "Internal server error")).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/GenericExceptionMapper.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/GenericExceptionMapper.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/GenericExceptionMapper.java
new file mode 100644
index 0000000..684bd2e
--- /dev/null
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/GenericExceptionMapper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.stratos.rest.endpoint.handlers;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.rest.endpoint.Utils;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+/*This class maps any exception thrown by the server, which is not mapped by a specifi exception mapper
+* in to an appropriate format
+* */
+public class GenericExceptionMapper implements ExceptionMapper<WebApplicationException> {
+    private static Log log = LogFactory.getLog(GenericExceptionMapper.class);
+
+    public Response toResponse(WebApplicationException webApplicationException) {
+        if(log.isDebugEnabled()){
+            log.debug("Internal erver error", webApplicationException);
+        }
+        // if no specific error message specified, spitting out a generaic error message
+        String errorMessage = (webApplicationException.getMessage() != null)?
+                webApplicationException.getMessage():"Internal server error";
+        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).type(MediaType.APPLICATION_JSON).
+                entity(Utils.buildMessage(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), errorMessage)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/StratosAuthenticationHandler.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/StratosAuthenticationHandler.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/StratosAuthenticationHandler.java
index 7e66e6e..bfa676f 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/StratosAuthenticationHandler.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/handlers/StratosAuthenticationHandler.java
@@ -18,6 +18,10 @@
  */
 package org.apache.stratos.rest.endpoint.handlers;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.cxf.configuration.security.AuthorizationPolicy;
@@ -63,32 +67,45 @@ public class StratosAuthenticationHandler extends AbstractAuthenticationAuthoriz
      * @return
      */
     public Response handle(Message message, ClassResourceInfo classResourceInfo) {
+    	// If Mutual SSL is enabled
+        HttpServletRequest request = (HttpServletRequest) message.get("HTTP.REQUEST");
+        Object certObject = request.getAttribute("javax.servlet.request.X509Certificate");
+        
         AuthorizationPolicy policy = (AuthorizationPolicy) message.get(AuthorizationPolicy.class);
         String username = policy.getUserName().trim();
         String password = policy.getPassword().trim();
 
         //sanity check
-        if ((username == null) || (password == null) || username.equals("")
-                || password.equals("")) {
-            log.error("username or password is seen as null/empty values.");
-            return Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic").
-                    type(MediaType.APPLICATION_JSON).entity(Utils.buildMessage("Username/Password cannot be null")).build();
+        if ((username == null) || username.equals("")) {
+            log.error("username is seen as null/empty values.");
+            return Response.status(Response.Status.UNAUTHORIZED)
+                           .header("WWW-Authenticate", "Basic").type(MediaType.APPLICATION_JSON)
+                           .entity(Utils.buildMessage("Username cannot be null")).build();
+        } else if (certObject == null && ((password == null) || password.equals(""))) {
+            log.error("password is seen as null/empty values.");
+            return Response.status(Response.Status.UNAUTHORIZED)
+                           .header("WWW-Authenticate", "Basic").type(MediaType.APPLICATION_JSON)
+                           .entity(Utils.buildMessage("password cannot be null")).build();
         }
+        
         try {
             RealmService realmService = ServiceHolder.getRealmService();
             RegistryService registryService = ServiceHolder.getRegistryService();
             String tenantDomain = MultitenantUtils.getTenantDomain(username);
             int tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
-
-            UserRealm userRealm = AnonymousSessionUtil.getRealmByTenantDomain(registryService, realmService, tenantDomain);
-            if (userRealm == null) {
-                log .error("Invalid domain or unactivated tenant login");
-                // is this the correct HTTP code for this scenario ? (401)
-                return Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic").
-                        type(MediaType.APPLICATION_JSON).entity(Utils.buildMessage("Tenant not found")).build();
+            
+            UserRealm userRealm = null;
+            if (certObject == null) {
+                userRealm = AnonymousSessionUtil.getRealmByTenantDomain(registryService, realmService, tenantDomain);
+                if (userRealm == null) {
+                    log .error("Invalid domain or unactivated tenant login");
+                    // is this the correct HTTP code for this scenario ? (401)
+                    return Response.status(Response.Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic").
+                            type(MediaType.APPLICATION_JSON).entity(Utils.buildMessage("Tenant not found")).build();
+                }
             }
             username = MultitenantUtils.getTenantAwareUsername(username);
-            if (userRealm.getUserStoreManager().authenticate(username, password)) {  // if authenticated
+            if (certObject != null || userRealm.getUserStoreManager().authenticate(username, password)) {  // if authenticated
 
                 // setting the correct tenant info for downstream code..
                 PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/MockContext.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/MockContext.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/MockContext.java
index abd0a59..8ce6f68 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/MockContext.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/MockContext.java
@@ -21,21 +21,29 @@ package org.apache.stratos.rest.endpoint.mock;
 import org.apache.stratos.common.beans.TenantInfoBean;
 import org.apache.stratos.manager.dto.Cartridge;
 import org.apache.stratos.manager.dto.SubscriptionInfo;
+import org.apache.stratos.manager.subscription.SubscriptionDomain;
 import org.apache.stratos.rest.endpoint.bean.CartridgeInfoBean;
 import org.apache.stratos.rest.endpoint.bean.StratosAdminResponse;
+import org.apache.stratos.rest.endpoint.bean.SubscriptionDomainRequest;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.Partition;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.PartitionGroup;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.autoscale.AutoscalePolicy;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.deployment.DeploymentPolicy;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.CartridgeDefinitionBean;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.ServiceDefinitionBean;
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
 import org.apache.stratos.rest.endpoint.bean.topology.Cluster;
+import org.apache.stratos.rest.endpoint.bean.util.converter.PojoConverter;
 import org.apache.stratos.rest.endpoint.exception.RestAPIException;
 
 import java.util.*;
 
+import javax.ws.rs.core.Response.Status;
+
 public class MockContext {
     private static MockContext mockContext = new MockContext(); // singleton
+    private Map<String, List<SubscriptionDomain>> subscriptionAliasToDomainMap = new HashMap<String, List<SubscriptionDomain>>();
+    private Map<Integer, List<String>> tenantIdToAliasesMap = new HashMap<Integer, List<String>>();
     private List<CartridgeDefinitionBean> cartridgeDefinitionBeanList = new LinkedList<CartridgeDefinitionBean>();
     private Map<String,Cartridge> availableSingleTenantCartridges = new HashMap<String,Cartridge>();
     private Map<String,Cartridge> availableMultiTenantCartridges = new HashMap<String,Cartridge>();
@@ -383,4 +391,84 @@ public class MockContext {
         return deploymentPolicyMap.values().toArray(new DeploymentPolicy[0]);
     }
 
+	public StratosAdminResponse addSubscriptionDomains(int tenantId, String alias, SubscriptionDomainRequest request) {
+		// populate new alias
+		List<String> aliasList;
+		if(tenantIdToAliasesMap.containsKey(tenantId)) {
+			aliasList = tenantIdToAliasesMap.get(tenantId);
+		} else {
+			aliasList = new ArrayList<String>();
+		}
+		aliasList.add(alias);
+		tenantIdToAliasesMap.put(tenantId, aliasList);
+		
+		// populate domains
+		List<SubscriptionDomain> list;
+		if(subscriptionAliasToDomainMap.containsKey(alias)) {
+			list = subscriptionAliasToDomainMap.get(alias);
+		} else {
+			list = new ArrayList<SubscriptionDomain>();
+		}
+		for (org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean bean : request.domains) {
+			
+			SubscriptionDomain subscriptionDomain = new SubscriptionDomain(bean.domainName, bean.applicationContext);
+			list.add(subscriptionDomain);
+		}
+		
+		subscriptionAliasToDomainMap.put(alias, list);
+		
+		StratosAdminResponse stratosAdminResponse = new StratosAdminResponse();
+        stratosAdminResponse.setMessage("Successfully added subscription domain/s.");
+        return stratosAdminResponse;
+	}
+
+	public List<SubscriptionDomainBean> getSubscriptionDomains(int tenantId, String alias) {
+		List<String> tenantAliases = tenantIdToAliasesMap.get(tenantId);
+		if(tenantAliases != null && tenantAliases.contains(alias)) {
+			
+			return PojoConverter.populateSubscriptionDomainPojos(subscriptionAliasToDomainMap.get(alias));
+		}
+        return new ArrayList<SubscriptionDomainBean>();
+	}
+
+	public SubscriptionDomainBean getSubscriptionDomain(int tenantId, String cartridgeType,
+			String subscriptionAlias, String domainName) throws RestAPIException {
+		List<String> tenantAliases = tenantIdToAliasesMap.get(tenantId);
+		if(tenantAliases != null && tenantAliases.contains(subscriptionAlias)) {
+			for (SubscriptionDomain subscriptionDomain : subscriptionAliasToDomainMap.get(subscriptionAlias)) {
+				if(subscriptionDomain.getDomainName().equals(domainName)) {
+					
+					return PojoConverter.populateSubscriptionDomainPojo(subscriptionDomain);
+				}
+			}
+		}
+
+		String message = "Could not find a subscription [domain] " + domainName
+				+ " for Cartridge [type] " + cartridgeType + " and [alias] "
+				+ subscriptionAlias;
+		throw new RestAPIException(Status.NOT_FOUND, message);
+	}
+
+	public StratosAdminResponse removeSubscriptionDomain(int tenantId,
+			String subscriptionAlias, String domainName) {
+		StratosAdminResponse stratosAdminResponse = new StratosAdminResponse();
+		
+		List<String> tenantAliases = tenantIdToAliasesMap.get(tenantId);
+		if(tenantAliases != null && tenantAliases.contains(subscriptionAlias)) {
+			for (Iterator<SubscriptionDomain> iterator = subscriptionAliasToDomainMap.get(subscriptionAlias).iterator(); iterator
+					.hasNext();) {
+				SubscriptionDomain subscriptionDomain = (SubscriptionDomain) iterator.next();
+				if (subscriptionDomain.getDomainName().equals(domainName)) {
+					iterator.remove();
+					stratosAdminResponse.setMessage("Successfully removed the subscription domain: "+domainName);
+				}
+			}
+		} else {
+			
+			stratosAdminResponse.setMessage("Failed to remove the subscription domain: "+domainName);
+		}
+		
+        return stratosAdminResponse;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/StratosTestAdmin.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/StratosTestAdmin.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/StratosTestAdmin.java
index 6880bab..5302dab 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/StratosTestAdmin.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/mock/StratosTestAdmin.java
@@ -18,26 +18,30 @@
  */
 package org.apache.stratos.rest.endpoint.mock;
 
-import org.apache.catalina.tribes.membership.McastService;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.common.beans.TenantInfoBean;
 import org.apache.stratos.manager.dto.Cartridge;
 import org.apache.stratos.manager.dto.SubscriptionInfo;
 import org.apache.stratos.manager.exception.ADCException;
+import org.apache.stratos.manager.subscription.SubscriptionDomain;
 import org.apache.stratos.rest.endpoint.Utils;
 import org.apache.stratos.rest.endpoint.annotation.AuthorizationAction;
 import org.apache.stratos.rest.endpoint.annotation.SuperTenantService;
 import org.apache.stratos.rest.endpoint.bean.CartridgeInfoBean;
 import org.apache.stratos.rest.endpoint.bean.StratosAdminResponse;
+import org.apache.stratos.rest.endpoint.bean.SubscriptionDomainRequest;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.Partition;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.PartitionGroup;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.autoscale.AutoscalePolicy;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.deployment.DeploymentPolicy;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.CartridgeDefinitionBean;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.ServiceDefinitionBean;
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
 import org.apache.stratos.rest.endpoint.bean.topology.Cluster;
 import org.apache.stratos.rest.endpoint.exception.RestAPIException;
+import org.apache.stratos.rest.endpoint.services.ServiceUtils;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
@@ -465,6 +469,46 @@ public class StratosTestAdmin {
         return MockContext.getInstance().getDeploymentPoliciesForCartridgeType(cartridgeType);
     }
 
+    @POST
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public StratosAdminResponse addSubscriptionDomains(@PathParam("cartridgeType") String cartridgeType,
+                                                      @PathParam("subscriptionAlias") String subscriptionAlias,
+                                                      SubscriptionDomainRequest request) throws RestAPIException {
+
+        return MockContext.getInstance().addSubscriptionDomains(2, subscriptionAlias, request);
+    }
+
+    @GET
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public SubscriptionDomainBean[] getSubscriptionDomains(@PathParam("cartridgeType") String cartridgeType,
+                                           @PathParam("subscriptionAlias") String subscriptionAlias) throws RestAPIException {
+
+        return MockContext.getInstance().getSubscriptionDomains(2, subscriptionAlias).toArray(new SubscriptionDomainBean[0]);
+    }
 
+    @GET
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains/{domainName}")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public SubscriptionDomainBean getSubscriptionDomain(@PathParam("cartridgeType") String cartridgeType,
+            @PathParam("subscriptionAlias") String subscriptionAlias, @PathParam("domainName") String domainName) throws RestAPIException {
+
+        return MockContext.getInstance().getSubscriptionDomain(2, cartridgeType, subscriptionAlias, domainName);
+    }
+
+    @DELETE
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains/{domainName}")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public StratosAdminResponse removeSubscriptionDomain(@PathParam("cartridgeType") String cartridgeType,
+                                                         @PathParam("subscriptionAlias") String subscriptionAlias,
+                                                         @PathParam("domainName") String domainName) throws RestAPIException {
+
+        return MockContext.getInstance().removeSubscriptionDomain(2, subscriptionAlias, domainName);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/ServiceUtils.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/ServiceUtils.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/ServiceUtils.java
index 44b2c26..7f468d7 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/ServiceUtils.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/ServiceUtils.java
@@ -20,6 +20,7 @@ package org.apache.stratos.rest.endpoint.services;
 
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.context.ConfigurationContext;
+import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.autoscaler.deployment.policy.DeploymentPolicy;
@@ -44,6 +45,7 @@ import org.apache.stratos.manager.subscription.CartridgeSubscription;
 import org.apache.stratos.manager.subscription.DataCartridgeSubscription;
 import org.apache.stratos.manager.subscription.PersistenceContext;
 import org.apache.stratos.manager.subscription.SubscriptionData;
+import org.apache.stratos.manager.subscription.SubscriptionDomain;
 import org.apache.stratos.manager.topology.model.TopologyClusterInformationModel;
 import org.apache.stratos.manager.utils.ApplicationManagementUtil;
 import org.apache.stratos.manager.utils.CartridgeConstants;
@@ -54,16 +56,19 @@ import org.apache.stratos.messaging.message.receiver.topology.TopologyManager;
 import org.apache.stratos.messaging.util.Constants;
 import org.apache.stratos.rest.endpoint.bean.CartridgeInfoBean;
 import org.apache.stratos.rest.endpoint.bean.StratosAdminResponse;
+import org.apache.stratos.rest.endpoint.bean.SubscriptionDomainRequest;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.Partition;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.PartitionGroup;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.autoscale.AutoscalePolicy;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.CartridgeDefinitionBean;
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.ServiceDefinitionBean;
 import org.apache.stratos.rest.endpoint.bean.repositoryNotificationInfoBean.Payload;
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
 import org.apache.stratos.rest.endpoint.bean.util.converter.PojoConverter;
 import org.apache.stratos.rest.endpoint.exception.RestAPIException;
 
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 
 import java.rmi.RemoteException;
 import java.util.*;
@@ -575,6 +580,7 @@ public class ServiceUtils {
                     //cartridge.setStatus(CartridgeConstants.NOT_SUBSCRIBED);
                     cartridge.setCartridgeAlias("-");
                     cartridge.setPersistence(cartridgeInfo.getPersistence());
+                    cartridge.setServiceGroup(cartridgeInfo.getServiceGroup());
 
                     if(cartridgeInfo.getLbConfig() != null && cartridgeInfo.getProperties() != null) {
                         for(Property property: cartridgeInfo.getProperties()) {
@@ -718,7 +724,7 @@ public class ServiceUtils {
         return availableMultitenantCartridges;
     }
 
-	static List<Cartridge> getSubscriptions (String cartridgeSearchString, ConfigurationContext configurationContext) throws RestAPIException {
+	static List<Cartridge> getSubscriptions (String cartridgeSearchString, String serviceGroup, ConfigurationContext configurationContext) throws RestAPIException {
 
         List<Cartridge> cartridges = new ArrayList<Cartridge>();
 
@@ -762,6 +768,10 @@ public class ServiceUtils {
                     // Ignoring the LB cartridges since they are not shown to the user.
                     if(cartridge.isLoadBalancer())
                         continue;
+                    if(StringUtils.isNotEmpty(serviceGroup) && cartridge.getServiceGroup() != null &&
+                    		!cartridge.getServiceGroup().equals(serviceGroup)){
+                        continue;
+                    }
                     cartridges.add(cartridge);
                 }
             } else {
@@ -894,7 +904,9 @@ public class ServiceUtils {
                     }
                 }
             }
-			
+            if(subscription.getCartridgeInfo().getServiceGroup() != null) {
+            	cartridge.setServiceGroup(subscription.getCartridgeInfo().getServiceGroup());
+            }
 			return cartridge;
 			
 		} catch (Exception e) {
@@ -992,6 +1004,7 @@ public class ServiceUtils {
         subscriptionData.setRepositoryPassword(cartridgeInfoBean.getRepoPassword());
         subscriptionData.setCommitsEnabled(cartridgeInfoBean.isCommitsEnabled());
         subscriptionData.setServiceGroup(cartridgeInfoBean.getServiceGroup());
+        //subscriptionData.setServiceName(cartridgeInfoBean.getServiceName()); // For MT cartridges
         
         if (cartridgeInfoBean.isPersistanceRequired()) {
             // Add persistence related properties to PersistenceContext
@@ -1050,6 +1063,22 @@ public class ServiceUtils {
         return arrCluster;
 
     }
+    
+	public static org.apache.stratos.rest.endpoint.bean.topology.Cluster[] getClustersForCartridgeType(String cartridgeType) {
+
+		Set<Cluster> clusterSet = TopologyClusterInformationModel
+				.getInstance()
+				.getClusters(cartridgeType);
+		List<org.apache.stratos.rest.endpoint.bean.topology.Cluster> clusters = new ArrayList<org.apache.stratos.rest.endpoint.bean.topology.Cluster>();
+		for (Cluster cluster : clusterSet) {
+			clusters.add(PojoConverter.populateClusterPojos(cluster));
+		}
+		org.apache.stratos.rest.endpoint.bean.topology.Cluster[] arrCluster = new org.apache.stratos.rest.endpoint.bean.topology.Cluster[clusters
+				.size()];
+		arrCluster = clusters.toArray(arrCluster);
+		return arrCluster;
+
+	}
 
     // return the cluster id for the lb. This is a temp fix.
     /*private static String subscribeToLb(String cartridgeType, String loadBalancedCartridgeType, String lbAlias,
@@ -1187,4 +1216,101 @@ public class ServiceUtils {
         return stratosAdminResponse;
     }
 
+    public static StratosAdminResponse addSubscriptionDomains(ConfigurationContext configurationContext, String cartridgeType,
+                                                             String subscriptionAlias, 
+                                                             SubscriptionDomainRequest request) 
+                                                            		 throws RestAPIException {
+        try {
+            int tenantId = ApplicationManagementUtil.getTenantId(configurationContext);
+
+            for (org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean subscriptionDomain : request.domains) {
+                boolean isDomainExists = isSubscriptionDomainExists(configurationContext, cartridgeType, subscriptionAlias, subscriptionDomain.domainName);
+                if (isDomainExists) {
+                    String message = "Subscription domain " + subscriptionDomain.domainName + " exists";
+                    throw new RestAPIException(Status.INTERNAL_SERVER_ERROR, message);
+                }
+            }
+
+            for (org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean subscriptionDomain : request.domains) {
+                cartridgeSubsciptionManager.addSubscriptionDomain(tenantId, subscriptionAlias,
+            			subscriptionDomain.domainName, subscriptionDomain.applicationContext);
+			}
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RestAPIException(e.getMessage(), e);
+        }
+
+        StratosAdminResponse stratosAdminResponse = new StratosAdminResponse();
+        stratosAdminResponse.setMessage("Successfully added domains to cartridge subscription");
+        return stratosAdminResponse;
+    }
+
+    public static boolean isSubscriptionDomainExists(ConfigurationContext configurationContext, String cartridgeType,
+                                                     String subscriptionAlias, String domain) throws RestAPIException {
+        try {
+            int tenantId = ApplicationManagementUtil.getTenantId(configurationContext);
+            SubscriptionDomainBean subscriptionDomain = PojoConverter.populateSubscriptionDomainPojo(cartridgeSubsciptionManager.getSubscriptionDomain(tenantId,
+                    subscriptionAlias, domain));
+
+            if (subscriptionDomain.domainName != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RestAPIException(e.getMessage(), e);
+        }
+
+    }
+
+    public static List<SubscriptionDomainBean> getSubscriptionDomains(ConfigurationContext configurationContext, String cartridgeType,
+                                                      String subscriptionAlias) throws RestAPIException {
+        try {
+            int tenantId = ApplicationManagementUtil.getTenantId(configurationContext);
+            return PojoConverter.populateSubscriptionDomainPojos(cartridgeSubsciptionManager.getSubscriptionDomains(tenantId, subscriptionAlias));
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RestAPIException(e.getMessage(), e);
+        }
+    }
+    
+	public static SubscriptionDomainBean getSubscriptionDomain(ConfigurationContext configurationContext, String cartridgeType,
+			String subscriptionAlias, String domain) throws RestAPIException {
+		try {
+			int tenantId = ApplicationManagementUtil
+					.getTenantId(configurationContext);
+			SubscriptionDomainBean subscriptionDomain = PojoConverter.populateSubscriptionDomainPojo(cartridgeSubsciptionManager.getSubscriptionDomain(tenantId,
+					subscriptionAlias, domain));
+			
+			if (subscriptionDomain == null) {
+				String message = "Could not find a subscription [domain] "+domain+ " for Cartridge [type] "
+							+cartridgeType+ " and [alias] "+subscriptionAlias;
+				log.error(message);
+				throw new RestAPIException(Status.NOT_FOUND, message);
+			}
+			
+			return subscriptionDomain;
+			
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+			throw new RestAPIException(e.getMessage(), e);
+		}
+	}
+
+    public static StratosAdminResponse removeSubscriptionDomain(ConfigurationContext configurationContext, String cartridgeType,
+                                                                String subscriptionAlias, String domain) throws RestAPIException {
+        try {
+            int tenantId = ApplicationManagementUtil.getTenantId(configurationContext);
+            cartridgeSubsciptionManager.removeSubscriptionDomain(tenantId, subscriptionAlias, domain);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RestAPIException(e.getMessage(), e);
+        }
+
+        StratosAdminResponse stratosAdminResponse = new StratosAdminResponse();
+        stratosAdminResponse.setMessage("Successfully removed domains from cartridge subscription");
+        return stratosAdminResponse;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/StratosAdmin.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/StratosAdmin.java b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/StratosAdmin.java
index 7b744a5..63d713f 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/StratosAdmin.java
+++ b/components/org.apache.stratos.rest.endpoint/src/main/java/org/apache/stratos/rest/endpoint/services/StratosAdmin.java
@@ -18,6 +18,7 @@
  */
 package org.apache.stratos.rest.endpoint.services;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.common.beans.TenantInfoBean;
@@ -27,12 +28,14 @@ import org.apache.stratos.common.util.CommonUtil;
 import org.apache.stratos.manager.dto.Cartridge;
 import org.apache.stratos.manager.dto.SubscriptionInfo;
 import org.apache.stratos.manager.subscription.CartridgeSubscription;
+import org.apache.stratos.manager.subscription.SubscriptionDomain;
 import org.apache.stratos.rest.endpoint.ServiceHolder;
 import org.apache.stratos.rest.endpoint.Utils;
 import org.apache.stratos.rest.endpoint.annotation.AuthorizationAction;
 import org.apache.stratos.rest.endpoint.annotation.SuperTenantService;
 import org.apache.stratos.rest.endpoint.bean.CartridgeInfoBean;
 import org.apache.stratos.rest.endpoint.bean.StratosAdminResponse;
+import org.apache.stratos.rest.endpoint.bean.SubscriptionDomainRequest;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.Partition;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.partition.PartitionGroup;
 import org.apache.stratos.rest.endpoint.bean.autoscaler.policy.autoscale.AutoscalePolicy;
@@ -41,6 +44,7 @@ import org.apache.stratos.rest.endpoint.bean.cartridge.definition.CartridgeDefin
 import org.apache.stratos.rest.endpoint.bean.cartridge.definition.ServiceDefinitionBean;
 import org.apache.stratos.rest.endpoint.bean.repositoryNotificationInfoBean.Payload;
 import org.apache.stratos.rest.endpoint.bean.repositoryNotificationInfoBean.Repository;
+import org.apache.stratos.rest.endpoint.bean.subscription.domain.SubscriptionDomainBean;
 import org.apache.stratos.rest.endpoint.bean.topology.Cluster;
 import org.apache.stratos.rest.endpoint.exception.RestAPIException;
 import org.apache.stratos.tenant.mgt.core.TenantPersistor;
@@ -79,6 +83,7 @@ public class StratosAdmin extends AbstractAdmin {
     public StratosAdminResponse initialize ()
             throws RestAPIException {
 
+
         StratosAdminResponse stratosAdminResponse = new StratosAdminResponse();
         stratosAdminResponse.setMessage("Successfully logged in");
         return stratosAdminResponse;
@@ -309,7 +314,18 @@ public class StratosAdmin extends AbstractAdmin {
     @Consumes("application/json")
     @AuthorizationAction("/permission/protected/manage/monitor/tenants")
     public Cartridge[] getSubscribedCartridges() throws RestAPIException {
-        List<Cartridge> cartridgeList = ServiceUtils.getSubscriptions(null, getConfigContext());
+        List<Cartridge> cartridgeList = ServiceUtils.getSubscriptions(null, null, getConfigContext());
+        // Following is very important when working with axis2
+        return cartridgeList.isEmpty() ? new Cartridge[0] : cartridgeList.toArray(new Cartridge[cartridgeList.size()]);
+    }
+
+    @GET
+    @Path("/cartridge/list/subscribed/group/{serviceGroup}")
+    @Produces("application/json")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Cartridge[] getSubscribedCartridgesForServiceGroup(@PathParam("serviceGroup") String serviceGroup) throws RestAPIException {
+        List<Cartridge> cartridgeList = ServiceUtils.getSubscriptions(null, serviceGroup, getConfigContext());
         // Following is very important when working with axis2
         return cartridgeList.isEmpty() ? new Cartridge[0] : cartridgeList.toArray(new Cartridge[cartridgeList.size()]);
     }
@@ -382,6 +398,15 @@ public class StratosAdmin extends AbstractAdmin {
     @Consumes("application/json")
     @AuthorizationAction("/permission/protected/manage/monitor/tenants")
     public Cluster[] getClusters(@PathParam("cartridgeType") String cartridgeType) throws RestAPIException {
+        return ServiceUtils.getClustersForCartridgeType(cartridgeType);
+    }
+    
+    @GET
+    @Path("/cluster/service/{cartridgeType}/")
+    @Produces("application/json")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Cluster[] getServiceClusters(@PathParam("cartridgeType") String cartridgeType) throws RestAPIException {
 
         return ServiceUtils.getClustersForTenantAndCartridgeType(getConfigContext(), cartridgeType);
     }
@@ -405,7 +430,7 @@ public class StratosAdmin extends AbstractAdmin {
     public Cluster getCluster(@PathParam("clusterId") String clusterId) throws RestAPIException {
     	Cluster cluster = null;
     	if(log.isDebugEnabled()) {
-    		log.debug("Finding the Cluster for [id]: "+clusterId);
+            log.debug("Finding cluster for [id]: "+clusterId);
     	}
         Cluster[] clusters = ServiceUtils.getClustersForTenant(getConfigContext());
         if(log.isDebugEnabled()) {
@@ -1018,4 +1043,81 @@ public class StratosAdmin extends AbstractAdmin {
         }
         return tenantList;
     }
+
+    @POST
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Response addSubscriptionDomains(@PathParam("cartridgeType") String cartridgeType,
+                                                       @PathParam("subscriptionAlias") String subscriptionAlias,
+                                                       SubscriptionDomainRequest request) throws RestAPIException {
+
+        StratosAdminResponse stratosAdminResponse = ServiceUtils.addSubscriptionDomains(getConfigContext(), cartridgeType, subscriptionAlias, request);
+        return Response.ok().entity(stratosAdminResponse).build();
+    }
+
+    @GET
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Response getSubscriptionDomains(@PathParam("cartridgeType") String cartridgeType,
+                                                           @PathParam("subscriptionAlias") String subscriptionAlias) throws RestAPIException {
+        SubscriptionDomainBean[] subscriptionDomainBean = ServiceUtils.getSubscriptionDomains(getConfigContext(), cartridgeType, subscriptionAlias).toArray(new SubscriptionDomainBean[0]);
+
+        if(subscriptionDomainBean.length == 0){
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }else{
+            return Response.ok().entity(subscriptionDomainBean).build();
+        }
+    }
+
+    @GET
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains/{domainName}")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Response getSubscriptionDomain(@PathParam("cartridgeType") String cartridgeType,
+                                                        @PathParam("subscriptionAlias") String subscriptionAlias, @PathParam("domainName") String domainName) throws RestAPIException {
+        SubscriptionDomainBean subscriptionDomainBean = ServiceUtils.getSubscriptionDomain(getConfigContext(), cartridgeType, subscriptionAlias, domainName);
+        if(subscriptionDomainBean.domainName == null){
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }else{
+            return Response.ok().entity(subscriptionDomainBean).build();
+        }
+    }
+
+    @DELETE
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/domains/{domainName}")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public StratosAdminResponse removeSubscriptionDomain(@PathParam("cartridgeType") String cartridgeType,
+                                                         @PathParam("subscriptionAlias") String subscriptionAlias,
+                                                         @PathParam("domainName") String domainName) throws RestAPIException {
+        return ServiceUtils.removeSubscriptionDomain(getConfigContext(), cartridgeType, subscriptionAlias, domainName);
+    }
+
+    @GET
+    @Path("/cartridge/{cartridgeType}/subscription/{subscriptionAlias}/load-balancer-cluster")
+    @Consumes("application/json")
+    @AuthorizationAction("/permission/protected/manage/monitor/tenants")
+    public Response getLoadBalancerCluster(@PathParam("cartridgeType") String cartridgeType,
+                                           @PathParam("subscriptionAlias") String subscriptionAlias) throws RestAPIException {
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("GET /cartridge/%s/subscription/%s/load-balancer-cluster", cartridgeType, subscriptionAlias));
+        }
+        Cartridge subscription = ServiceUtils.getSubscription(subscriptionAlias, getConfigContext());
+        String lbClusterId = subscription.getLbClusterId();
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("Load balancer cluster-id found: %s", lbClusterId));
+        }
+        if (StringUtils.isNotBlank(lbClusterId)) {
+            Cluster lbCluster = getCluster(lbClusterId);
+            if (lbCluster != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug(String.format("Load balancer cluster found: %s", lbCluster.toString()));
+                }
+                Response.ok().entity(lbCluster).build();
+            }
+        }
+        return Response.status(Response.Status.NOT_FOUND).build();
+    }
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/7b35e29e/components/org.apache.stratos.rest.endpoint/src/main/webapp/stratos-test/WEB-INF/cxf-servlet.xml
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.rest.endpoint/src/main/webapp/stratos-test/WEB-INF/cxf-servlet.xml b/components/org.apache.stratos.rest.endpoint/src/main/webapp/stratos-test/WEB-INF/cxf-servlet.xml
index 552cad7..f8b8750 100644
--- a/components/org.apache.stratos.rest.endpoint/src/main/webapp/stratos-test/WEB-INF/cxf-servlet.xml
+++ b/components/org.apache.stratos.rest.endpoint/src/main/webapp/stratos-test/WEB-INF/cxf-servlet.xml
@@ -31,6 +31,7 @@
         </jaxrs:serviceBeans>
 
         <jaxrs:providers>
+			<ref bean="throwableExceptionHandler"/>
             <bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
                 <property name="dropRootElement" value="true"/>
                 <property name="supportUnwrapped" value="true"/>
@@ -41,4 +42,5 @@
 
     <bean id="stratosRestEndpointTestBean" class="org.apache.stratos.rest.endpoint.mock.StratosTestAdmin"/>
     <bean id="exceptionHandler" class="org.apache.stratos.rest.endpoint.handlers.CustomExceptionMapper"/>
+    <bean id="throwableExceptionHandler" class="org.apache.stratos.rest.endpoint.handlers.CustomThrowableExceptionMapper"/>
 </beans>