Skip to content

Commit

Permalink
Add implementation of DIVIDE central services (version of 1 May 2022)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrdbrouw committed Sep 30, 2022
1 parent 3c2fbcd commit 6502e8d
Show file tree
Hide file tree
Showing 153 changed files with 17,153 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea/
55 changes: 55 additions & 0 deletions src/divide-central/divide-api/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>divide</artifactId>
<groupId>be.ugent.idlab</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>divide-api</artifactId>

<repositories>
<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>https://maven.restlet.org</url>
</repository>
</repositories>

<dependencies>
<!-- DIVIDE engine -->
<dependency>
<groupId>be.ugent.idlab</groupId>
<artifactId>divide-engine</artifactId>
<version>1.0</version>
</dependency>

<!-- Java Restlet: to set up REST APIs -->
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet</artifactId>
<version>2.3.6</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.slf4j</artifactId>
<version>2.2.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>

<!-- Google Gson: for JSON parsing -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package be.ugent.idlab.divide.api;

import be.ugent.idlab.divide.api.endpoints.component.ComponentEndpoint;
import be.ugent.idlab.divide.api.endpoints.component.GeneralComponentEndpoint;
import be.ugent.idlab.divide.api.endpoints.query.DivideQueryEndpoint;
import be.ugent.idlab.divide.api.endpoints.query.DivideQueryRegistrationAsRspQlEndpoint;
import be.ugent.idlab.divide.api.endpoints.query.DivideQueryRegistrationAsSparqlEndpoint;
import be.ugent.idlab.divide.api.endpoints.query.GeneralDivideQueryEndpoint;
import be.ugent.idlab.divide.core.engine.IDivideEngine;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import org.restlet.routing.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DivideApiApplication extends Application {

private static final Logger LOGGER = LoggerFactory.getLogger(DivideApiApplication.class.getName());

public static final String ATTR_DIVIDE_ENGINE = "divide_engine";

private final IDivideEngine divideEngine;

public DivideApiApplication(IDivideEngine divideEngine) {
this.divideEngine = divideEngine;
}

@Override
public Restlet createInboundRoot() {
getContext().getAttributes().put(ATTR_DIVIDE_ENGINE, divideEngine);

Router router = new Router(getContext());
router.setDefaultMatchingMode(Template.MODE_EQUALS);

router.attach(DivideRoutes.ENDPOINT_COMPONENT, ComponentEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_COMPONENT);
ComponentEndpoint.logEndpoints(LOGGER);

router.attach(DivideRoutes.ENDPOINT_COMPONENT_GENERAL, GeneralComponentEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_COMPONENT_GENERAL);
GeneralComponentEndpoint.logEndpoints(LOGGER);

router.attach(DivideRoutes.ENDPOINT_DIVIDE_QUERY, DivideQueryEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_DIVIDE_QUERY);
DivideQueryEndpoint.logEndpoints(LOGGER);

router.attach(DivideRoutes.ENDPOINT_DIVIDE_QUERY_REGISTER_AS_SPARQL,
DivideQueryRegistrationAsSparqlEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_DIVIDE_QUERY_REGISTER_AS_SPARQL);
DivideQueryRegistrationAsSparqlEndpoint.logEndpoints(LOGGER);

router.attach(DivideRoutes.ENDPOINT_DIVIDE_QUERY_REGISTER_AS_RSP_QL,
DivideQueryRegistrationAsRspQlEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_DIVIDE_QUERY_REGISTER_AS_RSP_QL);
DivideQueryRegistrationAsRspQlEndpoint.logEndpoints(LOGGER);

router.attach(DivideRoutes.ENDPOINT_DIVIDE_QUERY_GENERAL, GeneralDivideQueryEndpoint.class);
LOGGER.info("DIVIDE API endpoint {}", DivideRoutes.ENDPOINT_DIVIDE_QUERY_GENERAL);
GeneralDivideQueryEndpoint.logEndpoints(LOGGER);

return router;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package be.ugent.idlab.divide.api;

import be.ugent.idlab.divide.core.engine.IDivideEngine;
import org.restlet.Component;
import org.restlet.data.Protocol;

@SuppressWarnings("unused")
public class DivideApiComponentFactory {

/**
* Create a Restlet {@link Component} that can be started to host an API
* for the given DIVIDE engine. This DIVIDE API will be hosted via the
* HTTP protocol on the given host and port, on the root path,
* i.e., at http://[host]:[port]/.
*
* @param divideEngine DIVIDE engine that should be wrapped by the created
* API component
* @param host host at which the DIVIDE API should run
* @param port port at which the DIVIDE API should run
* @return a Restlet {@link Component} which can be started with the
* {@link Component#start()} method to host the DIVIDE API
*/
public static Component createRestApiComponent(IDivideEngine divideEngine,
String host,
int port) {
return createRestApiComponent(divideEngine, host, port, "");
}

/**
* Create a Restlet {@link Component} that can be started to host an API
* for the given DIVIDE engine. This DIVIDE API will be hosted via the
* HTTP protocol on the given host and port, on the specified uri path,
* i.e., at http://[host]:[port]/[uri].
*
* @param divideEngine DIVIDE engine that should be wrapped by the created
* API component
* @param host host at which the DIVIDE API should run
* @param port port at which the DIVIDE API should run
* @param uri path URI string at which the DIVIDE API should run
* @return a Restlet {@link Component} which can be started with the
* {@link Component#start()} method to host the DIVIDE API
*/
public static Component createRestApiComponent(IDivideEngine divideEngine,
String host,
int port,
String uri) {
// create Restlet component
Component component = new Component();
component.getServers().add(Protocol.HTTP, host, port);

// create and attach Servlet application
DivideApiApplication divideApiApplication = new DivideApiApplication(divideEngine);
component.getDefaultHost().attach(uri, divideApiApplication);

return component;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package be.ugent.idlab.divide.api;

import static be.ugent.idlab.divide.api.endpoints.CustomEndpoint.SERVER_ATTR_ID;

class DivideRoutes {

private static final String COMPONENT_ENTITY = "component";
private static final String QUERY_ENTITY = "query";

static final String ENDPOINT_COMPONENT_GENERAL =
"/" + COMPONENT_ENTITY;
static final String ENDPOINT_COMPONENT =
"/" + COMPONENT_ENTITY + "/{" + SERVER_ATTR_ID + "}";

static final String ENDPOINT_DIVIDE_QUERY_GENERAL =
"/" + QUERY_ENTITY;
static final String ENDPOINT_DIVIDE_QUERY =
"/" + QUERY_ENTITY + "/{" + SERVER_ATTR_ID + "}";
static final String ENDPOINT_DIVIDE_QUERY_REGISTER_AS_SPARQL =
"/" + QUERY_ENTITY + "/sparql/{" + SERVER_ATTR_ID + "}";
static final String ENDPOINT_DIVIDE_QUERY_REGISTER_AS_RSP_QL =
"/" + QUERY_ENTITY + "/rspql/{" + SERVER_ATTR_ID + "}";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package be.ugent.idlab.divide.api.endpoints;

import be.ugent.idlab.divide.api.DivideApiApplication;
import be.ugent.idlab.divide.core.engine.IDivideEngine;
import org.restlet.resource.ServerResource;

public abstract class CustomEndpoint extends ServerResource {

public static final String SERVER_ATTR_ID = "id";

protected IDivideEngine getDivideEngine() {
return (IDivideEngine) getContext().getAttributes().get(
DivideApiApplication.ATTR_DIVIDE_ENGINE);
}

protected String getIdAttribute() {
return (String) getRequest().getAttributes().get(SERVER_ATTR_ID);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package be.ugent.idlab.divide.api.endpoints.component;

import be.ugent.idlab.divide.api.endpoints.CustomEndpoint;
import be.ugent.idlab.divide.api.representation.component.ComponentRepresentation;
import be.ugent.idlab.divide.core.component.IComponent;
import be.ugent.idlab.divide.core.engine.IDivideEngine;
import be.ugent.idlab.divide.core.exception.DivideNotInitializedException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
import org.restlet.resource.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.Set;

public class ComponentEndpoint extends CustomEndpoint {

private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
private static final Logger LOGGER = LoggerFactory.getLogger(ComponentEndpoint.class.getName());

@Options
public void optionsRequestHandler() {
Set<Method> allowedMethods = new HashSet<>();
allowedMethods.add(Method.GET);
allowedMethods.add(Method.DELETE);
getResponse().setAccessControlAllowMethods(allowedMethods);
getResponse().setAccessControlAllowOrigin("*");
}

public static void logEndpoints(Logger logger) {
logger.info(" GET: retrieve DIVIDE component with ID {}", SERVER_ATTR_ID);
logger.info(" DELETE: unregister DIVIDE component with ID {}", SERVER_ATTR_ID);
}

@Get
public void getComponent() {
getResponse().setAccessControlAllowOrigin("*");

IDivideEngine divideEngine = getDivideEngine();

try {
String componentId = getIdAttribute();

IComponent component = divideEngine.getRegisteredComponentById(componentId);

if (component != null) {
ComponentRepresentation componentRepresentation =
new ComponentRepresentation(component);

String message = "Component with ID " + componentId + " successfully retrieved";
getResponse().setStatus(Status.SUCCESS_OK, message);
getResponse().setEntity(GSON.toJson(componentRepresentation),
MediaType.APPLICATION_JSON);

} else {
String message = "Component with ID '" + componentId + "' does not exist";
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);
}

} catch (DivideNotInitializedException e) {
String message = e.getMessage();
LOGGER.error(message, e);
getResponse().setStatus(Status.SERVER_ERROR_SERVICE_UNAVAILABLE, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);

} catch (Exception e) {
String logMessage = "Error while getting component data";
String eMessage = e.getMessage();
String message = logMessage + (eMessage != null ? ": " + eMessage : "");
LOGGER.error(logMessage, e);
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);

} finally {
getResponse().commit();
commit();
release();
}
}

@Delete
public void unregisterComponent(Representation rep) {
getResponse().setAccessControlAllowOrigin("*");

IDivideEngine divideEngine = getDivideEngine();

try {
String componentId = getIdAttribute();

IComponent component = divideEngine.getRegisteredComponentById(componentId);

if (component != null) {
// retrieve url parameter which specifies whether the queries of this
// component should be unregistered
// (default when it is not specified = false)
boolean unregisterQueries =
Boolean.parseBoolean(getQueryValue("unregister"));

divideEngine.unregisterComponent(componentId, unregisterQueries);

String message = "Component with ID " + componentId + " successfully unregistered";
getResponse().setStatus(Status.SUCCESS_NO_CONTENT, message);

} else {
String message = "Component with ID '" + componentId + "' does not exist";
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);
}

} catch (DivideNotInitializedException e) {
String message = e.getMessage();
LOGGER.error(message, e);
getResponse().setStatus(Status.SERVER_ERROR_SERVICE_UNAVAILABLE, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);

} catch (Exception e) {
String logMessage = "Error while unregistering component";
String eMessage = e.getMessage();
String message = logMessage + (eMessage != null ? ": " + eMessage : "");
LOGGER.error(logMessage, e);
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL, message);
getResponse().setEntity(message, MediaType.TEXT_PLAIN);

} finally {
getResponse().commit();
commit();
release();
}
}

}
Loading

0 comments on commit 6502e8d

Please sign in to comment.