Author: enridaga
Date: Wed Aug 24 16:39:34 2011
New Revision: 1161197
URL: http://svn.apache.org/viewvc?rev=1161197&view=rev
Log:
STANBOL-185
* Created a ReasoningServiceExecutor as a delegate to run reasoning services
(the input preparation is still responsability of the front rest service, while
the output is managed by the executor. This can change later on)
* Minor adjustments in the ReasoningService interface
* Preparation of the front rest service to support parameters for scope,
session and recipe (not implemented yet) and prepared basic workflow (not
implemented yet)
* Some minor refactoring
Added:
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningPrettyResultResource.java
- copied, changed from r1160643,
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningPrettyResultResource.java
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningServiceExecutor.java
Removed:
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningPrettyResultResource.java
Modified:
incubator/stanbol/branches/jena-reasoners/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/AbstractJenaReasoningService.java
incubator/stanbol/branches/jena-reasoners/reasoners/owlapi/src/main/java/org/apache/stanbol/reasoners/owlapi/AbstractOWLApiReasoningService.java
incubator/stanbol/branches/jena-reasoners/reasoners/servicesapi/src/main/java/org/apache/stanbol/reasoners/servicesapi/ReasoningService.java
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl
Modified:
incubator/stanbol/branches/jena-reasoners/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/AbstractJenaReasoningService.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/AbstractJenaReasoningService.java?rev=1161197&r1=1161196&r2=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/AbstractJenaReasoningService.java
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/jena/src/main/java/org/apache/stanbol/reasoners/jena/AbstractJenaReasoningService.java
Wed Aug 24 16:39:34 2011
@@ -87,7 +87,7 @@ public abstract class AbstractJenaReason
Model data,
List<Rule> rules,
boolean filtered,
- Map<String,?> parameters) throws
UnsupportedTaskException,
+ Map<String,List<String>> parameters) throws
UnsupportedTaskException,
ReasoningServiceException,
InconsistentInputException {
if (taskID.equals(ReasoningService.Tasks.CLASSIFY)) {
Modified:
incubator/stanbol/branches/jena-reasoners/reasoners/owlapi/src/main/java/org/apache/stanbol/reasoners/owlapi/AbstractOWLApiReasoningService.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/owlapi/src/main/java/org/apache/stanbol/reasoners/owlapi/AbstractOWLApiReasoningService.java?rev=1161197&r1=1161196&r2=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/owlapi/src/main/java/org/apache/stanbol/reasoners/owlapi/AbstractOWLApiReasoningService.java
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/owlapi/src/main/java/org/apache/stanbol/reasoners/owlapi/AbstractOWLApiReasoningService.java
Wed Aug 24 16:39:34 2011
@@ -176,7 +176,7 @@ public abstract class AbstractOWLApiReas
OWLOntology data,
List<SWRLRule> rules,
boolean filtered,
- Map<String,?> parameters) throws
UnsupportedTaskException,
+ Map<String,List<String>> parameters) throws
UnsupportedTaskException,
ReasoningServiceException,
InconsistentInputException {
if (taskID.equals(ReasoningService.Tasks.CLASSIFY)) {
Modified:
incubator/stanbol/branches/jena-reasoners/reasoners/servicesapi/src/main/java/org/apache/stanbol/reasoners/servicesapi/ReasoningService.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/servicesapi/src/main/java/org/apache/stanbol/reasoners/servicesapi/ReasoningService.java?rev=1161197&r1=1161196&r2=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/servicesapi/src/main/java/org/apache/stanbol/reasoners/servicesapi/ReasoningService.java
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/servicesapi/src/main/java/org/apache/stanbol/reasoners/servicesapi/ReasoningService.java
Wed Aug 24 16:39:34 2011
@@ -87,7 +87,7 @@ public interface ReasoningService<M,R,S>
M data,
List<R> rules,
boolean filtered,
- Map<String,?> parameters) throws
UnsupportedTaskException,
+ Map<String,List<String>> parameters) throws
UnsupportedTaskException,
ReasoningServiceException,
InconsistentInputException;
Modified:
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java?rev=1161197&r1=1161196&r2=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningServiceTaskResource.java
Wed Aug 24 16:39:34 2011
@@ -1,20 +1,21 @@
package org.apache.stanbol.reasoners.web.resources;
+import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
-import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.IOException;
import java.net.MalformedURLException;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.locks.Lock;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
@@ -24,29 +25,19 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import org.apache.clerezza.rdf.core.MGraph;
-import org.apache.clerezza.rdf.core.UriRef;
-import org.apache.clerezza.rdf.core.access.LockableMGraph;
-import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
import org.apache.clerezza.rdf.core.access.TcManager;
import org.apache.stanbol.commons.web.base.ContextHelper;
import org.apache.stanbol.commons.web.base.format.KRFormat;
import org.apache.stanbol.commons.web.base.resource.BaseStanbolResource;
-import org.apache.stanbol.owl.transformation.JenaToClerezzaConverter;
-import org.apache.stanbol.owl.transformation.OWLAPIToClerezzaConverter;
import org.apache.stanbol.reasoners.jena.JenaReasoningService;
import org.apache.stanbol.reasoners.owlapi.OWLApiReasoningService;
-import org.apache.stanbol.reasoners.servicesapi.InconsistentInputException;
import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
-import org.apache.stanbol.reasoners.servicesapi.ReasoningServiceException;
import org.apache.stanbol.reasoners.servicesapi.ReasoningServicesManager;
import
org.apache.stanbol.reasoners.servicesapi.UnboundReasoningServiceException;
-import org.apache.stanbol.reasoners.servicesapi.UnsupportedTaskException;
-import org.coode.owlapi.manchesterowlsyntax.ManchesterOWLSyntaxOntologyFormat;
+import org.apache.stanbol.reasoners.web.utils.ReasoningServiceExecutor;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.OWLOntologyCreationIOException;
import org.semanticweb.owlapi.model.IRI;
@@ -55,22 +46,24 @@ import org.semanticweb.owlapi.model.Miss
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
-import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.model.SWRLRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
-import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
+import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.api.core.HttpRequestContext;
import com.sun.jersey.api.view.Viewable;
-import com.sun.jersey.multipart.FormDataParam;
+import com.sun.jersey.multipart.BodyPart;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataMultiPart;
/**
* Endpoint for reasoning services. Services can be invoked using the service
name and task in the request
- * path. The concrete execution is delegated to the SCR service.
+ * path. The related active SCR service is selected, then the concrete
execution is delegated to a {@see
+ * ReasoningServiceExecutor}.
*
* Two different kind of implementation of {@see ReasoningService} are
supported: {@see JenaReasoningService}
* and {@see OWLApiReasonngService}.
@@ -83,27 +76,32 @@ import com.sun.jersey.multipart.FormData
public class ReasoningServiceTaskResource extends BaseStanbolResource {
private Logger log = LoggerFactory.getLogger(getClass());
private ServletContext context;
- private HttpHeaders headers;
private ReasoningService<?,?,?> service;
private String taskID;
+ private HttpContext httpContext;
+ private Map<String,List<String>> parameters;
private TcManager tcManager;
- private HttpRequestContext requestContext;
+ private HttpHeaders headers;
public ReasoningServiceTaskResource(@PathParam(value = "service") String
serviceID,
@PathParam(value = "task") String
taskID,
@Context ServletContext servletContext,
@Context HttpHeaders headers,
- @Context HttpRequestContext request) {
+ @Context HttpContext httpContext) {
super();
- log.info("Called service {} to perform task {}", service, taskID);
+ log.info("Called service {} to perform task {}", serviceID, taskID);
+
// ServletContext
this.context = servletContext;
+ // HttpContext
+ this.httpContext = httpContext;
+
// HttpHeaders
this.headers = headers;
- // HttpRequestContext
- this.requestContext = request;
+ // Parameters for customized reasoning services
+ this.parameters = prepareParameters();
// Clerezza storage
this.tcManager = (TcManager)
ContextHelper.getServiceFromContext(TcManager.class, servletContext);
@@ -115,16 +113,16 @@ public class ReasoningServiceTaskResourc
log.error("Service not found: {}", serviceID);
throw new WebApplicationException(e, Response.Status.NOT_FOUND);
}
-
+ log.info("Service retrieved");
// Check if the task is allowed
- if (this.service.supportsTask(taskID)) {
+ if (this.service.supportsTask(taskID) ||
taskID.equals(ReasoningServiceExecutor.TASK_CHECK)) {
this.taskID = taskID;
} else {
log.error("Unsupported task (not found): {}", taskID);
throw new WebApplicationException(new Exception("Unsupported task
(not found): " + taskID),
Response.Status.BAD_REQUEST);
}
-
+ log.info("Task is OK");
// Now we check if the service implementation is supported
if (getCurrentService() instanceof JenaReasoningService) {} else if
(getCurrentService() instanceof OWLApiReasoningService) {} else {
log.error("This implementation of ReasoningService is not
supported: {}", getCurrentService()
@@ -133,6 +131,8 @@ public class ReasoningServiceTaskResourc
"This implementation of ReasoningService is not supported:
"
+ getCurrentService().getClass()),
Response.Status.INTERNAL_SERVER_ERROR);
}
+ log.info("Implementation is supported");
+
}
// @GET
@@ -202,6 +202,48 @@ public class ReasoningServiceTaskResourc
// // If target is null, then get back results, elsewhere put it in target
graph
// return null;
// }
+ /**
+ *
+ * @return
+ */
+ private Map<String,List<String>> prepareParameters() {
+ Map<String,List<String>> parameters = new
HashMap<String,List<String>>();
+
+ log.info("Preparing parameters...");
+ HttpRequestContext request = this.httpContext.getRequest();
+ // Parameters for a GET request
+ MultivaluedMap<String,String> queryParameters =
request.getQueryParameters();
+ log.info("... {} query parameters found", queryParameters.size());
+ for (Entry<String,List<String>> e : queryParameters.entrySet()) {
+ parameters.put(e.getKey(), e.getValue());
+ }
+ // Parameters for a POST request with content-type
application/x-www-form-urlencoded
+ MultivaluedMap<String,String> formParameters =
request.getFormParameters();
+ log.info("... {} form urlencoded parameters found",
formParameters.size());
+ for (Entry<String,List<String>> e : formParameters.entrySet()) {
+ parameters.put(e.getKey(), e.getValue());
+ }
+ log.info("Paramters prepared");
+ return parameters;
+ }
+
+ /**
+ * This is an alias of the get method.
+ *
+ * @param url
+ * @param targetGraphID
+ * @return
+ */
+ @POST
+ @Consumes({APPLICATION_FORM_URLENCODED})
+ @Produces({TEXT_HTML, "text/plain", KRFormat.RDF_XML, KRFormat.TURTLE,
"text/turtle", "text/n3"})
+ public Response post(@FormParam("url") String url,
+ @FormParam("scope") String scope,
+ @FormParam("session") String session,
+ @FormParam("recipe") String recipe,
+ @FormParam("target") String targetGraphID) {
+ return get(url, scope, session, recipe, targetGraphID);
+ }
/**
* Get the inferences from input URL. If url param is null, get the HTML
description of this service/task
@@ -211,72 +253,145 @@ public class ReasoningServiceTaskResourc
*/
@GET
@Produces({TEXT_HTML, "text/plain", KRFormat.RDF_XML, KRFormat.TURTLE,
"text/turtle", "text/n3"})
- public Response get(@QueryParam("url") String url, @QueryParam("target")
String targetGraphID) {
- // If url param is missing, we produce the service/task welcome page
- if (url == null) {
+ public Response get(@QueryParam("url") String url,
+ @QueryParam("scope") String scope,
+ @QueryParam("session") String session,
+ @QueryParam("recipe") String recipe,
+ @QueryParam("target") String targetGraphID) {
+ // If all parameters are missing we produce the service/task welcome
page
+ if (this.parameters.isEmpty()) {
return Response.ok(new Viewable("index", this)).build();
}
+ if (url != null) {
+ // We remove it form the additional parameter list
+ this.parameters.remove("url");
+ }
+ // We remove also target
+ this.parameters.remove("target");
log.info("Called GET with input url: {} and target {}", url,
targetGraphID);
+ // The service executor
+ ReasoningServiceExecutor executor = new
ReasoningServiceExecutor(tcManager, headers, servletContext,
+ uriInfo);
+
/**
* Select the service implementation
*/
if (getCurrentService() instanceof JenaReasoningService) {
// Prepare input data
- Model input = ModelFactory.createDefaultModel().read(url);
- return executeJenaReasoningService((JenaReasoningService)
getCurrentService(), input, null,
- targetGraphID);
+ Model input = prepareJenaInputFromGET(url, scope, session);
+ // Prepare rules
+ List<Rule> rules = prepareJenaRules(recipe);
+ return executor.executeJenaReasoningService(getCurrentTask(),
+ (JenaReasoningService) getCurrentService(), input, rules,
targetGraphID, false,
+ this.parameters);
} else if (getCurrentService() instanceof OWLApiReasoningService) {
OWLOntology input = null;
try {
- input =
createOWLOntologyManager().loadOntologyFromOntologyDocument(IRI.create(url));
+ input = prepareOWLApiInputFromGET(url, scope, session);
} catch (OWLOntologyCreationIOException e) {
throw new WebApplicationException(e,
Response.Status.NOT_FOUND);
} catch (OWLOntologyCreationException e) {
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
- return executeOWLApiReasoningService((OWLApiReasoningService)
getCurrentService(), input, null,
- targetGraphID);
+ return executor.executeOWLApiReasoningService(getCurrentTask(),
+ (OWLApiReasoningService) getCurrentService(), input, null,
targetGraphID, this.parameters);
}
throw new WebApplicationException(new Exception("Unsupported
implementation"),
Response.Status.INTERNAL_SERVER_ERROR);
}
/**
- * Generate inferences from the input file. Output comes back to the
client.
+ * To catch additional parameters in case of a POST with content-type
multipart/form-data, we need to
+ * acces the {@link FormDataMultiPart} representation of the input.
*
- * @param file
+ * @param data
* @return
*/
@POST
@Consumes({MULTIPART_FORM_DATA})
@Produces({TEXT_HTML, "text/plain", KRFormat.RDF_XML, KRFormat.TURTLE,
"text/turtle", "text/n3"})
- public Response postData(@FormDataParam("file") File file,
@FormDataParam("target") String targetGraphID) {
+ public Response post(FormDataMultiPart data) {
+ File file = null;
+ String scope = null;
+ String session = null;
+ String recipe = null;
+ String targetGraphID = null;
+ for (BodyPart bpart : data.getBodyParts()) {
+ log.info("is a {}", bpart.getClass());
+ if (bpart instanceof FormDataBodyPart) {
+ FormDataBodyPart dbp = (FormDataBodyPart) bpart;
+ if (dbp.getName().equals("target")) {
+ targetGraphID = dbp.getValue();
+ } else if (dbp.getName().equals("file")) {
+ file = bpart.getEntityAs(File.class);
+ } else if (dbp.getName().equals("scope")) {
+ scope = ((FormDataBodyPart) bpart).getValue();
+ } else if (dbp.getName().equals("session")) {
+ session = ((FormDataBodyPart) bpart).getValue();
+ } else if (dbp.getName().equals("recipe")) {
+ recipe = ((FormDataBodyPart) bpart).getValue();
+ } else {
+ // We put all the rest in the parameters field
+ // XXX We supports here only simple fields
+ // We do NOT support the sent of additional files, for
example
+ if (dbp.isSimple()) {
+ if (this.parameters.containsKey(dbp.getName())) {
+
this.parameters.get(dbp.getName()).add(dbp.getValue());
+ } else {
+ List<String> values = new ArrayList<String>();
+ values.add(dbp.getValue());
+ this.parameters.put(dbp.getName(), values);
+ }
+ }
+ }
+ }
+ }
+ return postData(file, scope, session, recipe, targetGraphID);
+ }
+
+ /**
+ * Generate inferences from the input file. Output comes back to the
client.
+ *
+ * @param file
+ * @return
+ */
+ private Response postData(File file, String scope, String session, String
recipe, String targetGraphID) {
log.info("Called POST with input file: {} and target: {}", file,
targetGraphID);
if (file.exists() && file.canRead()) {
+ // The service executor
+ ReasoningServiceExecutor executor = new
ReasoningServiceExecutor(tcManager, headers, servletContext,
+ uriInfo);
+
// Select the service implementation
if (getCurrentService() instanceof JenaReasoningService) {
// Prepare input data
Model input;
try {
- input =
ModelFactory.createDefaultModel().read(file.toURI().toURL().toString());
+ input = prepareJenaInputFromPOST(file, scope, session);
} catch (MalformedURLException e) {
throw new WebApplicationException(new
IllegalArgumentException("Cannot read file"),
Response.Status.INTERNAL_SERVER_ERROR);
}
- return executeJenaReasoningService((JenaReasoningService)
getCurrentService(), input, null,
- targetGraphID);
+ // Prepare rules
+ List<Rule> rules = prepareJenaRules(recipe);
+ return executor.executeJenaReasoningService(getCurrentTask(),
+ (JenaReasoningService) getCurrentService(), input, rules,
targetGraphID, false,
+ this.parameters);
} else if (getCurrentService() instanceof OWLApiReasoningService) {
OWLOntology input = null;
try {
- input =
createOWLOntologyManager().loadOntologyFromOntologyDocument(file);
+ input = prepareOWLApiInputFromPOST(file, scope, session);
} catch (OWLOntologyCreationIOException e) {
throw new WebApplicationException(e,
Response.Status.NOT_FOUND);
} catch (OWLOntologyCreationException e) {
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
- return executeOWLApiReasoningService((OWLApiReasoningService)
getCurrentService(), input,
- null, targetGraphID);
+ // Prepare rules
+ List<SWRLRule> rules = prepareOWLApiRules(recipe);
+ return executor.executeOWLApiReasoningService(getCurrentTask(),
+ (OWLApiReasoningService) getCurrentService(), input,
rules, targetGraphID,
+ this.parameters);
}
throw new WebApplicationException(new Exception("Unsupported
implementation"),
Response.Status.INTERNAL_SERVER_ERROR);
@@ -287,200 +402,6 @@ public class ReasoningServiceTaskResourc
}
}
- /**
- * Check if the client needs a serialization of the output or a human
readable form (HTML)
- *
- * @param headers
- * @return
- */
- private boolean isHTML() {
- // We only want to state if HTML format is the preferred format
- // requested
- Set<String> htmlformats = new HashSet<String>();
- htmlformats.add(TEXT_HTML);
- Set<String> rdfformats = new HashSet<String>();
- String[] formats = {TEXT_HTML, "text/plain", KRFormat.RDF_XML,
KRFormat.TURTLE, "text/turtle",
- "text/n3"};
- rdfformats.addAll(Arrays.asList(formats));
- List<MediaType> mediaTypes = headers.getAcceptableMediaTypes();
- for (MediaType t : mediaTypes) {
- String strty = t.toString();
- log.info("Acceptable is {}", t);
- if (htmlformats.contains(strty)) {
- log.debug("Requested format is HTML {}", t);
- return true;
- } else if (rdfformats.contains(strty)) {
- log.debug("Requested format is RDF {}", t);
- return false;
- }
- }
- // Default behavior? Should never happen!
- return true;
- }
-
- /**
- * Execute a JenaReasoningService
- *
- * TODO: Add parameter to decide if the graph must be deleted if exists
- *
- * @param s
- * @param input
- * @param rules
- * @return
- */
- private Response executeJenaReasoningService(JenaReasoningService s,
- Model input,
- List<Rule> rules,
- String targetGraphID) {
- // Check task
- if (getCurrentTask().equals("check")) {
- log.debug("Task is 'check'");
- boolean isConsistent;
- try {
- isConsistent = s.isConsistent(input);
- if (isConsistent) {
- log.debug("The input is consistent");
- return Response.ok().build();
- } else {
- log.debug("The input is not consistent");
- return Response.status(Status.NO_CONTENT).build();
- }
- } catch (ReasoningServiceException e) {
- log.error("Error thrown: {}", e);
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- }
- }
- try {
- Set<Statement> result = s.runTask(getCurrentTask(), input);
- if (result == null) {
- log.error("Result is null");
- throw new WebApplicationException();
- }
- Model outputModel = ModelFactory.createDefaultModel();
- outputModel.add(result.toArray(new Statement[result.size()]));
- // If target is null, then get back results, elsewhere put it in
target graph
- if (targetGraphID == null) {
- log.info("Returning {} statements", result.size());
- if (isHTML()) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- outputModel.write(out, "TURTLE");
- return Response.ok(
- new Viewable("result", new
ReasoningPrettyResultResource(context, uriInfo, out)),
- TEXT_HTML).build();
- } else {
- return Response.ok(outputModel).build();
- }
- } else {
- save(outputModel, targetGraphID);
- return Response.ok().build();
- }
- } catch (ReasoningServiceException e) {
- log.error("Error thrown: {}", e);
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- } catch (InconsistentInputException e) {
- log.debug("The input is not consistent");
- return Response.status(Status.NO_CONTENT).build();
- } catch (UnsupportedTaskException e) {
- log.error("Error thrown: {}", e);
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- }
- }
-
- /**
- * Executes the OWLApiReasoingService
- *
- * @param s
- * @param input
- * @param rules
- * @return
- */
- private Response executeOWLApiReasoningService(OWLApiReasoningService s,
- OWLOntology input,
- List<SWRLRule> rules,
- String targetGraphID) {
- if (getCurrentTask().equals("check")) {
- log.debug("Task is 'check'");
- boolean isConsistent;
-
- try {
- isConsistent = s.isConsistent(input);
- if (isConsistent) {
- log.debug("The input is consistent");
- return Response.ok().build();
- } else {
- log.debug("The input is not consistent");
- return Response.status(Status.NO_CONTENT).build();
- }
- } catch (ReasoningServiceException e) {
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- }
- }
- // We get the manager from the input ontology
- // XXX We must be aware of this.
- OWLOntologyManager manager = input.getOWLOntologyManager();
- try {
- OWLOntology output = manager.createOntology();
- manager.addAxioms(output, s.runTask(getCurrentTask(), input));
-
- if (targetGraphID == null) {
- if (isHTML()) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- manager.saveOntology(output, new
ManchesterOWLSyntaxOntologyFormat(), out);
- return Response.ok(
- new Viewable("result", new
ReasoningPrettyResultResource(context, uriInfo, out)),
- TEXT_HTML).build();
- } else {
- return Response.ok(output).build();
- }
- } else {
- save(output, targetGraphID);
- return Response.ok().build();
- }
- } catch (ReasoningServiceException e) {
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- } catch (InconsistentInputException e) {
- log.debug("The input is not consistent");
- return Response.status(Status.NO_CONTENT).build();
- } catch (OWLOntologyCreationException e) {
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- } catch (OWLOntologyStorageException e) {
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- } catch (UnsupportedTaskException e) {
- throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
- }
- }
-
- private void save(Object data, String targetGraphID) {
- log.info("Attempt saving in target graph {}", targetGraphID);
- final long startSave = System.currentTimeMillis();
- LockableMGraph mGraph;
- UriRef graphUriRef = new UriRef(targetGraphID);
- try {
- // Check whether the graph already exists
- mGraph = this.tcManager.getMGraph(graphUriRef);
- } catch (NoSuchEntityException e) {
- mGraph = this.tcManager.createMGraph(graphUriRef);
- }
- // We lock the graph before proceed
- Lock writeLock = mGraph.getLock().writeLock();
- boolean saved = false;
- if (data instanceof Model) {
- MGraph m =
JenaToClerezzaConverter.jenaModelToClerezzaMGraph((Model) data);
- writeLock.lock();
- saved = mGraph.addAll(m);
- writeLock.unlock();
- } else if (data instanceof OWLOntology) {
- MGraph m =
OWLAPIToClerezzaConverter.owlOntologyToClerezzaMGraph((OWLOntology) data);
- writeLock.lock();
- saved = mGraph.addAll(m);
- writeLock.unlock();
- }
- if (!saved) throw new WebApplicationException(new IOException("Cannot
save model!"),
- Response.Status.INTERNAL_SERVER_ERROR);
- final long endSave = System.currentTimeMillis();
- log.info("Save time: {}", (endSave - startSave));
- }
-
private OWLOntologyManager createOWLOntologyManager() {
// We isolate here the creation of the temporary manager
// TODO How to behave when resolving owl:imports?
@@ -527,10 +448,13 @@ public class ReasoningServiceTaskResourc
}
/**
- * The list of supported tasks.
+ * The list of supported tasks. We include CHECK, which is managed
directly by the endpoint.
*/
public List<String> getSupportedTasks() {
- return getCurrentService().getSupportedTasks();
+ List<String> supported = new ArrayList<String>();
+ supported.add(ReasoningServiceExecutor.TASK_CHECK);
+ supported.addAll(getCurrentService().getSupportedTasks());
+ return supported;
}
/**
@@ -564,4 +488,87 @@ public class ReasoningServiceTaskResourc
log.debug("(getActiveServices()) There are {} reasoning services",
getServicesManager().size());
return getServicesManager().asUnmodifiableSet();
}
+
+ private Model prepareJenaInputFromGET(String url, String scope, String
session) {
+ Model input = ModelFactory.createDefaultModel();
+ // TODO
+ // If session exists, get the ontology and load it in a Jena model
+ // If scope exists, get the ontology and load it in a Jena model
+ if (session != null || scope != null) {
+ log.error("prepareJenaInputFromGET(String url, String scope,
String session) Not implemented yet!");
+ throw new WebApplicationException(501);
+ }
+
+ // If url exists, merge the location within the model
+ if (url != null) {
+ input.read(url);
+ }
+
+ return input;
+ }
+
+ private Model prepareJenaInputFromPOST(File file, String scope, String
session) throws MalformedURLException {
+ Model input = ModelFactory.createDefaultModel();
+ // TODO
+ // If session exists, get the ontology and load it in a Jena model
+ // If scope exists, get the ontology and load it in a Jena model
+ if (scope != null || session != null) {
+ log.error("prepareJenaInputForPOST(File file, String scope, String
session) Not implemented yet!");
+ throw new WebApplicationException(501);
+ }
+ // If file exists, merge the location within the model
+ if (file != null) {
+ input.read(file.toURI().toURL().toString());
+ }
+ return input;
+ }
+
+ private OWLOntology prepareOWLApiInputFromGET(String url, String scope,
String session) throws OWLOntologyCreationException {
+ OWLOntologyManager m = createOWLOntologyManager();
+ // TODO
+ // If session exists, load it
+ // If scope exists, load it
+ if (scope != null || session != null) {
+ log.error("prepareOWLApiInputFromGET(String url, String scope,
String session) Not implemented yet!");
+ throw new WebApplicationException(501);
+ }
+ // If url exists, load it as triples, then include an import statement
to the session/scope, then load
+ // it in the manager (TODO)
+ return m.loadOntologyFromOntologyDocument(IRI.create(url));
+ }
+
+ private OWLOntology prepareOWLApiInputFromPOST(File file, String scope,
String session) throws OWLOntologyCreationException {
+ OWLOntologyManager m = createOWLOntologyManager();
+ // TODO
+ // If session exists, load it
+ // If scope exists, load it
+ if (scope != null || session != null) {
+ log.error("prepareOWLApiInputFromPOST(File file, String scope,
String session) Not implemented yet!");
+ throw new WebApplicationException(501);
+ }
+ // If url exists, load it as triples, then include an import statement
to the session/scope, then load
+ // it in the manager
+ // FIXME
+ return m.loadOntologyFromOntologyDocument(file);
+ }
+
+ private List<Rule> prepareJenaRules(String recipe) {
+ if (recipe != null) {
+ // If recipe exists, parse it as a list of Jena rules
+ // TODO This cannot be implemented since Jena rules format is not
yet supported by the Rules
+ // module!!!
+ log.error("prepareJenaRules(String recipe) Not implemented yet!");
+ throw new WebApplicationException(501);
+ }
+ return null;
+ }
+
+ private List<SWRLRule> prepareOWLApiRules(String recipe) {
+ if (recipe != null) {
+ // If recipe exists, return it as a list of SWRL rules
+ log.error("prepareOWLApiRules(String recipe) Not implemented
yet!");
+ throw new WebApplicationException(501);
+ }
+ return null;
+ }
}
Copied:
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningPrettyResultResource.java
(from r1160643,
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningPrettyResultResource.java)
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningPrettyResultResource.java?p2=incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningPrettyResultResource.java&p1=incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningPrettyResultResource.java&r1=1160643&r2=1161197&rev=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/resources/ReasoningPrettyResultResource.java
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningPrettyResultResource.java
Wed Aug 24 16:39:34 2011
@@ -1,4 +1,4 @@
-package org.apache.stanbol.reasoners.web.resources;
+package org.apache.stanbol.reasoners.web.utils;
import javax.servlet.ServletContext;
import javax.ws.rs.core.UriInfo;
Added:
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningServiceExecutor.java
URL:
http://svn.apache.org/viewvc/incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningServiceExecutor.java?rev=1161197&view=auto
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningServiceExecutor.java
(added)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/java/org/apache/stanbol/reasoners/web/utils/ReasoningServiceExecutor.java
Wed Aug 24 16:39:34 2011
@@ -0,0 +1,302 @@
+package org.apache.stanbol.reasoners.web.utils;
+
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
+import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.stanbol.commons.web.base.format.KRFormat;
+import org.apache.stanbol.owl.transformation.JenaToClerezzaConverter;
+import org.apache.stanbol.owl.transformation.OWLAPIToClerezzaConverter;
+import org.apache.stanbol.reasoners.jena.JenaReasoningService;
+import org.apache.stanbol.reasoners.owlapi.OWLApiReasoningService;
+import org.apache.stanbol.reasoners.servicesapi.InconsistentInputException;
+import org.apache.stanbol.reasoners.servicesapi.ReasoningService;
+import org.apache.stanbol.reasoners.servicesapi.ReasoningServiceException;
+import org.apache.stanbol.reasoners.servicesapi.UnsupportedTaskException;
+import org.coode.owlapi.manchesterowlsyntax.ManchesterOWLSyntaxOntologyFormat;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.semanticweb.owlapi.model.OWLOntologyCreationException;
+import org.semanticweb.owlapi.model.OWLOntologyManager;
+import org.semanticweb.owlapi.model.OWLOntologyStorageException;
+import org.semanticweb.owlapi.model.SWRLRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.rdf.model.Statement;
+import com.hp.hpl.jena.reasoner.rulesys.Rule;
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * TODO Add comment
+ */
+public class ReasoningServiceExecutor {
+ private Logger log = LoggerFactory.getLogger(getClass());
+ private HttpHeaders headers;
+ private ServletContext servletContext;
+ private UriInfo uriInfo;
+ private TcManager tcManager;
+
+ // This task is not dinamically provided by the service, since it work on
a specific method
+ // (isConsistent())
+ public static String TASK_CHECK = "check";
+
+ public ReasoningServiceExecutor(
+ TcManager tcManager,
+ HttpHeaders headers,
+ ServletContext context,
+ UriInfo uriInfo) {
+ this.headers = headers;
+ this.servletContext = context;
+ this.uriInfo = uriInfo;
+ this.tcManager = tcManager;
+ }
+
+ /**
+ * Execute a JenaReasoningService
+ *
+ * TODO: Add parameter to decide if the output graph must be deleted if
exists
+ *
+ * @param s
+ * @param input
+ * @param rules
+ * @return
+ */
+ public Response executeJenaReasoningService(String task,
+ JenaReasoningService s,
+ Model input,
+ List<Rule> rules,
+ String targetGraphID,
+ boolean filtered,
+ Map<String,List<String>>
parameters) {
+ // Check task: this is managed directly by the endpoint
+ if (task.equals(ReasoningServiceExecutor.TASK_CHECK)) {
+ log.debug("Task is '{}'", ReasoningServiceExecutor.TASK_CHECK);
+ try {
+ return buildCheckResponse(s.isConsistent(input));
+ } catch (ReasoningServiceException e) {
+ log.error("Error thrown: {}", e);
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+ try {
+ Set<Statement> result = s.runTask(task, input, rules, filtered,
parameters);
+ if (result == null) {
+ log.error("Result is null");
+ throw new WebApplicationException();
+ }
+ Model outputModel = ModelFactory.createDefaultModel();
+ outputModel.add(result.toArray(new Statement[result.size()]));
+ // If target is null, then get back results, elsewhere put it in
target graph
+ if (targetGraphID == null) {
+ log.info("Returning {} statements", result.size());
+ if (isHTML()) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ outputModel.write(out, "TURTLE");
+ return Response.ok(
+ new Viewable("result",
+ new
ReasoningPrettyResultResource(servletContext, uriInfo, out)), TEXT_HTML)
+ .build();
+ } else {
+ return Response.ok(outputModel).build();
+ }
+ } else {
+ save(outputModel, targetGraphID);
+ return Response.ok().build();
+ }
+ } catch (ReasoningServiceException e) {
+ log.error("Error thrown: {}", e);
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (InconsistentInputException e) {
+ log.debug("The input is not consistent");
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (UnsupportedTaskException e) {
+ log.error("Error thrown: {}", e);
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Executes the OWLApiReasoingService
+ *
+ * @param task
+ * @param s
+ * @param input
+ * @param rules
+ * @param targetGraphID
+ * @param paramters
+ * @return
+ */
+ public Response executeOWLApiReasoningService(String task,
+ OWLApiReasoningService s,
+ OWLOntology input,
+ List<SWRLRule> rules,
+ String targetGraphID,
+ Map<String,List<String>>
paramters) {
+ // Check task: this is managed directly by the endpoint
+ if (task.equals(ReasoningServiceExecutor.TASK_CHECK)) {
+ log.debug("Task is '{}'", ReasoningServiceExecutor.TASK_CHECK);
+ try {
+ return buildCheckResponse(s.isConsistent(input));
+ } catch (ReasoningServiceException e) {
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+ // We get the manager from the input ontology
+ // XXX We must be aware of this.
+ OWLOntologyManager manager = input.getOWLOntologyManager();
+ try {
+ OWLOntology output = manager.createOntology();
+ manager.addAxioms(output, s.runTask(task, input));
+
+ if (targetGraphID == null) {
+ if (isHTML()) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ manager.saveOntology(output, new
ManchesterOWLSyntaxOntologyFormat(), out);
+ return Response.ok(
+ new Viewable("result",
+ new
ReasoningPrettyResultResource(servletContext, uriInfo, out)), TEXT_HTML)
+ .build();
+ } else {
+ return Response.ok(output).build();
+ }
+ } else {
+ save(output, targetGraphID);
+ return Response.ok().build();
+ }
+ } catch (ReasoningServiceException e) {
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (InconsistentInputException e) {
+ log.debug("The input is not consistent");
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (OWLOntologyCreationException e) {
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (OWLOntologyStorageException e) {
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (UnsupportedTaskException e) {
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * To build the Response for any CHECK task execution
+ *
+ * @param isConsistent
+ * @return
+ */
+ public Response buildCheckResponse(boolean isConsistent) {
+ if (isHTML()) {
+ if (isConsistent) {
+ log.debug("The input is consistent");
+ return Response.ok(
+ new Viewable("result", new
ReasoningPrettyResultResource(servletContext, uriInfo,
+ "The input is consistent :)")), TEXT_HTML).build();
+ } else {
+ log.debug("The input is not consistent");
+ return Response
+ .status(Status.NO_CONTENT)
+ .entity(
+ new Viewable("result", new
ReasoningPrettyResultResource(servletContext, uriInfo,
+ "The input is NOT consistent
:("))).type(TEXT_HTML).build();
+ }
+ } else {
+ if (isConsistent) {
+ log.debug("The input is consistent");
+ return Response.ok("The input is consistent :)").build();
+ } else {
+ log.debug("The input is not consistent");
+ return Response.status(Status.NO_CONTENT).build();
+ }
+ }
+ }
+
+ /**
+ * Check if the client needs a serialization of the output or a human
readable form (HTML)
+ *
+ * @param headers
+ * @return
+ */
+ public boolean isHTML() {
+ // We only want to state if HTML format is the preferred format
+ // requested
+ Set<String> htmlformats = new HashSet<String>();
+ htmlformats.add(TEXT_HTML);
+ Set<String> rdfformats = new HashSet<String>();
+ String[] formats = {TEXT_HTML, "text/plain", KRFormat.RDF_XML,
KRFormat.TURTLE, "text/turtle",
+ "text/n3"};
+ rdfformats.addAll(Arrays.asList(formats));
+ List<MediaType> mediaTypes = headers.getAcceptableMediaTypes();
+ for (MediaType t : mediaTypes) {
+ String strty = t.toString();
+ log.info("Acceptable is {}", t);
+ if (htmlformats.contains(strty)) {
+ log.debug("Requested format is HTML {}", t);
+ return true;
+ } else if (rdfformats.contains(strty)) {
+ log.debug("Requested format is RDF {}", t);
+ return false;
+ }
+ }
+ // Default behavior? Should never happen!
+ return true;
+ }
+
+ /**
+ * To save data in the triple store.
+ *
+ * @param data
+ * @param targetGraphID
+ */
+ protected void save(Object data, String targetGraphID) {
+ log.info("Attempt saving in target graph {}", targetGraphID);
+ final long startSave = System.currentTimeMillis();
+ LockableMGraph mGraph;
+ UriRef graphUriRef = new UriRef(targetGraphID);
+ try {
+ // Check whether the graph already exists
+ mGraph = tcManager.getMGraph(graphUriRef);
+ } catch (NoSuchEntityException e) {
+ mGraph = tcManager.createMGraph(graphUriRef);
+ }
+ // We lock the graph before proceed
+ Lock writeLock = mGraph.getLock().writeLock();
+ boolean saved = false;
+ if (data instanceof Model) {
+ MGraph m =
JenaToClerezzaConverter.jenaModelToClerezzaMGraph((Model) data);
+ writeLock.lock();
+ saved = mGraph.addAll(m);
+ writeLock.unlock();
+ } else if (data instanceof OWLOntology) {
+ MGraph m =
OWLAPIToClerezzaConverter.owlOntologyToClerezzaMGraph((OWLOntology) data);
+ writeLock.lock();
+ saved = mGraph.addAll(m);
+ writeLock.unlock();
+ }
+ if (!saved) throw new WebApplicationException(new IOException("Cannot
save model!"),
+ Response.Status.INTERNAL_SERVER_ERROR);
+ final long endSave = System.currentTimeMillis();
+ log.info("Save time: {}", (endSave - startSave));
+ }
+
+}
Modified:
incubator/stanbol/branches/jena-reasoners/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/branches/jena-reasoners/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl?rev=1161197&r1=1161196&r2=1161197&view=diff
==============================================================================
---
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl
(original)
+++
incubator/stanbol/branches/jena-reasoners/reasoners/web/src/main/resources/org/apache/stanbol/reasoners/web/templates/org/apache/stanbol/reasoners/web/resources/ReasoningServicesResource/index.ftl
Wed Aug 24 16:39:34 2011
@@ -36,8 +36,9 @@
<#list it.activeServices as service>
<li><b>${service.path}</b>:
<#list service.supportedTasks as task>
- <a href="/${it.currentPath}/${service.path}/${task}"
title="${service.class.name} Task: ${task}">${task}</a>
+ <a href="/${it.currentPath}/${service.path}/${task}"
title="${service.class.name} Task: ${task}">${task}</a> |
</#list>
+ <a href="/${it.currentPath}/${service.path}/check"
title="${service.class.name} Task: check">check</a>
</li>
</#list>
</ul>