Package org.apache.jena.fuseki.server

Source Code of org.apache.jena.fuseki.server.SPARQLServer

/*
* 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.jena.fuseki.server;

import static java.lang.String.format ;
import static org.apache.jena.fuseki.Fuseki.serverLog ;

import java.io.FileInputStream ;
import java.util.EnumSet ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;

import javax.servlet.http.HttpServlet ;

import org.apache.jena.fuseki.Fuseki ;
import org.apache.jena.fuseki.FusekiException ;
import org.apache.jena.fuseki.mgt.ActionDataset ;
import org.apache.jena.fuseki.mgt.MgtFunctions ;
import org.apache.jena.fuseki.mgt.PageNames ;
import org.apache.jena.fuseki.servlets.* ;
import org.apache.jena.fuseki.validation.DataValidator ;
import org.apache.jena.fuseki.validation.IRIValidator ;
import org.apache.jena.fuseki.validation.QueryValidator ;
import org.apache.jena.fuseki.validation.UpdateValidator ;
import org.eclipse.jetty.http.MimeTypes ;
import org.eclipse.jetty.server.Connector ;
import org.eclipse.jetty.server.Server ;
import org.eclipse.jetty.server.nio.BlockingChannelConnector ;
import org.eclipse.jetty.servlet.DefaultServlet ;
import org.eclipse.jetty.servlet.ServletContextHandler ;
import org.eclipse.jetty.servlet.ServletHolder ;
import org.eclipse.jetty.xml.XmlConfiguration ;
import org.openjena.riot.WebContent ;

import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.servlets.GzipFilter;


import com.hp.hpl.jena.sparql.util.Utils ;

public class SPARQLServer
{
    static { Fuseki.init() ; }
   
    private ServerConfig serverConfig ;
   
    private Server server = null ;
    private boolean verboseLogging = false ;
    //private static int ThreadPoolSize = 100 ;
   
    public SPARQLServer(ServerConfig config)
    {
        this.serverConfig = config ;
        verboseLogging = config.verboseLogging ;
       
        // GZip compression
        // Note that regardless of this setting we'll always leave it turned off for the servlets
        // where it makes no sense to have it turned on e.g. update and upload
       
        ServletContextHandler context = buildServer(serverConfig.jettyConfigFile, config.enableCompression) ;
        // Build them all.
        for ( DatasetRef sDesc : serverConfig.services )
            configureOneDataset(context, sDesc,  config.enableCompression) ;
    }
   
    public void start()
    {
        String now = Utils.nowAsString() ;
        //serverLog.info(format("%s %s", Fuseki.NAME, Fuseki.VERSION)) ;
        serverLog.info(format("%s %s %s", Fuseki.NAME, Fuseki.VERSION, Fuseki.BUILD_DATE)) ;
        String jettyVersion = org.eclipse.jetty.server.Server.getVersion() ;
        serverLog.info(format("Jetty %s",jettyVersion)) ;
        String host = server.getConnectors()[0].getHost();
        if (host != null)
            serverLog.info("Incoming connections limited to " + host);
        serverLog.info(format("Started %s on port %d", now, server.getConnectors()[0].getPort())) ;

        try { server.start() ; }
        catch (java.net.BindException ex)
        { serverLog.error("SPARQLServer: Failed to start server: " + ex.getMessage()) ; System.exit(1) ; }
        catch (Exception ex)
        { serverLog.error("SPARQLServer: Failed to start server: " + ex.getMessage(), ex) ; System.exit(1) ; }
       
        ServletContextHandler context = (ServletContextHandler)server.getHandler() ;
    }

    public void stop()
    {
        String now = Utils.nowAsString() ;
        serverLog.info(format("Stopped %s on port %d", now, server.getConnectors()[0].getPort())) ;
        try { server.stop() ; }
        catch (Exception ex)
        { Fuseki.serverLog.warn("SPARQLServer: Exception while stopping server: " + ex.getMessage(), ex) ; }
    }
   
    public Server getServer() { return server ; }
    public List<DatasetRef> getDatasets() { return serverConfig.services ; }
   
    public ServerConfig getServerConfig()
    {
        return serverConfig ;
    }

    // Later : private and in constructor.
    private ServletContextHandler buildServer(String jettyConfig, boolean enableCompression)
    {
        if ( jettyConfig != null )
        {
            // --jetty-config=jetty-fuseki.xml
            // for detailed configuration of the server using Jetty features.
            server = configServer(jettyConfig) ;
        }
        else
            server = defaultServerConfig(serverConfig.port) ;
        // Keep the server to a maximum number of threads.
        //server.setThreadPool(new QueuedThreadPool(ThreadPoolSize)) ;
       
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setErrorHandler(new FusekiErrorHandler()) ;
        // Increase form size.
        context.getServletContext().getContextHandler().setMaxFormContentSize(10*1000*1000) ;
        server.setHandler(context);
       
        // Constants. Add RDF types.
        MimeTypes mt = new MimeTypes() ;
        mt.addMimeMapping("rdf",    WebContent.contentTypeRDFXML+";charset=utf-8") ;
        mt.addMimeMapping("ttl",    WebContent.contentTypeTurtle+";charset=utf-8") ;
        mt.addMimeMapping("nt",     WebContent.contentTypeNTriples+";charset=ascii") ;
        mt.addMimeMapping("nq",     WebContent.contentTypeNQuads+";charset=ascii") ;
        mt.addMimeMapping("trig",   WebContent.contentTypeTriG+";charset=utf-8") ;
       
        //mt.addMimeMapping("tpl",    "text/html;charset=utf-8") ;
        context.setMimeTypes(mt) ;
        server.setHandler(context);

        serverLog.debug("Pages = "+serverConfig.pages) ;
       
        boolean installManager = true ;
        boolean installServices = true ;
       
        String validationRoot = "/validate" ;
        String sparqlProcessor = "/sparql" ;
       
        // Should all services be /_/.... or some such?
       
        if ( installManager || installServices)
        {
            // TODO Respect port.
            if ( serverConfig.pagesPort != serverConfig.port )
                serverLog.warn("Not supported yet - pages on a different port to services") ;
           
            String base = serverConfig.pages ;
            Map<String, Object> data = new HashMap<String, Object>() ;
            data.put("mgt", new MgtFunctions()) ;
            SimpleVelocityServlet templateEngine = new SimpleVelocityServlet(base, data) ;
            addServlet(context, templateEngine, "*.tpl", false) ;
        }
       
        if ( installManager )
        {
            // Action when control panel selects a dataset.
            HttpServlet datasetChooser = new ActionDataset() ;
            addServlet(context, datasetChooser, PageNames.actionDatasetNames, false) ;
        }
       
        if ( installServices )
        {
            // Validators
            HttpServlet validateQuery = new QueryValidator() ;
            HttpServlet validateUpdate = new UpdateValidator() ;
            HttpServlet validateData = new DataValidator() ;   
            HttpServlet validateIRI = new IRIValidator() ;
           
            HttpServlet dumpService = new DumpServlet() ;
            HttpServlet generalQueryService = new SPARQL_QueryGeneral() ;
            // TODO Name management
            addServlet(context, validateQuery, validationRoot+"/query", false) ;
            addServlet(context, validateUpdate, validationRoot+"/update", false) ;
            addServlet(context, validateData, validationRoot+"/data", false) ;
            addServlet(context, validateIRI, validationRoot+"/iri", false) ;
            addServlet(context, dumpService, "/dump", false) ;
            // general query processor.
            addServlet(context, generalQueryService, sparqlProcessor, enableCompression) ;
        }
       
        if ( installManager || installServices )
        {
            String [] files = { "fuseki.html", "index.html" } ;
            context.setWelcomeFiles(files) ;
            addContent(context, "/", serverConfig.pages) ;
        }
       
        return context ;
       
    }
   
    private void configureOneDataset(ServletContextHandler context, DatasetRef sDesc, boolean enableCompression)
    {
        String datasetPath = sDesc.name ;
        if ( datasetPath.equals("/") )
            datasetPath = "" ;
        else if ( ! datasetPath.startsWith("/") )
            datasetPath = "/"+datasetPath ;
       
        if ( datasetPath.endsWith("/") )
            datasetPath = datasetPath.substring(0, datasetPath.length()-1) ;

        DatasetRegistry.get().put(datasetPath, sDesc) ;
        serverLog.info(format("Dataset path = %s", datasetPath)) ;
       
        HttpServlet sparqlQuery = new SPARQL_QueryDataset(verboseLogging) ;
        HttpServlet sparqlUpdate = new SPARQL_Update(verboseLogging) ;
        HttpServlet sparqlUpload = new SPARQL_Upload(verboseLogging) ;
        HttpServlet sparqlHttpR = new SPARQL_REST_R(verboseLogging)
        HttpServlet sparqlHttpRW = new SPARQL_REST_RW(verboseLogging) ;
       
        addServlet(context, datasetPath, sparqlQuery, sDesc.queryEP, enableCompression) ;
        addServlet(context, datasetPath, sparqlUpdate, sDesc.updateEP, false) ; // No point - no results of any size.
        addServlet(context, datasetPath, sparqlUpload, sDesc.uploadEP, false) ;
        addServlet(context, datasetPath, sparqlHttpR, sDesc.readGraphStoreEP, enableCompression) ;
        addServlet(context, datasetPath, sparqlHttpRW, sDesc.readWriteGraphStoreEP, enableCompression) ;
    }
   
    private static Server configServer(String jettyConfig)
    {
        try {
            serverLog.info("Jetty server config file = "+jettyConfig) ;
            Server server = new Server() ;
            XmlConfiguration configuration = new XmlConfiguration(new FileInputStream(jettyConfig)) ;
            configuration.configure(server) ;
            return server ;
        } catch (Exception ex)
        {
            serverLog.error("SPARQLServer: Failed to configure server: " + ex.getMessage(), ex) ;
            throw new FusekiException("Failed to configure a server using configuration file '"+jettyConfig+"'") ;
        }
    }
   
    private static Server defaultServerConfig(int port)
    {
        // Server, with one NIO-based connector, large input buffer size (for long URLs, POSTed forms (queries, updates)).
        Server server = new Server();
       
        // Using "= new SelectChannelConnector() ;" on Darwin (OS/X) causes problems
        // with initialization not seen (thread scheduling?) in Joseki.
       
        // BlockingChannelConnector is better for pumping large responses back
        // but there have been observed problems with DirectMemory allocation
        // (-XX:MaxDirectMemorySize=1G does not help)
        // Connector connector = new SelectChannelConnector() ;
       
        // Connector and specific settings.
        BlockingChannelConnector bcConnector = new BlockingChannelConnector() ;
        //bcConnector.setUseDirectBuffers(false) ;
       
        Connector connector = bcConnector ;
        // Ignore. If set, then if this goes off, it keeps going off
        // and you get a lot of log messages.
        connector.setMaxIdleTime(0) ; // Jetty outputs a lot of messages if this goes off.
        connector.setPort(port);
        // Some people do try very large operations ...
        connector.setRequestHeaderSize(64*1024) ;
        connector.setRequestBufferSize(5*1024*1024) ;
        connector.setResponseBufferSize(5*1024*1024) ;
        server.addConnector(connector) ;
        return server ;
    }

    private static void addContent(ServletContextHandler context, String pathSpec, String pages)
    {
        DefaultServlet staticServlet = new DefaultServlet() ;
        ServletHolder staticContent = new ServletHolder(staticServlet) ;
        staticContent.setInitParameter("resourceBase", pages) ;
       
        //Note we set GZip to false for static content because the Jetty DefaultServlet has
        //a built-in GZip capability that is better for static content than the mechanism the
        //GzipFilter uses for dynamic content
        addServlet(context, staticContent, pathSpec, false) ;
    }

    // SHARE
    private static void addServlet(ServletContextHandler context, String datasetPath, HttpServlet servlet, List<String> pathSpecs, boolean enableCompression)
    {
        for ( String pathSpec : pathSpecs )
        {
            if ( pathSpec.equals("") )
            {
                // "" is special -- add as "base" and "base/"
                addServlet(context, servlet, datasetPath+"/", enableCompression) ;
                addServlet(context, servlet, datasetPath,     enableCompression) ;
                continue ;
            }
           
            if ( pathSpec.endsWith("/") )
                pathSpec = pathSpec.substring(0, pathSpec.length()-1) ;
            if ( pathSpec.startsWith("/") )
                pathSpec = pathSpec.substring(1, pathSpec.length()) ;
            addServlet(context, servlet, datasetPath+"/"+pathSpec, enableCompression) ;
        }
    }

    private static void addServlet(ServletContextHandler context, HttpServlet servlet, String pathSpec, boolean enableCompression)
    {
        ServletHolder holder = new ServletHolder(servlet) ;
        addServlet(context, holder, pathSpec, enableCompression) ;
    }
   
    private static void addServlet(ServletContextHandler context, ServletHolder holder, String pathSpec, boolean enableCompression)
    {
        if ( serverLog.isDebugEnabled() )
        {
            if ( enableCompression )
                serverLog.debug("Add servlet @ "+pathSpec+" (with gzip)") ;
            else
                serverLog.debug("Add servlet @ "+pathSpec) ;
        }
        context.addServlet(holder, pathSpec) ;

        if (enableCompression)
            context.addFilter(GzipFilter.class, pathSpec, EnumSet.allOf(DispatcherType.class));
    }

}
TOP

Related Classes of org.apache.jena.fuseki.server.SPARQLServer

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.