Creating a straman for allowing external tools (e.g. Nagios) to manage 'manageable' services and or resources from a tuscany domain

git-svn-id: https://svn.apache.org/repos/asf/tuscany/sca-java-2.x/trunk@1297253 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/modules/node-manager/META-INF/MANIFEST.MF b/modules/node-manager/META-INF/MANIFEST.MF
index 1e10ed6..3f03d67 100644
--- a/modules/node-manager/META-INF/MANIFEST.MF
+++ b/modules/node-manager/META-INF/MANIFEST.MF
@@ -9,8 +9,11 @@
 Bundle-ManifestVersion: 2

 Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt

 Bundle-Description: Apache Tuscany SCA Node Manager

-Import-Package: javax.ws.rs,

+Import-Package: javax.servlet;version="2.5.0",

+ javax.ws.rs,

+ javax.ws.rs.core,

  org.apache.tuscany.sca.assembly;version="2.0.0",

+ org.apache.tuscany.sca.interfacedef;version="2.0.0",

  org.apache.tuscany.sca.node;version="2.0.0",

  org.apache.tuscany.sca.node.configuration;version="2.0.0",

  org.apache.tuscany.sca.node.extensibility;version="2.0.0",

diff --git a/modules/node-manager/pom.xml b/modules/node-manager/pom.xml
index b29c97b..61e15fc 100644
--- a/modules/node-manager/pom.xml
+++ b/modules/node-manager/pom.xml
@@ -128,6 +128,25 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>        
+        
+        <dependency>
             <groupId>org.apache.tuscany.sca</groupId>
             <artifactId>tuscany-host-jetty</artifactId>
             <version>2.0-SNAPSHOT</version>
diff --git a/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResource.java b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResource.java
new file mode 100644
index 0000000..bb017a5
--- /dev/null
+++ b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResource.java
@@ -0,0 +1,43 @@
+/*
+ * 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.tuscany.sca.node.manager;
+
+import java.util.List;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+@Remotable
+public interface DomainAssetManagerResource {
+
+    @GET
+    @Path("{domainURI}/resources/status")
+    List<Status> getResourceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI);
+    
+
+    @GET
+    @Path("{domainURI}/services/status")
+    List<Status> getServiceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI);
+
+}
diff --git a/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableResource.java b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableResource.java
new file mode 100644
index 0000000..36051c3
--- /dev/null
+++ b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableResource.java
@@ -0,0 +1,41 @@
+/*
+ * 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.tuscany.sca.node.manager;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+@Remotable
+public interface ManageableResource {
+
+    /**
+     * Ping resource used for service monitoring
+     * @return
+     */
+    @GET
+    @Path("/ping")
+    @Produces(MediaType.TEXT_HTML)
+    Response ping();
+}
diff --git a/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableService.java b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableService.java
new file mode 100644
index 0000000..17ab866
--- /dev/null
+++ b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/ManageableService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.tuscany.sca.node.manager;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+@Remotable
+public interface ManageableService {
+
+    /**
+     * isAlive method that allow service to be managed
+     */
+    void isAlive();
+}
diff --git a/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/Status.java b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/Status.java
new file mode 100644
index 0000000..f20f5e1
--- /dev/null
+++ b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/Status.java
@@ -0,0 +1,85 @@
+/*
+ * 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.tuscany.sca.node.manager;
+
+public class Status {
+    public static int SUCCESS = 0;
+    public static int FAILURE = 1;
+    
+    private String name;
+    private String uri;
+    private int  status;
+    private String statusMessage;
+    private long   execution;
+    
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+    public String getStatusMessage() {
+        return statusMessage;
+    }
+
+    public void setStatusMessage(String statusMessage) {
+        this.statusMessage = statusMessage;
+    }
+
+    public long getExecution() {
+        return execution;
+    }
+
+    public void setExecution(long execution) {
+        this.execution = execution;
+    }
+
+    @Override
+    public String toString() {
+        return "Status [name=" + name
+            + ", uri="
+            + uri
+            + ", status="
+            + status
+            + ", statusMessage="
+            + statusMessage
+            + ", execution="
+            + execution
+            + "]";
+    }
+}
diff --git a/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/impl/DomainAssetManagerResourceImpl.java b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/impl/DomainAssetManagerResourceImpl.java
new file mode 100644
index 0000000..3b045b8
--- /dev/null
+++ b/modules/node-manager/src/main/java/org/apache/tuscany/sca/node/manager/impl/DomainAssetManagerResourceImpl.java
@@ -0,0 +1,215 @@
+/*
+ * 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.tuscany.sca.node.manager.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.WebApplicationException;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.binding.rest.RESTBinding;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.host.http.client.HttpClientFactory;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.extensibility.NodeActivator;
+import org.apache.tuscany.sca.node.extensibility.NodeExtension;
+import org.apache.tuscany.sca.node.manager.DomainAssetManagerResource;
+import org.apache.tuscany.sca.node.manager.ManageableResource;
+import org.apache.tuscany.sca.node.manager.ManageableService;
+import org.apache.tuscany.sca.node.manager.Status;
+import org.oasisopen.sca.annotation.Init;
+
+public class DomainAssetManagerResourceImpl implements NodeActivator, DomainAssetManagerResource {
+    private static Map<String, NodeExtension> nodeMap = new ConcurrentHashMap<String,NodeExtension>();
+    
+    private HttpClientFactory httpClientFactory;
+
+    public void nodeStarted(Node node) {
+        NodeExtension nodeExtension = (NodeExtension) node;
+        nodeMap.put(nodeExtension.getDomainURI(), nodeExtension);     
+    }
+
+    public void nodeStopped(Node node) {
+        NodeExtension nodeExtension = (NodeExtension) node;
+        nodeMap.remove(nodeExtension.getDomainURI());
+    }
+    
+    @Init
+    public void init() {
+        NodeExtension node = (NodeExtension) nodeMap.values().iterator().next();
+        if(node != null) {
+            ExtensionPointRegistry extensionPoints =  node.getExtensionPointRegistry();
+            FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class);
+            this.httpClientFactory = HttpClientFactory.getInstance(extensionPoints);
+        }
+    }
+    
+    @Override
+    public List<Status> getResourceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI) {
+        if( ! nodeMap.containsKey(domainURI)) {
+            throw new WebApplicationException(404);
+        }
+        
+        NodeExtension node = nodeMap.get(domainURI);
+        Composite domainComposite = node.getDomainComposite();
+        
+        List<Status> statuses = new ArrayList<Status>();
+        for(Component component : domainComposite.getComponents()) {
+            for(Service service : component.getServices()) {
+                Interface interfaceContract = service.getInterfaceContract().getInterface();
+                if(ManageableResource.class.getName().equals(interfaceContract.toString())) {
+                    Binding binding = service.getBinding(RESTBinding.class);
+                    if(binding != null) {
+                        
+                        Status status = new Status();
+                        status.setName(component.getName());
+                        status.setUri(binding.getURI());
+                        
+                        try {
+                            Timer t = new Timer();
+                            status = testResource(status);
+                            status.setExecution(t.elapsed(TimeUnit.MILLISECONDS));
+                            status.setStatus(Status.SUCCESS);
+                        } catch (Exception e) {
+                            status.setStatus(Status.FAILURE);
+                            status.setStatusMessage(e.getMessage());
+                        }
+                        
+                        statuses.add(status);
+                    }
+                }
+            }
+            
+        }
+        return statuses;
+    }
+
+    @Override
+    public List<Status> getServiceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI) {
+        if( ! nodeMap.containsKey(domainURI)) {
+            throw new WebApplicationException(404);
+        }
+
+        NodeExtension node = nodeMap.get(domainURI);
+        Composite domainComposite = node.getDomainComposite();
+
+        List<Status> statuses = new ArrayList<Status>();
+        for(Component component : domainComposite.getComponents()) {
+            for(Service service : component.getServices()) {
+                Interface interfaceContract = service.getInterfaceContract().getInterface();
+                if(ManageableService.class.getName().equals(interfaceContract.toString())) {
+
+                    Status status = new Status();
+                    status.setName(component.getName());
+                    status.setUri(service.getBindings().get(0).getURI());
+                    
+                    try {
+                        String serviceName = component.getName() +"/" + service.getName();
+                        ManageableService serviceInstance = node.getService(ManageableService.class, component.getName());
+                        Timer t = new Timer();
+                        serviceInstance.isAlive();
+                        status.setExecution(t.elapsed(TimeUnit.MILLISECONDS));
+                        status.setStatus(Status.SUCCESS);
+                    } catch (Exception e) {
+                        status.setStatus(Status.FAILURE);
+                        status.setStatusMessage(e.getMessage());
+                    }
+                    
+                    statuses.add(status);
+                }
+            }
+        }
+        
+        return statuses;
+    }
+    
+    
+    private Status testResource(Status status) throws IOException {
+        
+        // Create an HTTP client
+        HttpClient httpClient = httpClientFactory.createHttpClient();
+        
+        HttpGet request = new HttpGet(status.getUri() + "ping");
+        //request.addHeader("Accept","application/json");
+        HttpResponse response = httpClient.execute(request);
+        
+        if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+            throw new IOException("Error invoking service at '" + request.getURI() +"' => " + response.getStatusLine().getReasonPhrase());
+        }
+        
+        if (httpClient != null) {
+            httpClient.getConnectionManager().shutdown();
+        }
+        
+        return status;
+    }
+    
+    
+    class Timer {
+        Date time;
+        long t;
+
+        public Timer() {
+            reset();
+        }
+
+        public void reset() {
+            time = new Date();
+            t = System.nanoTime();
+        }
+
+        public Date time() {
+            return time; 
+        }
+        
+        public long elapsed(TimeUnit timeUnit) {
+            long elapsedTime = elapsed();
+            return timeUnit.convert(elapsedTime, TimeUnit.NANOSECONDS);
+        }
+
+        public void print(String s, TimeUnit timeUnit) {
+            long elapsedTime = elapsed();
+
+            System.out.println(s + ": " + timeUnit.convert(elapsedTime, TimeUnit.NANOSECONDS)  + "ms");
+        }
+        
+        private long elapsed() {
+            return System.nanoTime() - t;
+        }
+    }
+    
+}
diff --git a/modules/node-manager/src/main/resources/META-INF/services/org.apache.tuscany.sca.node.extensibility.NodeActivator b/modules/node-manager/src/main/resources/META-INF/services/org.apache.tuscany.sca.node.extensibility.NodeActivator
index 76ecb61..632f62d 100644
--- a/modules/node-manager/src/main/resources/META-INF/services/org.apache.tuscany.sca.node.extensibility.NodeActivator
+++ b/modules/node-manager/src/main/resources/META-INF/services/org.apache.tuscany.sca.node.extensibility.NodeActivator
@@ -16,3 +16,4 @@
 # under the License.
 # Implementation class for the ModuleActivator
 org.apache.tuscany.sca.node.manager.impl.DomainCompositeResourceImpl;ranking=100
+org.apache.tuscany.sca.node.manager.impl.DomainAssetManagerResourceImpl;ranking=101
diff --git a/modules/node-manager/src/test/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResourceTestCase.java b/modules/node-manager/src/test/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResourceTestCase.java
new file mode 100644
index 0000000..ded7a3a
--- /dev/null
+++ b/modules/node-manager/src/test/java/org/apache/tuscany/sca/node/manager/DomainAssetManagerResourceTestCase.java
@@ -0,0 +1,85 @@
+/*
+ * 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.tuscany.sca.node.manager;
+
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.meterware.httpunit.GetMethodWebRequest;
+import com.meterware.httpunit.WebConversation;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+
+public class DomainAssetManagerResourceTestCase {
+    private static String SERVICE_URL;
+    private static Node node;
+    
+
+    @BeforeClass
+    public static void init() throws Exception {
+        try {
+            String contribution = ContributionLocationHelper.getContributionLocation(DomainCompositeResourceTestCase.class);
+            node = NodeFactory.newInstance().createNode("node-asset-manager-test.composite", new Contribution("node-manager", contribution));
+            node.start();
+            
+            SERVICE_URL = node.getEndpointAddress("NodeAssetManagerComponent");
+            
+            System.out.println(">>" + SERVICE_URL);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @AfterClass
+    public static void destroy() throws Exception {
+        if (node != null) {
+            node.stop();
+        }
+    }
+    
+    
+    @Test
+    public void testServiceManagement() throws Exception {
+        WebConversation wc = new WebConversation();
+        WebRequest request = new GetMethodWebRequest(SERVICE_URL + "default/services/status");
+        request.setHeaderField("Accept","application/json");
+        WebResponse response = wc.getResource(request);
+
+        Assert.assertEquals(200, response.getResponseCode());
+        System.out.println(">>>" + response.getText());
+    }
+    
+    @Test
+    public void testResourceManagement() throws Exception {
+        WebConversation wc = new WebConversation();
+        WebRequest request = new GetMethodWebRequest(SERVICE_URL + "default/resources/status");
+        request.setHeaderField("Accept","application/json");
+        WebResponse response = wc.getResource(request);
+
+        Assert.assertEquals(200, response.getResponseCode());
+        System.out.println(">>>" + response.getText());
+    }    
+}
diff --git a/modules/node-manager/src/test/java/services/MyResourceImpl.java b/modules/node-manager/src/test/java/services/MyResourceImpl.java
new file mode 100644
index 0000000..ac8b84a
--- /dev/null
+++ b/modules/node-manager/src/test/java/services/MyResourceImpl.java
@@ -0,0 +1,34 @@
+/*
+ * 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 services;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.tuscany.sca.node.manager.ManageableResource;
+
+public class MyResourceImpl implements ManageableResource {
+
+    @Override
+    public Response ping() {
+        System.out.println(">>> ping");
+        return Response.ok("pong").build();
+    }
+
+}
diff --git a/modules/node-manager/src/test/java/services/MyServiceImpl.java b/modules/node-manager/src/test/java/services/MyServiceImpl.java
new file mode 100644
index 0000000..770be99
--- /dev/null
+++ b/modules/node-manager/src/test/java/services/MyServiceImpl.java
@@ -0,0 +1,32 @@
+/*
+ * 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 services;
+
+import org.apache.tuscany.sca.node.manager.ManageableService;
+
+public class MyServiceImpl implements ManageableService {
+
+ 
+    @Override
+    public void isAlive() {
+        System.out.println(">>> isAlive");
+    }
+
+}
diff --git a/modules/node-manager/src/test/resources/node-asset-manager-test.composite b/modules/node-manager/src/test/resources/node-asset-manager-test.composite
new file mode 100644
index 0000000..c3eeba8
--- /dev/null
+++ b/modules/node-manager/src/test/resources/node-asset-manager-test.composite
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite	xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+		xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
+		targetNamespace="http://node-manager"
+		name="NodeAssetManager">
+
+	<component name="NodeAssetManagerComponent">
+		<implementation.java class="org.apache.tuscany.sca.node.manager.impl.DomainAssetManagerResourceImpl"/>
+		<service name="DomainAssetManagerResource">
+			<tuscany:binding.rest uri="/services/manager" />
+   		</service>
+	</component>
+	
+	<component name="Resource">
+		<implementation.java class="services.MyResourceImpl"/>
+		<service name="ManageableResource">
+			<tuscany:binding.rest uri="/services/resource" />
+   		</service>
+	</component>
+
+    <!-- -->
+	<component name="AnotherResource">
+		<implementation.java class="services.MyResourceImpl"/>
+		<service name="ManageableResource">
+			<tuscany:binding.rest uri="/services/another/resource" />
+   		</service>
+	</component>
+	<!-- -->
+
+	
+	<component name="Service">
+		<implementation.java class="services.MyServiceImpl"/>
+		<service name="ManageableService">
+			<binding.sca />
+   		</service>
+	</component>	
+</composite>