/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.rdf.sail.webapp; import java.io.IOException; import java.util.Collections; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.openrdf.model.URI; import org.openrdf.model.impl.URIImpl; import com.bigdata.rdf.sail.webapp.client.MiniMime; /** * Default dispatch pattern for a core REST API. * * @author Martyn Cutcher */ public class RESTServlet extends BigdataRDFServlet { private static final transient Logger log = Logger .getLogger(RESTServlet.class); static { // // pull a Tinkerpop interface into the class loader // log.info(com.tinkerpop.blueprints.Graph.class.getName()); // log.info(org.apache.avro.Schema.class.getName()); } /** * */ private static final long serialVersionUID = 1L; /* * The delegates to which we dispatch the various requests. */ private QueryServlet m_queryServlet; private InsertServlet m_insertServlet; private DeleteServlet m_deleteServlet; private UpdateServlet m_updateServlet; private WorkbenchServlet m_workbenchServlet; private BlueprintsServletProxy m_blueprintsServlet; private MapgraphServletProxy m_mapgraphServlet; /** * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/584"> * DESCRIBE CACHE </a> */ private DescribeCacheServlet m_describeServlet; public RESTServlet() { } /** * Overridden to create and initialize the delegate {@link Servlet} * instances. */ @Override public void init() throws ServletException { super.init(); m_queryServlet = new QueryServlet(); m_insertServlet = new InsertServlet(); m_updateServlet = new UpdateServlet(); m_deleteServlet = new DeleteServlet(); m_describeServlet = new DescribeCacheServlet(); m_workbenchServlet = new WorkbenchServlet(); { final String provider = this .getInitParameter(ConfigParams.BLUEPRINTS_SERVLET_PROVIDER); final String blueprintsProvider = provider == null || provider.equals("") ? ConfigParams.DEFAULT_BLUEPRINTS_SERVLET_PROVIDER : provider; m_blueprintsServlet = BlueprintsServletProxy.BlueprintsServletFactory .getInstance(blueprintsProvider); } { final String provider = this .getInitParameter(ConfigParams.MAPGRAPH_SERVLET_PROVIDER); final String mapgraphProvider = provider == null || provider.equals("") ? ConfigParams.DEFAULT_MAPGRAPH_SERVLET_PROVIDER : provider; m_mapgraphServlet = new MapgraphServletProxy.MapgraphServletFactory() .getInstance(mapgraphProvider); } m_queryServlet.init(getServletConfig()); m_insertServlet.init(getServletConfig()); m_updateServlet.init(getServletConfig()); m_deleteServlet.init(getServletConfig()); m_describeServlet.init(getServletConfig()); m_workbenchServlet.init(getServletConfig()); m_blueprintsServlet.init(getServletConfig()); m_mapgraphServlet.init(getServletConfig()); } /** * Overridden to destroy the delegate {@link Servlet} instances. */ @Override public void destroy() { if (m_queryServlet != null) { m_queryServlet.destroy(); m_queryServlet = null; } if (m_insertServlet != null) { m_insertServlet.destroy(); m_insertServlet = null; } if (m_updateServlet != null) { m_updateServlet.destroy(); m_updateServlet = null; } if (m_deleteServlet != null) { m_deleteServlet.destroy(); m_deleteServlet = null; } if (m_describeServlet != null) { m_describeServlet.destroy(); m_describeServlet = null; } if (m_workbenchServlet != null) { m_workbenchServlet.destroy(); m_workbenchServlet = null; } if (m_blueprintsServlet != null) { m_blueprintsServlet.destroy(); m_blueprintsServlet = null; } if (m_mapgraphServlet != null) { m_mapgraphServlet.destroy(); m_mapgraphServlet = null; } super.destroy(); } @Override protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { if (log.isInfoEnabled()) log.info(req.toString()); /* * Look for linked data GET requests. * * Note: URIs ending in /sparql are *assumed* to be SPARQL end points on * this server. A GET against a SPARQL end point is a SERVICE * DESCRIPTION request (not a DESCRIBE) and will be handled by the * QueryServlet. */ final String pathInfo = req.getPathInfo(); if (pathInfo != null && !pathInfo.endsWith("/sparql")) { final URI uri = new URIImpl(req.getRequestURL().toString()); if (m_describeServlet != null) { /* * Test the DESCRIBE cache. */ req.setAttribute(DescribeCacheServlet.ATTR_DESCRIBE_URIS, Collections.singleton(uri)); m_describeServlet.doGet(req, resp); if (resp.isCommitted()) { // Cache hit. return; } } // Set this up as a DESCRIBE query. req.setAttribute(QueryServlet.ATTR_QUERY, "DESCRIBE <" + uri.stringValue() + ">"); // Handle the linked data GET as a DESCRIBE query. m_queryServlet.doSparqlQuery(req, resp); return; } /* * Otherwise, GET against the SPARQL endpoint is only allowed with query * requests, so delegate to the QueryServlet. */ m_queryServlet.doGet(req, resp); } /** * A query can be submitted with a POST if a query parameter is provided. * Otherwise delegate to the {@link InsertServlet} or {@link DeleteServlet} * as appropriate. */ @Override protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { if (log.isInfoEnabled()) log.info(req.toString()); if (req.getParameter(QueryServlet.ATTR_QUERY) != null || req.getParameter(QueryServlet.ATTR_UPDATE) != null || req.getParameter(QueryServlet.ATTR_UUID) != null || req.getParameter(QueryServlet.ATTR_ESTCARD) != null || req.getParameter(QueryServlet.ATTR_HASSTMT) != null || req.getParameter(QueryServlet.ATTR_GETSTMTS) != null || req.getParameter(QueryServlet.ATTR_CONTEXTS) != null // the two cases below were added to fix bug trac 711 || hasMimeType(req, BigdataRDFServlet.MIME_SPARQL_UPDATE) || hasMimeType(req, BigdataRDFServlet.MIME_SPARQL_QUERY) ) { // SPARQL QUERY -or- SPARQL UPDATE via POST m_queryServlet.doPost(req, resp); } else if (req.getParameter("updatePost") != null) { // UPDATE via POST w/ Multi-part Body. m_updateServlet.doPost(req, resp); } else if (req.getParameter("delete") != null) { // DELETE via POST w/ Body. m_deleteServlet.doPost(req, resp); } else if (req.getParameter(StatusServlet.CANCEL_QUERY) != null) { StatusServlet.doCancelQuery(req, resp, getIndexManager(), getBigdataRDFContext()); buildAndCommitResponse(resp, HTTP_OK, MIME_TEXT_PLAIN, ""); } else if (req.getParameter(WorkbenchServlet.ATTR_WORKBENCH) != null) { m_workbenchServlet.doPost(req, resp); } else if (req.getParameter(BlueprintsServletProxy.ATTR_BLUEPRINTS) != null) { m_blueprintsServlet.doPostRequest(req, resp); } else if (req.getParameter(MapgraphServletProxy.ATTR_MAPGRAPH) != null) { m_mapgraphServlet.doPostRequest(req, resp); } else if (req.getParameter("uri") != null) { // INSERT via w/ URIs m_insertServlet.doPost(req, resp); } else { // INSERT via POST w/ Body m_insertServlet.doPost(req, resp); } } static boolean hasMimeType(final HttpServletRequest req, final String mimeType) { final String contentType = req.getContentType(); return contentType != null && mimeType.equals(new MiniMime(contentType).getMimeType()); } /** * A PUT request always delegates to the {@link UpdateServlet}. * <p> * Note: The semantics of PUT are "DELETE+INSERT" for the API. PUT is not * support for just "INSERT". Use POST instead for that purpose. */ @Override protected void doPut(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { if (log.isInfoEnabled()) log.info(req.toString()); m_updateServlet.doPut(req, resp); } /** * Delegate to the {@link DeleteServlet}. */ @Override protected void doDelete(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { if (log.isInfoEnabled()) log.info(req.toString()); m_deleteServlet.doDelete(req, resp); } }