[Mulgara-svn] r1514 - trunk/src/jar/querylang/java/org/mulgara/protocol/http
pag at mulgara.org
pag at mulgara.org
Tue Feb 17 16:07:00 UTC 2009
Author: pag
Date: 2009-02-17 08:07:00 -0800 (Tue, 17 Feb 2009)
New Revision: 1514
Modified:
trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
trunk/src/jar/querylang/java/org/mulgara/protocol/http/PublicSparqlServlet.java
Log:
Added REST support for creating and deleting graphs and individual statements. Also refactored the servlet to allow for deployment in a WAR
Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java 2009-02-17 16:05:29 UTC (rev 1513)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/ProtocolServlet.java 2009-02-17 16:07:00 UTC (rev 1514)
@@ -20,6 +20,7 @@
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
@@ -30,14 +31,12 @@
import javax.activation.MimeTypeParseException;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import org.apache.log4j.Logger;
import org.mulgara.connection.Connection;
-import org.mulgara.connection.SessionConnection;
import org.mulgara.parser.Interpreter;
import org.mulgara.protocol.StreamedAnswer;
import org.mulgara.query.Answer;
@@ -47,12 +46,15 @@
import org.mulgara.query.TuplesException;
import org.mulgara.query.operation.Command;
import org.mulgara.query.operation.CreateGraph;
+import org.mulgara.query.operation.Deletion;
+import org.mulgara.query.operation.DropGraph;
+import org.mulgara.query.operation.Insertion;
import org.mulgara.query.operation.Load;
-import org.mulgara.server.SessionFactory;
import org.mulgara.server.SessionFactoryProvider;
import org.mulgara.util.functional.C;
import org.mulgara.util.functional.Fn1E;
import org.mulgara.util.functional.Fn2;
+import org.mulgara.util.functional.Pair;
/**
* A query gateway for query languages.
@@ -61,11 +63,14 @@
* @author Paul Gearon
* @copyright © 2008 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
*/
-public abstract class ProtocolServlet extends HttpServlet {
+public abstract class ProtocolServlet extends MulgaraServlet {
/** Generated serialization ID. */
private static final long serialVersionUID = -6510062000251611536L;
+ /** The logger. */
+ final static Logger logger = Logger.getLogger(ProtocolServlet.class.getName());
+
/**
* Internal type definition of a function that takes "something" and an output stream,
* and returns a {@link StreamedAnswer}
@@ -111,9 +116,6 @@
/** The content type of the results. */
protected static final String CONTENT_TYPE = "application/sparql-results+xml";
- /** Session value for database connection. */
- private static final String CONNECTION = "session.connection";
-
/** Session value for interpreter. */
protected static final String INTERPRETER = "session.interpreter";
@@ -132,12 +134,18 @@
/** A made-up scheme for data uploaded through http-put, since http means "downloaded". */
protected static final String HTTP_PUT_NS = "http-put://upload/";
- /** The server for finding a session factory. */
- private SessionFactoryProvider server;
+ /** The various parameter names used to identify a graph in a request */
+ private static final String[] GRAPH_PARAM_NAMES = { DEFAULT_GRAPH_ARG, GRAPH_DATA };
- /** Session factory for accessing the database. */
- private SessionFactory cachedSessionFactory;
+ /** The various parameter names used to identify a subject in a request */
+ private static final String[] SUBJECT_PARAM_NAMES = { "subject", "subj", "s" };
+ /** The various parameter names used to identify a predicate in a request */
+ private static final String[] PREDICATE_PARAM_NAMES = { "predicate", "pred", "p" };
+
+ /** The various parameter names used to identify an object in a request */
+ private static final String[] OBJECT_PARAM_NAMES = { "object", "obj", "o" };
+
/** This object maps request types to the constructors for that output. */
protected final Map<Output,AnswerStreamConstructor> streamBuilders = new EnumMap<Output,AnswerStreamConstructor>(Output.class);
@@ -149,13 +157,21 @@
* @param server The server that provides access to the database.
*/
public ProtocolServlet(SessionFactoryProvider server) throws IOException {
- this.cachedSessionFactory = null;
- this.server = server;
+ super(server);
initializeBuilders();
}
/**
+ * Creates the servlet for communicating with the given server. Default construction,
+ * meaning that the connectionFactory will be used for establishing a connection.
+ */
+ public ProtocolServlet() throws IOException {
+ initializeBuilders();
+ }
+
+
+ /**
* Initialize the functional mappings of output types to the objects that manage them.
*/
abstract protected void initializeBuilders();
@@ -202,6 +218,40 @@
/**
+ * Responds to requests to create graphs or triples.
+ */
+ protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ try {
+ Pair<URI,LocalTriple> params = getModifyParams(req);
+ URI graph = params.first();
+ LocalTriple triple = params.second();
+ Connection conn = getConnection(req);
+ if (triple == null) createGraph(conn, graph);
+ else createTriple(conn, graph, triple);
+ } catch (ServletException e) {
+ e.sendResponseTo(resp);
+ }
+ }
+
+
+ /**
+ * Responds to requests to create graphs or triples.
+ */
+ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ try {
+ Pair<URI,LocalTriple> params = getModifyParams(req);
+ URI graph = params.first();
+ LocalTriple triple = params.second();
+ Connection conn = getConnection(req);
+ if (triple == null) deleteGraph(conn, graph);
+ else deleteTriple(conn, graph, triple);
+ } catch (ServletException e) {
+ e.sendResponseTo(resp);
+ }
+ }
+
+
+ /**
* Provide a description for the servlet.
* @see javax.servlet.GenericServlet#getServletInfo()
*/
@@ -500,41 +550,68 @@
/**
- * Gets the connection for the current session, creating it if it doesn't exist yet.
- * @param req The current request environment.
- * @return A connection that is tied to this HTTP session.
- * @throws IOException When an error occurs creating a new session.
+ * Creates a new graph.
+ * @param conn A connection to the database.
+ * @param graph The graph to create.
+ * @throws ServletException If there was an error creating the graph.
*/
- private Connection getConnection(HttpServletRequest req) throws IOException, IllegalStateException {
- HttpSession httpSession = req.getSession();
- Connection connection = (Connection)httpSession.getAttribute(CONNECTION);
- if (connection == null) {
- try {
- connection = new SessionConnection(getSessionFactory().newSession(), null, null);
- } catch (QueryException qe) {
- throw new IOException("Unable to create a connection to the database. " + qe.getMessage());
- }
- httpSession.setAttribute(CONNECTION, connection);
+ protected void createGraph(Connection conn, URI graph) throws ServletException {
+ try {
+ new CreateGraph(graph).execute(conn);
+ } catch (QueryException e) {
+ throw new InternalErrorException("Unable to create graph: " + e.getMessage());
}
- return connection;
}
/**
- * This method allows us to put off getting a session factory until the server is
- * ready to provide one.
- * @return A new session factory.
+ * Creates a triple in a graph.
+ * @param conn A connection to the database.
+ * @param graph The graph to create the triple in.
+ * @param triple The triple to create.
+ * @throws ServletException If there was an error creating the triple, or the graph does not exist.
*/
- private SessionFactory getSessionFactory() throws IllegalStateException {
- if (cachedSessionFactory == null) {
- cachedSessionFactory = server.getSessionFactory();
- if (cachedSessionFactory == null) throw new IllegalStateException("Server not yet ready. Try again soon.");
+ protected void createTriple(Connection conn, URI graph, LocalTriple triple) throws ServletException {
+ try {
+ new Insertion(graph, triple.toSet()).execute(conn);
+ } catch (QueryException e) {
+ throw new InternalErrorException("Unable to create triple: " + e.getMessage());
}
- return cachedSessionFactory;
}
/**
+ * Deletes a graph.
+ * @param conn A connection to the database.
+ * @param graph The graph to delete.
+ * @throws ServletException If there was an error removing the graph.
+ */
+ protected void deleteGraph(Connection conn, URI graph) throws ServletException {
+ try {
+ new DropGraph(graph).execute(conn);
+ } catch (QueryException e) {
+ throw new InternalErrorException("Unable to drop graph: " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Deletes a triple in a graph.
+ * @param conn A connection to the database.
+ * @param graph The graph to delete the triple from.
+ * @param triple The triple to delete.
+ * @throws ServletException If there was an error deleting the triple.
+ */
+ protected void deleteTriple(Connection conn, URI graph, LocalTriple triple) throws ServletException {
+ try {
+ new Deletion(graph, triple.toSet()).execute(conn);
+ } catch (QueryException e) {
+ throw new InternalErrorException("Unable to delete triple: " + e.getMessage());
+ }
+ }
+
+
+ /**
* Compare a parameter name to a set of known parameter names.
* @param name The name to check.
* @return <code>true</code> if the name is known. <code>false</code> if not known or <code>null</code>.
@@ -547,6 +624,57 @@
/**
+ * Get the parameters of a request to modify the store.
+ * @param req The HTTP request.
+ * @return A Pair containing the graph for the modification, and an optional triple to be
+ * modified in the graph.
+ * @throws ServletException If the request was improperly formed.
+ */
+ @SuppressWarnings("unchecked")
+ private Pair<URI,LocalTriple> getModifyParams(HttpServletRequest req) throws ServletException {
+ Map<String,String[]> params = req.getParameterMap();
+ String graphParam = getParam(GRAPH_PARAM_NAMES, params);
+ if (graphParam == null) throw new BadRequestException("No graph parameter defined.");
+ URI g;
+ try {
+ g = new URI(graphParam);
+ } catch (URISyntaxException e) {
+ throw new BadRequestException("Invalid graph name: " + graphParam);
+ }
+ String s = getParam(SUBJECT_PARAM_NAMES, params);
+ String p = getParam(PREDICATE_PARAM_NAMES, params);
+ String o = getParam(OBJECT_PARAM_NAMES, params);
+ if (s == null && p == null && o == null) return new Pair<URI,LocalTriple>(g, null);
+ return new Pair<URI,LocalTriple>(g, new LocalTriple(s, p, o, true));
+ }
+
+
+ /**
+ * Get the value of a parameter from a map. The parameter is identified by one of the elements
+ * found in the <var>keyNames</var> parameter.
+ * @param keyNames An array of alternative names for the one parameter.
+ * @param params A map of parameter names to values.
+ * @return The value for the parameter, or <code>null</code> if not found.
+ * @throws ServletException If the parameter appear more than once.
+ */
+ private String getParam(String[] keyNames, Map<String,String[]> params) throws ServletException {
+ boolean found = false;
+ String result = null;
+ for (String k: keyNames) {
+ if (params.containsKey(k)) {
+ if (found) throw new BadRequestException("Duplicate parameter: " + k);
+ String[] values = params.get(k);
+ if (values.length == 0) throw new BadRequestException("Unsupplied parameter: " + k);
+ if (values.length > 1) throw new BadRequestException("Duplicate values for " + k + ": " + Arrays.asList(values));
+ result = values[0];
+ found = true;
+ }
+ }
+ return result;
+ }
+
+
+ /**
* Determine the type of response we need.
* @param req The request object for the servlet connection.
* @return xml, json, rdfXml or rdfN3.
@@ -599,4 +727,5 @@
static Output forMime(String mimeText) { return outputs.get(mimeText); }
}
+
}
Modified: trunk/src/jar/querylang/java/org/mulgara/protocol/http/PublicSparqlServlet.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/http/PublicSparqlServlet.java 2009-02-17 16:05:29 UTC (rev 1513)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/http/PublicSparqlServlet.java 2009-02-17 16:07:00 UTC (rev 1514)
@@ -64,6 +64,12 @@
resp.sendError(SC_METHOD_NOT_ALLOWED, "This is a Read Only service.");
}
+ /**
+ * Respond to a request for the servlet. This may handle update queries.
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ resp.sendError(SC_METHOD_NOT_ALLOWED, "This is a Read Only service.");
+ }
-
}
More information about the Mulgara-svn
mailing list