Package org.apache.marmotta.platform.ldpath.webservices

Source Code of org.apache.marmotta.platform.ldpath.webservices.LDPathWebService

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.marmotta.platform.ldpath.webservices;

import static org.apache.marmotta.commons.sesame.repository.ResultUtils.iterable;
import static org.apache.marmotta.commons.sesame.repository.ExceptionUtils.handleRepositoryException;

import org.apache.commons.io.IOUtils;
import org.apache.marmotta.platform.ldpath.api.LDPathService;
import org.apache.marmotta.commons.sesame.repository.ResourceUtils;
import org.apache.marmotta.commons.util.JSONUtils;

import org.apache.marmotta.platform.core.api.triplestore.SesameService;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiStringLiteral;
import org.apache.marmotta.ldpath.api.functions.SelectorFunction;
import org.apache.marmotta.ldpath.backend.sesame.SesameConnectionBackend;
import org.apache.marmotta.ldpath.exception.LDPathParseException;
import org.openrdf.model.Namespace;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.slf4j.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import java.io.IOException;
import java.text.Collator;
import java.util.*;

/**
* Execute LDPath queries against the LMF backend. Depending on the LMF configuration, this might trigger retrieval
* of external Linked Data resources before returning results.
*
* <p/>
* Author: Sebastian Schaffert
*/
@ApplicationScoped
@Path("/ldpath")
public class LDPathWebService {


    @Inject
    private Logger log;

    @Inject
    private LDPathService ldPathService;

    @Inject
    private SesameService sesameService;

    /**
     * Evaluate a single LDPath selection using the path passed as argument and starting at the resource identified
     * by the uri. Returns a list of RDF Nodes using the same syntax as RDF/JSON, i.e.
     * <ul>
     * <li> <code>{ "type": "uri", "value": "..." }</code> for resources</li>
     * <li><code>{ "type": "literal", "value": "...", "language": "...", "datatype": "..."}</code> for literals (datatype and language optional)</li>
     * </ul>
     *
     * @param path         the LDPath expression to evaluate
     * @param resourceUri  the URI of the resource from which to start the resource
     *
     * @return a list of RDF Nodes using the same syntax as RDF/JSON
     * @HTTP 404 in case the resource with the given URI does not exist
     * @HTTP 400 in case the path could not be parsed or the resource is not a valid URI
     * @HTTP 200 in case the query was evaluated successfully
     */
    @GET
    @Path("/path")
    @Produces("application/json")
    public Response evaluatePathQuery(@QueryParam("path") String path, @QueryParam("uri") String resourceUri) {
        //Preconditions.checkArgument(urlValidator.isValid(resourceUri));

        try {
            RepositoryConnection con = sesameService.getConnection();
            try {
                con.begin();
                if (ResourceUtils.isSubject(con, resourceUri)) {
                    URI resource = con.getValueFactory().createURI(resourceUri);
                    // get list of configured namespaces; we make them available for the path language
                    Map<String,String> namespaces = new HashMap<String, String>();
                    for(Namespace ns : iterable(con.getNamespaces())) {
                        namespaces.put(ns.getPrefix(),ns.getName());
                    }

                    List<Map<String,String>> result = new ArrayList<Map<String, String>>();

                    try {
                        for(Value node : ldPathService.pathQuery(resource,path,namespaces)) {
                            result.add(JSONUtils.serializeNodeAsJson(node));
                        }
                        return Response.ok().entity(result).build();
                    } catch (LDPathParseException e) {
                        log.warn("parse error while evaluating path {}: {}",path,e.getMessage());
                        return Response.status(Response.Status.BAD_REQUEST).entity("parse error while evaluating path '"+path+"': "+e.getMessage()).build();
                    }

                } else
                    return Response.status(Response.Status.NOT_FOUND).entity("resource "+resourceUri+" does not exist").build();
            } finally {
                con.commit();
                con.close();
            }
        } catch (RepositoryException ex) {
            handleRepositoryException(ex,LDPathWebService.class);
            return Response.serverError().entity("error accessing RDF repository: "+ex.getMessage()).build();
        }

    }

    /**
     * Evaluate a LDPath program using the program string passed as argument and starting at the resource identified
     * by the uri. Returns a map from field names to lists of RDF nodes using the same syntax as RDF/JSON, i.e.
     * <ul>
     * <li> <code>{ "type": "uri", "value": "..." }</code> for resources</li>
     * <li><code>{ "type": "literal", "value": "...", "language": "...", "datatype": "..."}</code> for literals (datatype and language optional)</li>
     * </ul>
     *
     * @param program      the program to evaluate
     * @param resourceUri  the URI of the resource where to start
     * @return a map from field names to lists of rdf nodes in rdf/json format
     * @HTTP 404 in case the resource with the given URI does not exist
     * @HTTP 400 in case the path could not be parsed or the resource is not a valid URI
     * @HTTP 200 in case the query was evaluated successfully
     */
    @GET
    @Path("/program")
    @Produces("application/json")
    public Response evaluateProgramQuery(@QueryParam("program") String program, @QueryParam("uri") String resourceUri) {
        //Preconditions.checkArgument(urlValidator.isValid(resourceUri));

        try {
            RepositoryConnection con = sesameService.getConnection();
            try {
                con.begin();
                if (ResourceUtils.isSubject(con, resourceUri)) {
                    URI resource = con.getValueFactory().createURI(resourceUri);
                    // get list of configured namespaces; we make them available for the path language
                    Map<String,String> namespaces = new HashMap<String, String>();
                    for(Namespace ns : iterable(con.getNamespaces())) {
                        namespaces.put(ns.getPrefix(),ns.getName());
                    }


                    Map<String,List<Map<String,String>>> result = new HashMap<String, List<Map<String, String>>>();

                    try {
                        for(Map.Entry<String,Collection<?>> row : ldPathService.programQuery(resource,program).entrySet()) {
                            List<Map<String,String>> rowList = new ArrayList<Map<String, String>>();
                            for(Object o : row.getValue()) {
                                if(o instanceof KiWiNode) {
                                    rowList.add(JSONUtils.serializeNodeAsJson((Value) o));
                                } else {
                                    // we convert always to a literal
                                    rowList.add(JSONUtils.serializeNodeAsJson(new KiWiStringLiteral(o.toString())));
                                }
                            }
                            result.put(row.getKey(),rowList);
                        }
                        return Response.ok().entity(result).build();
                    } catch (LDPathParseException e) {
                        log.warn("parse error while evaluating program {}: {}", program, e.getMessage());
                        return Response.status(Response.Status.BAD_REQUEST).entity("parse error while evaluating program: "+e.getMessage()).build();
                    }


                } else
                    return Response.status(Response.Status.NOT_FOUND).entity("resource "+resourceUri+" does not exist").build();
            } finally {
                con.commit();
                con.close();
            }
        } catch (RepositoryException ex) {
            handleRepositoryException(ex,LDPathWebService.class);
            return Response.serverError().entity("error accessing RDF repository: "+ex.getMessage()).build();
        }
    }


    /**
     * Return a list of all LDPath functions that have been registered in the LDPath installation.
     *
     * @HTTP 200 in case the functions exist; will return the function descriptions
     * @HTTP 500 in case there was an error accessing the triple store
     *
     * @return a list of JSON maps with the fields "name", "signature" and "description"
     */
    @GET
    @Path("/functions")
    @Produces("application/json")
    public Response listFunctions() {
        List<Map<String,String>> results = new ArrayList<Map<String, String>>();

        try {
            RepositoryConnection con = sesameService.getConnection();
            try {
                con.begin();
                SesameConnectionBackend backend = SesameConnectionBackend.withConnection(con);
                for(SelectorFunction<Value> function : ldPathService.getFunctions()) {
                    Map<String,String> fmap = new HashMap<String, String>();
                    fmap.put("name", function.getPathExpression(backend));
                    fmap.put("signature",function.getSignature());
                    fmap.put("description",function.getDescription());
                    results.add(fmap);
                }
            } finally {
                con.commit();
                con.close();
            }
        } catch (RepositoryException e) {
            return Response.serverError().entity(e).build();
        }
        Collections.sort(results, new Comparator<Map<String, String>>() {
            @Override
            public int compare(Map<String, String> o1, Map<String, String> o2) {
                return Collator.getInstance().compare(o1.get("name"),o2.get("name"));
            }
        });

        return Response.ok().entity(results).build();
    }

    /**
     * Return a description of the function whose name is passed as path argument.
     *
     * @HTTP 200 in case the function exists; will return the function description
     * @HTTP 404 in case the function does not exist
     * @HTTP 500 in case there was an error accessing the triple store
     *
     * @return a JSON map with the fields "name", "signature" and "description"
     */
    @GET
    @Path("/functions/{name}")
    @Produces("application/json")
    public Response getFunction(@PathParam("name") String name) {
        try {
            RepositoryConnection con = sesameService.getConnection();
            try {
                con.begin();
                SesameConnectionBackend backend = SesameConnectionBackend.withConnection(con);

                for (SelectorFunction<Value> function : ldPathService.getFunctions()) {
                    final String fName = function.getPathExpression(backend);
                    if (name.equals(fName)) {
                        Map<String, String> fmap = new HashMap<String, String>();
                        fmap.put("name", fName);
                        fmap.put("signature", function.getSignature());
                        fmap.put("description", function.getDescription());
                        return Response.ok(fmap).build();
                    }
                }
                return Response.status(Status.NOT_FOUND).entity("LDPath function with name " + name + " does not exist").build();
            } finally {
                con.commit();
                con.close();
            }
        } catch (RepositoryException e) {
            return Response.serverError().entity(e).build();
        }
    }

    /**
     * Evaluate the LDPath program send as byte stream in the POST body of the request starting at the contexts (array)
     * given as URL query arguments. Will return a JSON map with an entry for each context and its evaluation result.
     * The value of each entry will have the following format:
     * <ul>
     * <li><code>{ "type": "uri", "value": "..." }</code> for resources</li>
     * <li><code>{ "type": "literal", "value": "...", "language": "...", "datatype": "..."}</code> for literals (datatype and language optional)</li>
     * </ul>

     *
     * @HTTP 200 in case the evaluation was successful for all contexts
     * @HTTP 400 in case the LDPath program was invalid
     * @HTTP 404 in case one of the contexts passed as argument does not exist
     * @HTTP 500 in case there was an error accessing the repository or reading the POST body
     *
     * @param contextURI     the URI of a single context to evaluate the program against
     * @param contextURIarr  an array of URIs to use as contexts to evaluate the program against
     * @param request        a POST request containing the LDPath program in the POST body
     * @return a JSON map with an entry for each context pointing to its evaluation result (another map with field/value pairs)
     */
    @POST
    @Path("/debug")
    @Produces("application/json")
    public Response testProgram(@QueryParam("context") String[] contextURI, @QueryParam("context[]") String[] contextURIarr,  @Context HttpServletRequest request) {
        final String[] cs = contextURI != null ? contextURI : contextURIarr;

        try {
            // 1. read in the program from the post stream
            String program = IOUtils.toString(request.getReader());

            // 2. auto-register all namespaces that are defined in the triple store
            Map<String,String> namespaces = new HashMap<String, String>();
            RepositoryConnection con = sesameService.getConnection();
            try {
                con.begin();
                for(Namespace ns : iterable(con.getNamespaces())) {
                    namespaces.put(ns.getPrefix(),ns.getName());
                }

                // 3. iterate over all context uris passed as argument and run the path query, storing the results
                //    in a hashmap where the context uris are the keys and a result map is the value
                HashMap<String, Object> combined = new HashMap<String, Object>();
                for(String context : cs) {
                    if (ResourceUtils.isSubject(con, context)) {
                        URI resource = con.getValueFactory().createURI(context);

                        Map<String,List<Map<String,String>>> result = new HashMap<String, List<Map<String, String>>>();

                        try {
                            for(Map.Entry<String,Collection<?>> row : ldPathService.programQuery(resource,program).entrySet()) {
                                List<Map<String,String>> rowList = new ArrayList<Map<String, String>>();
                                for(Object o : row.getValue()) {
                                    if(o instanceof KiWiNode) {
                                        rowList.add(JSONUtils.serializeNodeAsJson((Value) o));
                                    } else {
                                        // we convert always to a literal
                                        rowList.add(JSONUtils.serializeNodeAsJson(new KiWiStringLiteral(o.toString())));
                                    }
                                }
                                result.put(row.getKey(),rowList);
                            }

                            combined.put(context,result);
                        } catch (LDPathParseException e) {
                            log.warn("parse error while evaluating program {}: {}", program, e.getMessage());
                            return Response.status(Response.Status.BAD_REQUEST).entity("parse error while evaluating program: "+e.getMessage()).build();
                        }
                    }  else {
                        return Response.status(Response.Status.NOT_FOUND).entity("resource "+context+" does not exist").build();
                    }
                }


                return Response.ok(combined).build();
            } finally {
                con.commit();
                con.close();
            }
        } catch (RepositoryException ex) {
            handleRepositoryException(ex,LDPathWebService.class);
            return Response.serverError().entity("error accessing RDF repository: "+ex.getMessage()).build();
        } catch(IOException ex) {
            return Response.serverError().entity("error reading program from stream: "+ex.getMessage()).build();
        }
    }

}
TOP

Related Classes of org.apache.marmotta.platform.ldpath.webservices.LDPathWebService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.