All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.inria.edelweiss.kgramserver.webservice.DqpRestAPI Maven / Gradle / Ivy

The newest version!
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.inria.edelweiss.kgramserver.webservice;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import fr.inria.acacia.corese.exceptions.EngineException;
import fr.inria.edelweiss.kgdqp.core.Messages;
import fr.inria.edelweiss.kgdqp.core.ProviderImplCostMonitoring;
import fr.inria.edelweiss.kgdqp.core.QueryProcessDQP;
import fr.inria.edelweiss.kgdqp.core.Util;
import fr.inria.edelweiss.kgdqp.core.WSImplem;
import fr.inria.edelweiss.kgenv.parser.Pragma;
import fr.inria.edelweiss.kgram.api.core.Entity;
import fr.inria.edelweiss.kgram.core.Mapping;
import fr.inria.edelweiss.kgram.core.Mappings;
import fr.inria.edelweiss.kgraph.core.Graph;
import fr.inria.edelweiss.kgraph.query.QueryProcess;
import fr.inria.edelweiss.kgtool.print.JSOND3Format;
import fr.inria.edelweiss.kgtool.print.JSONFormat;
import fr.inria.edelweiss.kgtool.print.ResultFormat;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.apache.commons.lang.time.StopWatch;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

/**
 * REST API to expose main features of the KGRAM-DQP federation engine.
 *
 * @author Alban Gaignard, [email protected]
 */
@Path("dqp")
public class DqpRestAPI {

    private Logger logger = LogManager.getLogger(DqpRestAPI.class);
    private static Graph graph = Graph.create(false);
    private static ProviderImplCostMonitoring sProv = ProviderImplCostMonitoring.create();
    private static QueryProcessDQP execDQP = QueryProcessDQP.create(graph, sProv, false);

    /**
     * This web service reset the local KGRAM graph. By default, RDFS
     * entailments and provenance are desactivated.
     *
     * @return a confirmation message to be possibly displayed from client side.
     */
    @POST
    @Path("/reset")
    public Response resetDQP() {
        try {
            DqpRestAPI.graph = Graph.create(false);
            DqpRestAPI.sProv = ProviderImplCostMonitoring.create();
            DqpRestAPI.execDQP = QueryProcessDQP.create(graph, sProv, false);

            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity("Reinitialized KGRAM-DQP federation engine").build();
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("Exception while reseting KGRAM-DQP").build();
        }
    }

    /**
     * Web service adding a new sparql endpoint url to the federation engine.
     *
     * @param endpointURL the URL of the SPARQL endpoint to be federated.
     * @return a confirmation message to be possibly displayed from client side.
     */
    @POST
    @Path("/configureDatasources")
    public Response addDataSource(@FormParam("endpointUrl") String endpointURL) {

        if ((endpointURL == null) || (endpointURL.isEmpty())) {
            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity("Empty list of data sources !").build();
        }

        String output = "";
        try {
            execDQP.addRemote(new URL(endpointURL), WSImplem.REST);
            output += endpointURL;
            output += " added to the federation engine";
            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(output).build();
        } catch (MalformedURLException ex) {
            logger.error(endpointURL + " is a malformed URL");
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("URL exception while configuring KGRAM-DQP").build();
        }
    }

    /**
     * Web service testing if a SPARQL endpoint is available.
     *
     * @param endpointURL the URL of the SPARQL endpoint to be tested.
     * @return JSON data with true or false depending on the availability of the
     * endpoint.
     */
    @POST
    @Path("/testDatasources")
    @Produces("application/sparql-results+json")
    public Response testDataSource(@FormParam("endpointUrl") String endpointURL) {

        if ((endpointURL == null) || (endpointURL.isEmpty())) {
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("{\"test\" : false}").build();
        }

        try {
            String query = "PREFIX foaf: "
                    + "SELECT distinct ?x ?p ?y WHERE"
                    + "{"
                    + "     ?x ?p ?y ."
                    + "}"
                    + "     LIMIT 1";

            ClientConfig config = new DefaultClientConfig();
            Client client = Client.create(config);
            WebResource service = client.resource(new URI(endpointURL));
            String response = service.queryParam("query", query).accept("application/sparql-results+xml").get(String.class);

            if (response.contains("sparql-results")) {
                return Response.status(200).header("Access-Control-Allow-Origin", "*").entity("{\"test\" : true}").build();
            } else {
                return Response.status(200).header("Access-Control-Allow-Origin", "*").entity("{\"test\" : false}").build();
            }

        } catch (URISyntaxException ex) {
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("{\"test\" : false}").build();
        } catch (ClientHandlerException ex) {
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("{\"test\" : false}").build();
        }

    }

    /**
     * Web service for federated query processing.
     *
     * @param query the initial SPARQL query.
     * @param tpgrouping a boolean for enabling/disabling tripple patterns
     * grouping into SERVICE clauses.
     * @param slicing an integer value describing the slicing parameter, used to
     * transmit intermediate bindings by blocks. The slice number corresponds to
     * the size of each block of bindings.
     * @return a JSON serialization of the SPARQL results.
     */
    @GET
    @Produces("application/sparql-results+json")
    @Path("/sparql")
    public Response getTriplesJSONForGet(@QueryParam("query") String query, @DefaultValue("false") @QueryParam("tpgrouping") String tpgrouping, @QueryParam("slicing") String slicing) {

        QueryProcessDQP.queryCounter.clear();
        QueryProcessDQP.queryVolumeCounter.clear();
        QueryProcessDQP.sourceCounter.clear();
        QueryProcessDQP.sourceVolumeCounter.clear();

        logger.info("Federated querying: " + query);

        // for TP groupping in SERVICE clauses
        if (!tpgrouping.equals("false")) {
            DqpRestAPI.execDQP.setGroupingEnabled(true);
            logger.info("Service grouping enabled");

            // for slicing in SERVICE clauses
            try {
                int sliceNb = Integer.valueOf(slicing);
                if (sliceNb > 0) {
                    DqpRestAPI.execDQP.addPragma(Pragma.SERVICE, Pragma.SLICE, sliceNb);
                    logger.info("Slicing set to " + sliceNb);
                }
            } catch (NumberFormatException ex) {
                logger.warn(slicing + " is not formatted as number for the slicing parameter");
                logger.warn("Slicing disabled");
            }
        }

        try {
            StopWatch sw = new StopWatch();
            sw.start();
            Mappings map = execDQP.query(query);
            sw.stop();
            logger.info(Util.jsonDqpCost(QueryProcessDQP.queryCounter, QueryProcessDQP.queryVolumeCounter, QueryProcessDQP.sourceCounter, QueryProcessDQP.sourceVolumeCounter));
            logger.info(map.size() + " results in " + sw.getTime() + "ms");
            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(JSONFormat.create(map).toString()).build();
        } catch (EngineException ex) {
            logger.error("Error while querying the remote KGRAM-DQP engine");
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("Error while querying the remote KGRAM engine").build();
        }
    }

    /**
     * Web service for federated query processing with provenance documented
     * results.
     *
     * @param query the SPARQL query to be sent over the federation.
     * @return JSON data describing SPARQL results and the associated PROV
     * graph.
     */
    @GET
    @Produces("application/sparql-results+json")
    @Path("/sparqlprov")
    public Response getProvTriplesJSONForGet(@QueryParam("query") String query, @DefaultValue("false") @QueryParam("tpgrouping") String tpgrouping, @QueryParam("slicing") String slicing) {

        DqpRestAPI.sProv = ProviderImplCostMonitoring.create();
        DqpRestAPI.execDQP.set(sProv);
        
        DqpRestAPI.execDQP.setProvEnabled(true);
        DqpRestAPI.sProv.setProvEnabled(true);
        logger.info("Federated querying: " + query);

        QueryProcessDQP.queryCounter.clear();
        QueryProcessDQP.queryVolumeCounter.clear();
        QueryProcessDQP.sourceCounter.clear();
        QueryProcessDQP.sourceVolumeCounter.clear();

        logger.info("Federated querying: " + query);

        // for TP groupping in SERVICE clauses
        if (!tpgrouping.equals("false")) {
            DqpRestAPI.execDQP.setGroupingEnabled(true);
            logger.info("Service grouping enabled");

            // for slicing in SERVICE clauses
            try {
                int sliceNb = Integer.valueOf(slicing);
                if (sliceNb > 0) {
                    DqpRestAPI.execDQP.addPragma(Pragma.SERVICE, Pragma.SLICE, sliceNb);
                    logger.info("Slicing set to " + sliceNb);
                }
            } catch (NumberFormatException ex) {
                logger.warn(slicing + " is not formatted as number for the slicing parameter");
                logger.warn("Slicing disabled");
            }
        }

        try {
            StopWatch sw = new StopWatch();
            sw.start();
            Mappings maps = execDQP.query(query);
            logger.info(maps.size() + " results in " + sw.getTime() + "ms");
            logger.info(Util.jsonDqpCost(QueryProcessDQP.queryCounter, QueryProcessDQP.queryVolumeCounter, QueryProcessDQP.sourceCounter, QueryProcessDQP.sourceVolumeCounter));

            Graph resProv = Graph.create();

            for (Mapping map : maps) {
                for (Entity ent : map.getEdges()) {
                    Graph prov = (Graph) ent.getProvenance();
                    if (prov != null) {
                        resProv.copy(prov);
                    }
                }
            }

            //For service provenance, to be cleaned
            if (sProv.getProvenance() != null) {
                resProv.copy(sProv.getProvenance());
            }

            //Filtering PROV annotations
            String provQuery = "PREFIX prov:<" + Util.provPrefix + ">"
                    + "CONSTRUCT {"
                    + " ?x ?p ?y ."
                    + "} WHERE {"
                    + " ?x ?p ?y ."
                    + " FILTER (?p NOT IN (rdf:type, prov:wasGeneratedBy, prov:qualifiedAssociation, prov:hadPlan, prov:agent, rdfs:comment)) "
                    + "} ";

//            String provQuery = "PREFIX prov:<" + Util.provPrefix + ">"
//                + "CONSTRUCT {"
//                + " ?x ?p ?y ."
//                + "} WHERE {"
//                + " ?x ?p ?y ."
//                + " FILTER (?p NOT IN (rdf:type)) "
//                + "} ";
//            String provQuery2 = "PREFIX prov:<" + Util.provPrefix + ">"
//                + "CONSTRUCT {"
//                + " ?s prov:wasAttributedTo ?ds ."
//                + " ?o prov:wasAttributedTo ?ds ."
//                + " ?s ?p ?o ."
//                + "} WHERE {"
//                + " ?x prov:wasAttributedTo ?ds ."
//                + " ?x rdf:subject ?s ."
//                + " ?x rdf:predicate ?p ."
//                + " ?x rdf:object ?o ."
//                + "}";
            QueryProcess qpProv = QueryProcess.create(resProv);
            Mappings mProv = qpProv.query(provQuery);

            String mapsProvJson = "{ \"mappings\" : "
                    + JSONFormat.create(maps).toString()
                    + " , "
                    + "\"d3\" : "
                    + JSOND3Format.create((Graph) mProv.getGraph()).toString()
                    + " }";

            execDQP.setProvEnabled(false);
            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(mapsProvJson).build();
        } catch (EngineException ex) {
            logger.error("Error while querying the remote KGRAM-DQP engine");
            logger.error(ex.getMessage());
            execDQP.setProvEnabled(false);
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("Error while querying the remote KGRAM engine").build();
        }
    }

    /**
     * Web service for federated query processing with XML SPARQL results.
     *
     * @param query the initial SPARQL query.
     * @return the XML sparql results.
     */
    @GET
    @Produces("application/sparql-results+xml")
    @Path("/sparql")
    public Response getTriplesXMLForGet(@QueryParam("query") String query) {

        QueryProcessDQP.queryCounter.clear();
        QueryProcessDQP.queryVolumeCounter.clear();
        QueryProcessDQP.sourceCounter.clear();
        QueryProcessDQP.sourceVolumeCounter.clear();

        logger.info("Federated querying: " + query);

        try {
            StopWatch sw = new StopWatch();
            sw.start();
            Mappings map = execDQP.query(query);
            logger.info(map.size() + " results in " + sw.getTime() + "ms");
            logger.info(Util.jsonDqpCost(QueryProcessDQP.queryCounter, QueryProcessDQP.queryVolumeCounter, QueryProcessDQP.sourceCounter, QueryProcessDQP.sourceVolumeCounter));
            return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(ResultFormat.create(map).toString()).build();
        } catch (EngineException ex) {
            logger.error("Error while querying the remote KGRAM-DQP engine");
            logger.error(ex.getMessage());
            return Response.status(500).header("Access-Control-Allow-Origin", "*").entity("Error while querying the remote KGRAM engine").build();
        }
    }

    /**
     * Get the current monitored distributed query processing cost.
     *
     * @return the cost serialized into JSON.
     */
    @GET
    @Path("/getCost")
    public Response getCost() {
        String response = Util.jsonDqpCost(QueryProcessDQP.queryCounter, QueryProcessDQP.queryVolumeCounter, QueryProcessDQP.sourceCounter, QueryProcessDQP.sourceVolumeCounter);
        return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(response).build();
    }

    private void logCost() {
        logger.info(Messages.countQueries);
        logger.info(Util.prettyPrintCounter(QueryProcessDQP.queryCounter));
        logger.info(Messages.countTransferredResults);
        logger.info(Util.prettyPrintCounter(QueryProcessDQP.queryVolumeCounter));
        logger.info(Messages.countDS);
        logger.info(Util.prettyPrintCounter(QueryProcessDQP.sourceCounter));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy