You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by en...@apache.org on 2012/01/16 11:17:54 UTC

svn commit: r1231894 - in /incubator/stanbol/trunk/reasoners: ./ bundlelist/ jena/src/main/java/org/apache/stanbol/reasoners/jena/ web/src/main/java/org/apache/stanbol/reasoners/web/resources/ web/src/main/resources/org/apache/stanbol/reasoners/web/tem...

Author: enridaga
Date: Mon Jan 16 10:17:53 2012
New Revision: 1231894

URL: http://svn.apache.org/viewvc?rev=1231894&view=rev
Log:
Added documentation about the rest api for reasoners (STANBOL-462)

Modified:
    incubator/stanbol/trunk/reasoners/README.md
    incubator/stanbol/trunk/reasoners/bundlelist/   (props changed)
    incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLMiniReasoningService.java
    incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLReasoningService.java
    incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaRDFSReasoningService.java
    incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
    incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource.java
    incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource/index.ftl
    incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl

Modified: incubator/stanbol/trunk/reasoners/README.md
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/README.md?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/README.md (original)
+++ incubator/stanbol/trunk/reasoners/README.md Mon Jan 16 10:17:53 2012
@@ -43,10 +43,10 @@ Description
 * HermiT reasoning service
 
 * A common REST endpoint at /reasoners with the following preloaded services:
-**    /rdfs
-**    /owl
-**    /owlmini
-**    /owl2
+ *    /rdfs
+ *    /owl
+ *    /owlmini
+ *    /owl2
 
 each can be accessed with one of three tasks: check,enrich,classify, for example:
 
@@ -55,7 +55,7 @@ or
 /reasoners/owl2/classify (the hermit service with task classify)
 
 Tasks description:
-* check    : is the input consistent? 200 =true, 204 =false
+* check    : is the input consistent? 200 =true, 409 =false
 * classify : return only rdf:type inferences
 * enrich   : return all inferences
 
@@ -80,7 +80,8 @@ These additional parameters can be sent:
 * recipe  // The ID of a recipe from the Rules module (only with OWLApi based services)s
 
 Supported output formats:
-Supported return formats are all classic RDF types (n3,turtle,rdf+xml) and HTML. For HTML the returned statements are provided in Turtle (Jena) or OWL Manchester syntax (OWLApi), wrapped in the stanbol layout. It would be nice to have all in the latter, which is very much readable (todo).
+Supported return formats are all classic RDF types (n3,turtle,rdf+xml) and HTML. 
+For HTML the returned statements are provided in Turtle (Jena) or OWL Manchester syntax (OWLApi), wrapped in the stanbol layout. It would be nice to have all in the latter, which is very much readable (todo).
 
 Recently added
 =============

Propchange: incubator/stanbol/trunk/reasoners/bundlelist/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Jan 16 10:17:53 2012
@@ -1,2 +1,3 @@
 .project
 target
+.settings

Modified: incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLMiniReasoningService.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLMiniReasoningService.java?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLMiniReasoningService.java (original)
+++ incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLMiniReasoningService.java Mon Jan 16 10:17:53 2012
@@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
+import org.apache.stanbol.reasoners.servicesapi.annotations.Documentation;
 import org.osgi.service.component.ComponentContext;
 
 import com.hp.hpl.jena.reasoner.ReasonerRegistry;
@@ -30,6 +31,7 @@ import com.hp.hpl.jena.reasoner.Reasoner
  */
 @Component(immediate = true, metatype = true)
 @Service
+@Documentation(name = "Jena OWLMini", description = "This service use the Jena OWLMini reasoner.")
 public class JenaOWLMiniReasoningService extends AbstractJenaReasoningService {
     public static final String _DEFAULT_PATH = "owlmini";
 

Modified: incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLReasoningService.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLReasoningService.java?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLReasoningService.java (original)
+++ incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaOWLReasoningService.java Mon Jan 16 10:17:53 2012
@@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
+import org.apache.stanbol.reasoners.servicesapi.annotations.Documentation;
 import org.osgi.service.component.ComponentContext;
 
 import com.hp.hpl.jena.reasoner.ReasonerRegistry;
@@ -30,6 +31,7 @@ import com.hp.hpl.jena.reasoner.Reasoner
  */
 @Component(immediate = true, metatype = true)
 @Service
+@Documentation(name = "Jena OWL", description = "This service use the Jena OWL reasoner.")
 public class JenaOWLReasoningService extends AbstractJenaReasoningService {
     public static final String _DEFAULT_PATH = "owl";
 

Modified: incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaRDFSReasoningService.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaRDFSReasoningService.java?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaRDFSReasoningService.java (original)
+++ incubator/stanbol/trunk/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/JenaRDFSReasoningService.java Mon Jan 16 10:17:53 2012
@@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
+import org.apache.stanbol.reasoners.servicesapi.annotations.Documentation;
 import org.osgi.service.component.ComponentContext;
 
 import com.hp.hpl.jena.reasoner.ReasonerRegistry;
@@ -33,6 +34,7 @@ import com.hp.hpl.jena.reasoner.Reasoner
  */
 @Component(immediate = true, metatype = true)
 @Service
+@Documentation(name = "Jena RDFS", description = "This service use the Jena RDFS reasoner.")
 public class JenaRDFSReasoningService extends AbstractJenaReasoningService {
     public static final String _DEFAULT_PATH = "rdfs";
 

Modified: incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java (original)
+++ incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java Mon Jan 16 10:17:53 2012
@@ -61,6 +61,7 @@ import org.apache.stanbol.reasoners.serv
 import org.apache.stanbol.reasoners.servicesapi.ReasoningServicesManager;
 import org.apache.stanbol.reasoners.servicesapi.UnboundReasoningServiceException;
 import org.apache.stanbol.reasoners.servicesapi.UnsupportedTaskException;
+import org.apache.stanbol.reasoners.servicesapi.annotations.Documentation;
 import org.apache.stanbol.reasoners.web.input.impl.SimpleInputManager;
 import org.apache.stanbol.reasoners.web.input.provider.impl.FileInputProvider;
 import org.apache.stanbol.reasoners.web.input.provider.impl.OntonetInputProvider;
@@ -566,4 +567,35 @@ public class ReasoningServiceTaskResourc
         log.debug("(getJobManager()) ");
         return (JobManager) ContextHelper.getServiceFromContext(JobManager.class, this.context);
     }
+    
+    
+    public Map<String,String> getServiceDescription(){
+    	return getServiceDescription(service);
+    }
+    
+    public Map<String,String> getServiceDescription(ReasoningService<?,?,?> service){
+    	Class<?> serviceC = service.getClass();
+	 	String name;
+		try {
+			name = serviceC.getAnnotation(Documentation.class).name();
+		} catch (NullPointerException e) {
+    		log.warn("The service {} is not documented: missing name", serviceC);
+			name="";
+		}
+	 	String description;
+		try {
+			description = serviceC.getAnnotation(Documentation.class).description();
+		} catch (NullPointerException e) {
+    		log.warn("The service {} is not documented: missing description", serviceC);
+    		description="";
+		}
+	 	// String file = serviceC.getAnnotation(Documentation.class).file();
+		Map<String,String> serviceProperties = new HashMap<String,String>();
+		serviceProperties.put("name", name);
+		serviceProperties.put("description", description);
+		// serviceProperties.put("file", file);
+		serviceProperties.put("path", service.getPath());
+		return serviceProperties;
+    }
+
 }

Modified: incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource.java?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource.java (original)
+++ incubator/stanbol/trunk/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource.java Mon Jan 16 10:17:53 2012
@@ -18,20 +18,28 @@ package org.apache.stanbol.reasoners.web
 
 import static javax.ws.rs.core.MediaType.TEXT_HTML;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.servlet.ServletContext;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.stanbol.commons.web.base.ContextHelper;
 import org.apache.stanbol.commons.web.base.resource.BaseStanbolResource;
 import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
 import org.apache.stanbol.reasoners.servicesapi.ReasoningServicesManager;
+import org.apache.stanbol.reasoners.servicesapi.UnboundReasoningServiceException;
+import org.apache.stanbol.reasoners.servicesapi.annotations.Documentation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,6 +73,21 @@ public class ReasoningServicesResource e
         return Response.ok(new Viewable("index", this), TEXT_HTML).build();
     }
 
+    private ReasoningService<?,?,?> service = null;
+    
+    @GET
+    @Produces(TEXT_HTML)
+    @Path("{service}")
+    public Response getServiceDocumentation(@PathParam(value = "service") String serviceID) {
+    	try {
+			this.service = this.getServicesManager().get(serviceID);
+		} catch (UnboundReasoningServiceException e) {
+			log.info("Service {} is not bound", serviceID);
+			return Response.status(Status.NOT_FOUND).build();
+		}
+        return Response.ok(new Viewable("service", this), TEXT_HTML).build();
+    }
+    
     private ReasoningServicesManager getServicesManager() {
         log.debug("(getServicesManager()) ");
         return (ReasoningServicesManager) ContextHelper.getServiceFromContext(ReasoningServicesManager.class,
@@ -76,4 +99,43 @@ public class ReasoningServicesResource e
         return getServicesManager().asUnmodifiableSet();
     }
 
+    public ReasoningService<?, ?, ?> getService(){
+    	return this.service;
+    }
+
+    public Map<String,String> getServiceDescription(){
+    	return getServiceDescription(service);
+    }
+    
+    public Map<String,String> getServiceDescription(ReasoningService<?,?,?> service){
+    	Class<?> serviceC = service.getClass();
+	 	String name;
+		try {
+			name = serviceC.getAnnotation(Documentation.class).name();
+		} catch (NullPointerException e) {
+    		log.warn("The service {} is not documented: missing name", serviceC);
+			name="";
+		}
+	 	String description;
+		try {
+			description = serviceC.getAnnotation(Documentation.class).description();
+		} catch (NullPointerException e) {
+    		log.warn("The service {} is not documented: missing description", serviceC);
+    		description="";
+		}
+	 	// String file = serviceC.getAnnotation(Documentation.class).file();
+		Map<String,String> serviceProperties = new HashMap<String,String>();
+		serviceProperties.put("name", name);
+		serviceProperties.put("description", description);
+		// serviceProperties.put("file", file);
+		serviceProperties.put("path", service.getPath());
+		return serviceProperties;
+    }
+    public List<Map<String,String>> getServicesDescription(){
+    	List<Map<String,String>> descriptions = new ArrayList<Map<String,String>>();
+    	for(ReasoningService<?, ?, ?> service : getActiveServices()){
+    		descriptions.add(getServiceDescription(service));
+    	}
+    	return descriptions;
+    }
 }

Modified: incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource/index.ftl
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource/index.ftl?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource/index.ftl (original)
+++ incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource/index.ftl Mon Jan 16 10:17:53 2012
@@ -14,16 +14,18 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
+<#import "/imports/taskDescription.ftl" as taskDescription>
 <#import "/imports/common.ftl" as common>
 <#escape x as x?html>
-<@common.page title="Reasoning Service /${it.currentService.path}/${it.currentTask}" hasrestapi=false> 
-		
+<@common.page title="Reasoning Service /${it.currentService.path}/${it.currentTask}" hasrestapi=true> 
+ 	<h3>Service Endpoint <a href="/${it.currentPath}/..">/reasoners/${it.currentService.path}</a>: ${it.serviceDescription.name}</h3>
+	<h4 style="font-size: 1em">Subresource <a href="/${it.currentPath}">/${it.currentPath}</a></h4>
+ 
  <div class="panel" id="webview">
- 	<h3>/${it.currentPath}</h3>
-	<p><b>Service type:</b> <tt>${it.currentService.class.name}</tt></p>
-	<p><b>Name:</b> ${it.currentService.path}</p>
-	<p><b>Task:</b> ${it.currentTask}</p>
-	
+	<p><b>Service:</b> <tt>${it.currentService.class.name}</tt>
+	<br/><b>Name:</b> ${it.currentService.path}
+	<br/><b>Task:</b> ${it.currentTask}</p>
+	<h4>Run as foreground job</h4>
 	<form method="GET" accept-charset="utf-8">
 	<fieldset>
 	<legend>Submit a URL to the service</legend>
@@ -37,6 +39,30 @@
 	<p><b>File:</b> <input type="file" name="file"/> <input type="submit" value="Send"/></p>
 	</fieldset>
 	</form>
+	<h4>Run as background job</h4>
+	<form method="GET" action="/${it.currentPath}/job" accept-charset="utf-8">
+	<fieldset>
+	<legend>Submit a URL to the service</legend>
+	<p><b>URL:</b> <input type="text" name="url" size="80"/> <input type="submit" value="Send"/></p>
+	</fieldset>
+	</form>
+	
+	<form method="POST" action="/${it.currentPath}/job" enctype="multipart/form-data" accept-charset="utf-8">
+	<fieldset>
+	<legend>Submit a file to the service</legend>
+	<p><b>File:</b> <input type="file" name="file"/> <input type="submit" value="Send"/></p>
+	</fieldset>
+	</form>
+ </div>
+ 
+ <div class="panel" id="restapi" style="display: none;">
+	 <#if it.currentTask == "classify">
+		<@taskDescription.view name="Classify" path="${it.currentPath}" description="This task infer all <tt>rdf:type</tt> statements."/>
+	 <#elseif it.currentTask == "check">
+		<@taskDescription.view name="Check" path="${it.currentPath}" description="This task checks whether the schema is correctly used."/>
+	 <#elseif it.currentTask == "enrich">
+		<@taskDescription.view name="Enrich" path="${it.currentPath}" description="This task materializes all inferences."/>
+	 </#if>
  </div>
-  </...@common.page>
+</...@common.page>
 </#escape>
\ No newline at end of file

Modified: incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl?rev=1231894&r1=1231893&r2=1231894&view=diff
==============================================================================
--- incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl (original)
+++ incubator/stanbol/trunk/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl Mon Jan 16 10:17:53 2012
@@ -16,52 +16,53 @@
 -->
 <#import "/imports/common.ftl" as common>
 <#import "/imports/reasonersDescription.ftl" as reasonersDescription>
+<#import "/imports/serviceDescription.ftl" as serviceDescription>
 <#escape x as x?html>
-<@common.page title="Reasoners" hasrestapi=false> 
+<@common.page title="Reasoners" hasrestapi=true> 
 		
  <div class="panel" id="webview">
+ <p>The Stanbol Reasoners provides a set of services that take advantage of automatic inference engines.</p>
+ <h3>Active services</h3>
+ <p>There are currently <strong>${it.activeServices?size}</strong> active services.</p>
+ <p>Each reasoning service can be accessed to perform one of three tasks: classification, consistency check, get all inferences</p>          
+  <ul>
+  <#list it.servicesDescription as service>
+    <@serviceDescription.li name="${service.name}" fullpath="${it.currentPath}/${service.path}" path="${service.path}" description="${service.description}"/>
+    <ul>
+    <#-- TODO: generate the task list dinamically -->
+      <li><a href="${it.publicBaseUri}${it.currentPath}/${service.path}/classify" title="${service.name} Task: classify">classify</a></li>
+      <li><a href="${it.publicBaseUri}${it.currentPath}/${service.path}/check" title="${service.name} Task: check">check</a></li>
+      <li><a href="${it.publicBaseUri}${it.currentPath}/${service.path}/enrich" title="${service.name} Task: classify">enrich</a></li>
+    </ul>	
+  </#list>
+ </ul>
  <#if it.activeServices?size == 0>
-   <p><em>There is no reasoning services. Administrators can install and
+   <p><em>There is no reasoning service. Administrators can install and
    configure new reasoning services using the
     <a href="/system/console/components" target="_blank">OSGi console</a>.</em></p>
  <#else>
- <!-- FIXME class names should be generic, and not bound to a specific functionality (here engines->reasoning services)-->
- <div class="enginelisting">
-  <div class="collapsed">
-  <p class="collapseheader">There are currently
-   <strong>${it.activeServices?size}</strong> active services.</p>
-   <div class="collapsable">
-    <ul>
-
-     <#list it.activeServices as service>
-      <li><b>${service.path}</b>:
-        <#list service.supportedTasks as task> 
-        	<a href="${it.publicBaseUri}${it.currentPath}/${service.path}/${task}" title="${service.class.name} Task: ${task}">${task}</a> |
-        </#list>
-        <a href="${it.publicBaseUri}${it.currentPath}/${service.path}/check" title="${service.class.name} Task: check">check</a>
-      </li>
-     </#list>
-    </ul>
-    
+<#--
+  This is not much informative for the moment   
   <p class="note">Administrators can enable, disable and deploy reasoning services using the
     <a href="/system/console/components" target="_blank">OSGi console</a>.</p>
-   </div>
-   
-  </div> 
- </div>
-
-<script>
-$(".enginelisting p").click(function () {
-  $(this).parents("div").toggleClass("collapsed");
-});    
-</script>
+-->
  </#if>
-	</div>
-
-    <!-- We disable this at the moment -->
-    <!--div class="panel" id="restapi" style="display: none;">
-          
-    </div -->
-
+ </div>
+ <!-- We disable this at the moment -->
+ <div class="panel" id="restapi" style="display: none;">
+    <p>This section lists how to use the REST api of all active services:</p>
+    <h3>Service Endpoints</h3>
+    <ul>
+    <#list it.servicesDescription as service>
+      <li><a href="#${service.path}">${service.name}</a></li>
+	</#list>
+    </ul>
+    <#list it.servicesDescription as service>
+    <hr/>
+      <a name="${service.path}"></a>
+      <h4 style="font-size:1em">Service Endpoint <a href="${it.currentPath}/${service.path}">/reasoners/${service.path}</a>: ${service.name}</h4>
+	  <@serviceDescription.view name="${service.name}" fullpath="${it.currentPath}/${service.path}" path="${service.path}" description="${service.description}"/>
+	</#list>
+ </div>
 </...@common.page>
 </#escape>
\ No newline at end of file