Add instance details

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@963391 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java
index 3151389..44260bd 100644
--- a/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java
+++ b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java
@@ -7,7 +7,9 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Enumeration;
 import java.util.List;
+import java.util.Properties;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -22,13 +24,23 @@
 import org.apache.felix.ipojo.annotations.Requires;
 import org.apache.felix.ipojo.annotations.ServiceProperty;
 import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
 import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.util.DependencyModel;
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.DefaultVariableResolver;
 import org.apache.felix.webconsole.WebConsoleUtil;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 
 @Component(immediate=true)
 @Provides
@@ -41,6 +53,8 @@
     private final String FACTORIES;
     private final String HANDLERS;
     private final String FACTORY_DETAILS;
+    private final String INSTANCE_DETAILS;
+
 
     
     /**
@@ -81,6 +95,8 @@
         FACTORIES = readTemplateFile(this.getClass(), "/res/factories.html" );
         HANDLERS = readTemplateFile(this.getClass(), "/res/handlers.html" );
         FACTORY_DETAILS = readTemplateFile(this.getClass(), "/res/factory.html" );
+        INSTANCE_DETAILS = readTemplateFile(this.getClass(), "/res/instance.html" );
+
     }
     
     private final String readTemplateFile(final Class clazz,
@@ -130,7 +146,9 @@
             if (reqInfo.name == null) {
                 response.getWriter().print( INSTANCES );
             } else {
-                // TODO
+                System.out.println("Details for " + reqInfo.name);
+                vars.put("name", reqInfo.name);
+                response.getWriter().print( INSTANCE_DETAILS );
             }
         } else if (reqInfo.factories) {
             if (reqInfo.name == null) {
@@ -324,6 +342,55 @@
         
     }
     
+    private void renderInstanceDetail(PrintWriter pw, String name) {
+        System.out.println("Render instance detail for " + name);
+        // Find the factory
+        InstanceDescription instance = null;
+        for (Architecture arch : m_archs) {
+            if (arch.getInstanceDescription().getName().equals(name)) {
+                instance = arch.getInstanceDescription();
+            }
+        }
+        
+        if (instance == null) {
+            // TODO Error management
+            System.err.println("instance " + name + "  not found");
+            return;
+        }
+        
+        try {
+            JSONObject resp = new JSONObject();
+            resp.put("count", m_factories.size());
+            resp.put("valid_count", getValidFactoriesCount());
+            resp.put("invalid_count", getInvalidFactoriesCount());
+            
+            // instance object
+            JSONObject data = new JSONObject();
+            data.put("name", instance.getName());
+            data.put("state", getInstanceState(instance.getState()));
+            data.put("factory", instance.getComponentDescription().getName());
+            
+            JSONArray services = getProvidedServiceDetail(instance.getHandlerDescription("org.apache.felix.ipojo:provides"));
+            if (services != null) {
+                data.put("services", services);
+            }
+            
+            JSONArray reqs = getRequiredServiceDetail(instance.getHandlerDescription("org.apache.felix.ipojo:requires"));
+            if (reqs != null) {
+                data.put("req", reqs);
+            }
+            
+            data.put("architecture", instance.getDescription().toString());
+            resp.put("data", data);
+            
+            pw.print(resp.toString());
+        } catch (JSONException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        
+    }
+    
     @Override
     protected void doGet(HttpServletRequest request,
             HttpServletResponse response) throws ServletException, IOException {
@@ -338,7 +405,7 @@
                     this.renderAllInstances(response.getWriter());
                     return;
                 } else {
-                    // TODO
+                    this.renderInstanceDetail(response.getWriter(), reqInfo.name);
                     return;
                 }
             }
@@ -371,6 +438,105 @@
         return null;
     }
     
+    private JSONArray getProvidedServiceDetail(HandlerDescription hd) throws JSONException {
+        if (hd == null) {
+            return null;
+        }
+
+        JSONArray array = new JSONArray();
+        ProvidedServiceHandlerDescription desc = (ProvidedServiceHandlerDescription) hd;
+
+        for (ProvidedServiceDescription ps : desc.getProvidedServices()) {
+            JSONObject svc = new JSONObject();
+            String spec = Arrays.toString(ps.getServiceSpecifications());
+            if (spec.startsWith("[")) {
+                spec = spec.substring(1, spec.length() - 1);
+            }
+            svc.put("specification", spec);
+            svc.put("state", getProvidedServiceState(ps.getState()));
+            
+            if (ps.getServiceReference() != null) {
+                svc.put("id", (Long) ps.getServiceReference().getProperty(Constants.SERVICE_ID));
+            }
+            
+            if (ps.getProperties() != null  &&!  ps.getProperties().isEmpty()) {
+                svc.put("properties", getServiceProperties(ps.getProperties()));
+            }
+
+            array.put(svc);
+        }
+        
+        return array;
+    }
+    
+    private JSONArray getServiceProperties(Properties properties) throws JSONException {
+        JSONArray array = new JSONArray();
+        Enumeration<Object> e = properties.keys();
+        while (e.hasMoreElements()) {
+            String key = (String) e.nextElement();
+            Object value = properties.get(key);
+            JSONObject prop = new JSONObject();
+            prop.put("name", key);
+            if (value != null  && value.getClass().isArray()) {
+                // TODO Test with primitive types
+                prop.put("value", Arrays.toString((Object[]) value));
+            } else if (value != null) {
+                prop.put("value", value.toString());
+            } else {
+                prop.put("value", "no value");
+            }
+            array.put(prop);
+        }
+        return array;
+    }
+    
+    private JSONArray getRequiredServiceDetail(
+            HandlerDescription hd) throws JSONException {
+        if (hd == null) {
+            return null;
+        }
+        JSONArray array = new JSONArray();
+        DependencyHandlerDescription desc = (DependencyHandlerDescription) hd;
+        for (DependencyDescription dep : desc.getDependencies()) {
+            JSONObject req = new JSONObject();
+            req.put("specification",dep.getSpecification());
+            req.put("id", dep.getId());
+            req.put("state", getDependencyState(dep.getState()));
+            req.put("policy", getDependencyBindingPolicy(dep.getPolicy()));
+            req.put("optional", dep.isOptional());
+            req.put("aggregate", dep.isMultiple());
+            //TODO Add filter support
+            if (dep.getServiceReferences() != null  && dep.getServiceReferences().size() != 0) {
+                req.put("matching",  getServiceReferenceList(dep.getServiceReferences()));
+            }
+            
+            if (dep.getUsedServices() != null  && dep.getUsedServices().size() != 0) {
+                req.put("used",  getServiceReferenceList(dep.getUsedServices()));
+            }
+            
+            array.put(req);
+        }
+
+        return array;
+    }
+    
+    private JSONArray getServiceReferenceList(List<ServiceReference> refs) throws JSONException {
+        JSONArray array = new JSONArray();
+        if (refs != null) {
+            for (ServiceReference ref : refs) {
+                JSONObject reference = new JSONObject();
+                if (ref.getProperty("instance.name") == null) {
+                    reference.put("id", ref.getProperty(Constants.SERVICE_ID));
+                } else {
+                    reference.put("id", ref.getProperty(Constants.SERVICE_ID));
+                    reference.put("instance", ref.getProperty("instance.name"));
+                }
+                array.put(reference);
+            }
+        }
+        return array;
+    }
+    
     /**
      * Gets the number of valid instances.
      * @return the number of valid instances.
@@ -562,5 +728,57 @@
     protected String[] getCssReferences() {
         return CSS;
     }
+    
+    /**
+     * Gets the dependency state as a String.
+     * @param state the state.
+     * @return the String form of the state.
+     */
+    private static String getDependencyState(int state) {
+        switch(state) {
+            case DependencyModel.RESOLVED :
+                return "resolved";
+            case DependencyModel.UNRESOLVED :
+                return "unresolved";
+            case DependencyModel.BROKEN :
+                return "broken";
+            default :
+                return "unknown (" + state + ")";
+        }
+    }
+
+    /**
+     * Gets the dependency binding policy as a String.
+     * @param policy the policy.
+     * @return the String form of the policy.
+     */
+    private static String getDependencyBindingPolicy(int policy) {
+        switch(policy) {
+            case DependencyModel.DYNAMIC_BINDING_POLICY :
+                return "dynamic";
+            case DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY :
+                return "dynamic-priority";
+            case DependencyModel.STATIC_BINDING_POLICY :
+                return "static";
+            default :
+                return "unknown (" + policy + ")";
+        }
+    }
+
+    /**
+     * Gets the provided service state as a String.
+     * @param state the state.
+     * @return the String form of the state.
+     */
+    private static String getProvidedServiceState(int state) {
+        switch(state) {
+            case ProvidedService.REGISTERED :
+                return "registered";
+            case ProvidedService.UNREGISTERED :
+                return "unregistered";
+            default :
+                return "unknown (" + state + ")";
+        }
+    }
 
 }
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/factory.html b/ipojo/webconsole-plugin/src/main/resources/res/factory.html
new file mode 100644
index 0000000..cd920f0
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/factory.html
@@ -0,0 +1,96 @@
+<script type="text/javascript" src="${pluginRoot}/res/ui/factory_detail.js"></script>
+<script>
+    var root_url = '${pluginRoot}';
+    var instances_url = '${pluginRoot}' + '/instances';
+    var factories_url = '${pluginRoot}' + '/factories';
+    var handlers_url = '${pluginRoot}' + '/handlers';
+    var factory_name = '${name}';
+</script>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+	<div class="ui-widget-header ui-corner-top buttonGroup">
+		<button class="instancesButton" type="button">Instances</button>
+		<button class="factoriesButton" type="button">Factories</button>
+		<button class="handlersButton" type="button">Handlers</button>
+	</div>
+</form>
+
+<table id="plugin_table" class="nicetable noauto ui-widget-content">
+	<tbody>
+	    <!-- template -->
+		<tr>
+			<td class="Nname lheader">Factory Name</td>
+			<td class="Vname">&nbsp;</td>
+		</tr>
+        <tr>
+            <td class="Nstate lheader">State</td>
+            <td class="Vstate">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="Nbundle lheader">Bundle</td>
+            <td class="Vbundle">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="Nservices lheader">Provided Service Specifications</td>
+            <td class="Vservices">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="Nproperties lheader">Configuration Properties</td>
+            <td class="Vproperties">
+                <table class="properties ui-widget-content">
+                    <thead>
+                        <tr>
+                            <th class="col_Name">Name</th>
+                            <th class="col_Type">Type</th>
+                            <th class="col_Mandatory">Mandatory</th>
+                            <th class="col_Immutable">Immutable</th>
+                            <th class="col_Value">Default Value</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                       <tr class="ui-widget-content"><!-- template -->
+                            <td class="ui-widget-content name">&nbsp; </td>
+                            <td class="ui-widget-content type">&nbsp; </td>
+                            <td class="ui-widget-content mandatory">&nbsp;</td>
+                            <td class="ui-widget-content immutable">&nbsp;</td>
+                            <td class="ui-widget-content value">&nbsp; </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </td>
+        </tr>
+        <tr>
+            <td class="NrequiredHandlers lheader">Required Handlers</td>
+            <td class="VrequiredHandlers">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="NmissingHandlers lheader">Missing Handlers</td>
+            <td class="VmissingHandlers">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="NcreatedInstances lheader">Created Instances</td>
+            <td class="VcreatedInstances">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="Narchitecture lheader">Architecture</td>
+            <td class="Varchitecture"><div class="architecture"><pre class="architecture_content">&nbsp;</pre></div></td>
+        </tr>
+        
+	</tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+    <div class="ui-widget-header ui-corner-bottom buttonGroup">
+        <button class="instancesButton" type="button">Instances</button>
+        <button class="factoriesButton" type="button">Factories</button>
+        <button class="handlersButton" type="button">Handlers</button>
+    </div>
+</form>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/instance.html b/ipojo/webconsole-plugin/src/main/resources/res/instance.html
new file mode 100644
index 0000000..1b62a97
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/instance.html
@@ -0,0 +1,109 @@
+<script type="text/javascript" src="${pluginRoot}/res/ui/instance_detail.js"></script>
+<script>
+    var root_url = '${pluginRoot}';
+    var instances_url = '${pluginRoot}' + '/instances';
+    var factories_url = '${pluginRoot}' + '/factories';
+    var handlers_url = '${pluginRoot}' + '/handlers';
+    var instance_name = '${name}';
+</script>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+	<div class="ui-widget-header ui-corner-top buttonGroup">
+		<button class="instancesButton" type="button">Instances</button>
+		<button class="factoriesButton" type="button">Factories</button>
+		<button class="handlersButton" type="button">Handlers</button>
+	</div>
+</form>
+
+<table id="plugin_table" class="nicetable noauto ui-widget-content">
+	<tbody>
+	    <!-- template -->
+		<tr>
+			<td class="Nname lheader">Instance Name</td>
+			<td class="Vname">&nbsp;</td>
+		</tr>
+        <tr>
+            <td class="Nstate lheader">State</td>
+            <td class="Vstate">&nbsp;</td>
+        </tr>
+        <tr>
+            <td class="Nfactory lheader">Factory</td>
+            <td class="Vfactory">&nbsp;</td> <!-- TODO Link if possible --> 
+        </tr>
+        <tr>
+            <td class="Nservices lheader">Provided Services</td>
+            <td class="Vservices">
+                <table class="services ui-widget-content">
+                    <thead>
+                        <tr>
+                            <th class="col_Name">Specifications</th>
+                            <th class="col_State">State</th>
+                            <th class="col_Id">Service Id</th>
+                            <th class="col_Properties">Service Properties</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                       <tr class="ui-widget-content"><!-- template -->
+                            <td class="ui-widget-content name">&nbsp; </td>
+                            <td class="ui-widget-content state">&nbsp; </td>
+                            <td class="ui-widget-content id">&nbsp;</td>
+                            <td class="ui-widget-content properties">&nbsp;</td>
+                        </tr>
+                    </tbody>
+                </table>
+            </td>
+        </tr>
+        <tr>
+            <td class="NreqServices lheader">Required Services</td>
+            <td class="VreqServices">
+                <table class="reqServices ui-widget-content">
+                    <thead>
+                        <tr>
+                            <th class="col_Name">Specification</th>
+                            <th class="col_Id">Id</th>
+                            <th class="col_State">State</th>
+                            <th class="col_Policy">Binding Policy</th>
+                            <th class="col_Optional">Optional</th>
+                            <th class="col_Aggregate">Aggregate</th>
+                            <th class="col_Matching">Matching Services</th>
+                            <th class="col_Used">Used Services</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                       <tr class="ui-widget-content"><!-- template -->
+                            <td class="ui-widget-content name">&nbsp; </td>
+                            <td class="ui-widget-content id">&nbsp; </td>
+                            <td class="ui-widget-content state">&nbsp;</td>
+                            <td class="ui-widget-content policy">&nbsp;</td>
+                            <td class="ui-widget-content optional">&nbsp; </td>
+                            <td class="ui-widget-content aggregate">&nbsp; </td>
+                            <td class="ui-widget-content matching">&nbsp; </td>
+                            <td class="ui-widget-content used">&nbsp; </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </td>
+        </tr>
+        <tr>
+            <td class="Narchitecture lheader">Architecture</td>
+            <td class="Varchitecture"><div class="architecture"><pre class="architecture_content">&nbsp;</pre></div></td>
+        </tr>
+        
+	</tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+    <div class="ui-widget-header ui-corner-bottom buttonGroup">
+        <button class="instancesButton" type="button">Instances</button>
+        <button class="factoriesButton" type="button">Factories</button>
+        <button class="handlersButton" type="button">Handlers</button>
+    </div>
+</form>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js
index 8fc76cf..81fc782 100644
--- a/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js
@@ -52,7 +52,6 @@
 }
 
 function loadInstancesData() {
-    console.log("Go to instances"); 
     window.location = instances_url;
 }
 
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js
new file mode 100644
index 0000000..dc58708
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+function renderInstanceDetails(data)  {
+    $(".statline").html(getInstancesStatLine(data));
+    createDetail( data.data );
+}
+
+function getInstancesStatLine(instances) {
+    return instances.count + " instances in total, "
+        + instances.valid_count + " valid instances, "
+        + instances.invalid_count + " invalid instances.";
+}
+
+function createDetail(instance) {
+    console.log("Create details");
+    var service = "No provided services"
+    
+    var _ = tableBody;
+    
+    // Set the name
+    _.find('td.Vname').html(instance.name);
+    
+    // Set the state
+    _.find('td.Vstate').text(instance.state);
+    
+    // Set the factory
+    _.find('td.Vfactory').html(instance.factory); //TODO Link
+    
+    if (instance.services) {
+        $(tableServiceBody).empty();
+        for (var s in instance.services) {
+            var service = instance.services[s];
+            // For each service clone the template
+            var entry = serviceEntryTemplate.clone().appendTo(tableServiceBody).attr('id', 'service-' + service.specification);
+            entry.find('td.name').text(service.specification);
+            entry.find('td.state').text(service.state);
+            
+            if (service.id) {
+                entry.find('td.id').text(service.id);
+            } else {
+                entry.find('td.id').html('<i>not registered</i>');
+            }
+            
+            if (service.properties) {
+                var list = $('<ul>');
+                for (var x in service.properties) {
+                    list.append($('<li>').append(service.properties[x].name + ' = ' + service.properties[x].value));
+                }
+                entry.find('td.properties').html(list);
+            } else {
+                entry.find('td.properties').html('<i>not properties</i>');
+            }
+        }
+    } else {
+        // Hide the table
+        $('services').hide();
+        _.find('td.Vservices').html("No provided services");    
+    }
+    
+   if (instance.req) {
+        $(tableReqBody).empty();
+        for (var s in instance.req) {
+            var service = instance.req[s];
+            console.dir(service);
+            // For each service clone the template
+            var entry = reqEntryTemplate.clone().appendTo(tableReqBody).attr('id', 'req-' + service.id);
+            entry.find('td.name').text(service.specification);
+            entry.find('td.id').text(service.id);
+            entry.find('td.state').text(service.state);
+            
+            entry.find('td.policy').text(service.policy);
+            entry.find('td.optional').text(service.optional);
+            entry.find('td.aggregate').text(service.aggregate);
+            
+            
+            if (service.matching) {
+                var list = $('<ul>');
+                for (var x in service.matching) {
+                    list.append($('<li>').append(service.matching[x].id)); // TODO Link
+                }
+                entry.find('td.matching').html(list);
+            } else {
+                entry.find('td.matching').html('<i>no matching services</i>');
+            }
+            
+             if (service.used) {
+                var list = $('<ul>');
+                for (var x in service.used) {
+                    list.append($('<li>').append(service.used[x].id)); // TODO Link
+                }
+                entry.find('td.used').html(list);
+            } else {
+                entry.find('td.used').html('<i>no used services</i>');
+            }
+            
+        }
+    } else {
+        // Hide the table
+        $('reqServices').hide();
+        _.find('td.VreqServices').html("No required services");    
+    }
+   
+
+    _.find('pre.architecture_content').text(instance.architecture);
+}
+
+function retrieveDetails() {
+    $.get(pluginRoot + '/instances/' + instance_name + '.json', null, function(data) {
+        renderInstanceDetails(data);
+    }, "json");
+}
+
+function loadFactoriesData() {
+    window.location = factories_url;	
+}
+
+function loadInstancesData() {
+    window.location = instances_url;
+}
+
+function loadHandlersData() {
+    window.location = handlers_url;
+}
+
+var tableBody = false;
+var tableServiceBody = false;
+var serviceEntryTemplate = false;
+
+var tableReqBody = false;
+var reqEntryTemplate = false;
+
+
+$(document).ready(function(){
+	tableBody = $('#plugin_table tbody');
+    
+    tableServiceBody = $('.services tbody');
+    serviceEntryTemplate = tableServiceBody.find('tr').clone();
+    
+    tableReqBody = $('.reqServices tbody');
+    reqEntryTemplate = tableReqBody.find('tr').clone();
+    
+    
+    retrieveDetails();
+	
+    $(".instancesButton").click(loadInstancesData);
+    $(".factoriesButton").click(loadFactoriesData);
+    $(".handlersButton").click(loadHandlersData);
+
+	var extractMethod = function(node) {
+		var link = node.getElementsByTagName("a");
+		if ( link && link.length == 1 ) {
+			return link[0].innerHTML;
+		}
+		return node.innerHTML;
+	};
+	
+});
+
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js
index f59f15f..30cc9e0 100644
--- a/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js
@@ -36,8 +36,8 @@
 
     var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'instance-' + instance.name);
 
-    _.find('td.name').html('<a href="' + window.location.pathname + '/instance/' + name + '">' + name + '</a>');
-    _.find('td.factory').html('<a href="' + window.location.pathname + '/factory/' + factory + '">' + factory + '</a>');;
+    _.find('td.name').html('<a href="' + instances_url + '/' + name + '">' + name + '</a>');
+    _.find('td.factory').html('<a href="' + factories_url + '/' + factory + '">' + factory + '</a>');;
     _.find('td.state').text(state);
 }