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

org.apache.jena.fuseki.cmds.FusekiBasicCmd Maven / Gradle / Ivy

/*
 * 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.cmds;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import arq.cmdline.CmdARQ;
import arq.cmdline.ModAssembler;
import arq.cmdline.ModDatasetAssembler;
import jena.cmd.ArgDecl;
import jena.cmd.CmdException;
import org.apache.jena.assembler.exceptions.AssemblerException;
import org.apache.jena.atlas.lib.DateTimeUtils ;
import org.apache.jena.atlas.lib.FileOps;
import org.apache.jena.atlas.logging.FmtLog;
import org.apache.jena.fuseki.Fuseki;
import org.apache.jena.fuseki.FusekiLogging;
import org.apache.jena.fuseki.embedded.FusekiServer;
import org.apache.jena.fuseki.server.DataAccessPoint;
import org.apache.jena.fuseki.server.DataAccessPointRegistry;
import org.apache.jena.fuseki.server.DataService;
import org.apache.jena.fuseki.servlets.SPARQL_QueryGeneral ;
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.apache.jena.query.ARQ;
import org.apache.jena.query.Dataset;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFLanguages;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphFactory;
import org.apache.jena.sys.JenaSystem;
import org.apache.jena.system.Txn;
import org.apache.jena.tdb.TDB;
import org.apache.jena.tdb.TDBFactory;
import org.apache.jena.tdb.transaction.TransactionManager;
import org.apache.jena.tdb2.DatabaseMgr;
import org.slf4j.Logger;

/** Fuseki command that runs a Fuseki server with no UI, just SPARQL services.
 * 

* Use {@code --conf=} for multiple datasets and specific service names. *

* The command line dataset setup only supports a single dataset. */ public class FusekiBasicCmd { // Own module (or optional dependency on jena-cmds) // Needs jena-cmds. static { FusekiLogging.setLogging(); } static public void main(String... argv) { FusekiCmdInner.innerMain(argv); } /** Dataset setup (command line, config file) for a dataset (or several if config file) */ static class ServerConfig { public int port; // Dataset name on the command line. public String datasetPath = null; // Command line --update. public boolean allowUpdate = false; // This is set ... public DatasetGraph dsg = null; // ... or this. public String serverConfig = null; // Allow there to be no registered datasets without it being an error. // which is "return dsg==null && serverConfig==null;" public boolean empty = false ; // Setup for SPARQLer - validators and general query engine, some pages. public boolean sparqler = false ; public boolean validators = false ; public boolean loopback = false; public String datasetDescription; public String contentDirectory = null; } static class FusekiCmdInner extends CmdARQ { private static int defaultPort = 3030; private static ArgDecl argMem = new ArgDecl(ArgDecl.NoValue, "mem"); private static ArgDecl argUpdate = new ArgDecl(ArgDecl.NoValue, "update", "allowUpdate"); private static ArgDecl argFile = new ArgDecl(ArgDecl.HasValue, "file"); private static ArgDecl argTDB2mode = new ArgDecl(ArgDecl.NoValue, "tdb2"); private static ArgDecl argMemTDB = new ArgDecl(ArgDecl.NoValue, "memtdb", "memTDB", "tdbmem"); private static ArgDecl argTDB = new ArgDecl(ArgDecl.HasValue, "loc", "location", "tdb"); // No SPARQL dataset or services private static ArgDecl argEmpty = new ArgDecl(ArgDecl.NoValue, "empty", "no-dataset"); private static ArgDecl argPort = new ArgDecl(ArgDecl.HasValue, "port"); private static ArgDecl argLocalhost = new ArgDecl(ArgDecl.NoValue, "localhost", "local"); private static ArgDecl argTimeout = new ArgDecl(ArgDecl.HasValue, "timeout"); private static ArgDecl argConfig = new ArgDecl(ArgDecl.HasValue, "config", "conf"); private static ArgDecl argGZip = new ArgDecl(ArgDecl.HasValue, "gzip"); private static ArgDecl argBase = new ArgDecl(ArgDecl.HasValue, "base", "files"); private static ArgDecl argSparqler = new ArgDecl(ArgDecl.HasValue, "sparqler"); private static ArgDecl argValidators = new ArgDecl(ArgDecl.NoValue, "validators"); // private static ModLocation modLocation = new ModLocation(); private static ModDatasetAssembler modDataset = new ModDatasetAssembler(); static public void innerMain(String... argv) { JenaSystem.init(); new FusekiCmdInner(argv).mainRun(); } private final ServerConfig serverConfig = new ServerConfig(); private boolean useTDB2; public FusekiCmdInner(String... argv) { super(argv); if ( false ) // Consider ... TransactionManager.QueueBatchSize = TransactionManager.QueueBatchSize / 2; getUsage().startCategory("Fuseki"); addModule(modDataset); add(argMem, "--mem", "Create an in-memory, non-persistent dataset for the server"); add(argFile, "--file=FILE", "Create an in-memory, non-persistent dataset for the server, initialised with the contents of the file"); add(argTDB2mode, "--tdb2", "Create command line persistent datasets with TDB2"); add(argTDB, "--loc=DIR", "Use an existing TDB database (or create if does not exist)"); add(argMemTDB, "--memTDB", "Create an in-memory, non-persistent dataset using TDB (testing only)"); // add(argEmpty, "--empty", // "Run with no datasets and services (validators only)"); add(argEmpty); // Hidden for now. add(argPort, "--port", "Listen on this port number"); add(argLocalhost, "--localhost", "Listen only on the localhost interface"); add(argTimeout, "--timeout=", "Global timeout applied to queries (value in ms) -- format is X[,Y] "); add(argUpdate, "--update", "Allow updates (via SPARQL Update and SPARQL HTTP Update)"); add(argConfig, "--config=", "Use a configuration file to determine the services"); add(argGZip, "--gzip=on|off", "Enable GZip compression (HTTP Accept-Encoding) if request header set"); add(argBase, "--base=DIR", "Directory for static content"); add(argSparqler, "--sparqler=DIR", "Run with SPARQLer services Directory for static content"); add(argValidators, "--validators", "Install validators"); super.modVersion.addClass(TDB.class); super.modVersion.addClass(Fuseki.class); } static String argUsage = "[--config=FILE] [--mem|--desc=AssemblerFile|--file=FILE] [--port PORT] /DatasetPathName"; @Override protected String getSummary() { return getCommandName() + " " + argUsage; } @Override protected void processModulesAndArgs() { int x = 0; Logger log = Fuseki.serverLog; // ---- Checking if ( contains(argMem) ) x++; if ( contains(argFile) ) x++; if ( contains(ModAssembler.assemblerDescDecl) ) x++; if ( contains(argTDB) ) x++; if ( contains(argMemTDB) ) x++; if ( contains(argConfig) ) x++; boolean allowEmpty = contains(argEmpty) || contains(argSparqler); if ( x == 0 && ! allowEmpty ) throw new CmdException("No dataset specified on the command line."); if ( x > 1 ) throw new CmdException("Multiple ways providing a dataset. Only one of --mem, --file, --loc or --desc"); if ( x > 0 && allowEmpty ) throw new CmdException("Dataset provided but 'no dataset' flag given"); //---- check: Invalid: --conf + service name. if ( contains(argConfig) ) { if ( getPositional().size() != 0 ) throw new CmdException("Can't have both a configutation file and a service name"); } else if ( ! allowEmpty ) { if ( getPositional().size() == 0 ) throw new CmdException("Missing service name"); if ( getPositional().size() > 1 ) throw new CmdException("Multiple dataset path names given"); serverConfig.datasetPath = DataAccessPoint.canonical(getPositionalArg(0)); } serverConfig.datasetDescription = ""; // ---- check: Invalid: --update + --conf if ( contains(argUpdate) && contains(argConfig) ) throw new CmdException("--update and a configuration file does not make sense (control using the configuration file only)"); boolean allowUpdate = contains(argUpdate); serverConfig.allowUpdate = allowUpdate; // ---- Port serverConfig.port = defaultPort; if ( contains(argPort) ) { String portStr = getValue(argPort); try { int port = Integer.parseInt(portStr); serverConfig.port = port; } catch (NumberFormatException ex) { throw new CmdException(argPort.getKeyName() + " : bad port number: " + portStr); } } if ( contains(argLocalhost) ) serverConfig.loopback = true; // ---- Dataset // Only one of these is choose from the checking above. // Which TDB to use to create a command line TDB database. useTDB2 = contains(argTDB2mode); String tag = useTDB2 ? "TDB2" : "TDB"; if ( allowEmpty ) { serverConfig.empty = true; serverConfig.datasetDescription = "No dataset"; } // Fuseki config file if ( contains(argConfig) ) { String file = getValue(argConfig); if ( file.startsWith("file:") ) file = file.substring("file:".length()); Path path = Paths.get(file); if ( ! Files.exists(path) ) throw new CmdException("File not found: "+file); if ( Files.isDirectory(path) ) throw new CmdException("Is a directory: "+file); serverConfig.datasetDescription = "Configuration: "+path.toAbsolutePath(); serverConfig.serverConfig = getValue(argConfig); } // Ways to setup a dataset. if ( contains(argMem) ) { serverConfig.datasetDescription = "in-memory"; // Only one setup should be called by the test above but to be safe // and in case of future changes, clear the configuration. serverConfig.dsg = DatasetGraphFactory.createTxnMem(); // Always allow, else you can't do very much! serverConfig.allowUpdate = true; } if ( contains(argFile) ) { String filename = getValue(argFile); String pathname = filename; if ( filename.startsWith("file:") ) pathname = filename.substring("file:".length()); serverConfig.datasetDescription = "file:"+filename; if ( !FileOps.exists(pathname) ) throw new CmdException("File not found: " + filename); serverConfig.dsg = DatasetGraphFactory.createTxnMem(); // INITIAL DATA. Lang language = RDFLanguages.filenameToLang(filename); if ( language == null ) throw new CmdException("Can't guess language for file: " + filename); Txn.executeWrite(serverConfig.dsg, ()->RDFDataMgr.read(serverConfig.dsg, filename)); } // if ( contains(argMemTDB) ) { // //log.info("TDB dataset: in-memory") ; // cmdLineConfig.reset(); // cmdLineConfig.argTemplateFile = useTDB2 ? Template.templateTDB2_MemFN : Template.templateTDB1_MemFN ; // cmdLineConfig.params.put(Template.DIR, Names.memName) ; // // Always allow. // cmdLineConfig.allowUpdate = true ; // cmdLineConfig.datasetDescription = useTDB2 ? "TDB2 dataset (in-memory)" : "TDB dataset (in-memory)"; // } // // if ( contains(argTDB) ) { // cmdLineConfig.reset(); // cmdLineConfig.argTemplateFile = // useTDB2 ? Template.templateTDB2_DirFN : Template.templateTDB1_DirFN; // String dir = getValue(argTDB) ; // cmdLineConfig.params.put(Template.DIR, dir) ; // cmdLineConfig.datasetDescription = useTDB2 ? "TDB2 dataset: "+dir : "TDB dataset: "+dir; // } if ( contains(argMemTDB) ) { serverConfig.datasetDescription = tag+" dataset in-memory"; serverConfig.dsg = useTDB2 ? DatabaseMgr.createDatasetGraph() : TDBFactory.createDatasetGraph(); serverConfig.allowUpdate = true; } if ( contains(argTDB) ) { String dir = getValue(argTDB); serverConfig.datasetDescription = tag+" dataset: "+dir; serverConfig.dsg = useTDB2 ? DatabaseMgr.connectDatasetGraph(dir) : TDBFactory.createDatasetGraph(dir); } if ( contains(ModAssembler.assemblerDescDecl) ) { serverConfig.datasetDescription = "Assembler: "+ getValue(ModAssembler.assemblerDescDecl); // Need to add service details. Dataset ds = modDataset.createDataset(); serverConfig.dsg = ds.asDatasetGraph(); } // ---- Misc features. if ( contains(argTimeout) ) { String str = getValue(argTimeout); ARQ.getContext().set(ARQ.queryTimeout, str); } if ( contains(argValidators) ) { serverConfig.validators = true; } if ( contains(argSparqler) ) { String filebase = getValue(argSparqler); if ( ! FileOps.exists(filebase) ) throw new CmdException("File area not found: "+filebase); serverConfig.contentDirectory = filebase; serverConfig.sparqler = true; serverConfig.validators = true; } if ( contains(argBase) ) { // Static files. String filebase = getValue(argBase); if ( ! FileOps.exists(filebase) ) { throw new CmdException("File area not found: "+filebase); //FmtLog.warn(Fuseki.configLog, "File area not found: "+filebase); } serverConfig.contentDirectory = filebase; } // if ( contains(argGZip) ) { // if ( !hasValueOfTrue(argGZip) && !hasValueOfFalse(argGZip) ) // throw new CmdException(argGZip.getNames().get(0) + ": Not understood: " + getValue(argGZip)); // jettyServerConfig.enableCompression = super.hasValueOfTrue(argGZip); // } } // private static String sort_out_dir(String path) { // path.replace('\\', '/'); // if ( !path.endsWith("/") ) // path = path + "/"; // return path; // } @Override protected void exec() { try { FusekiServer server = buildServer(serverConfig); info(server, serverConfig); server.start(); server.join(); System.exit(0); } catch (AssemblerException ex) { if ( ex.getCause() != null ) System.err.println(ex.getCause().getMessage()); else System.err.println(ex.getMessage()); } } // ServerConfig -> Setup the builder. private static FusekiServer buildServer(ServerConfig serverConfig) { FusekiServer.Builder builder = FusekiServer.create(); // Loopback. builder.setPort(serverConfig.port); builder.setLoopback(serverConfig.loopback); if ( serverConfig.validators ) { if ( serverConfig.sparqler ) builder.addServlet("/sparql", new SPARQL_QueryGeneral()); // Validators. builder.addServlet("/validate/query", new QueryValidator()); builder.addServlet("/validate/update", new UpdateValidator()); builder.addServlet("/validate/iri", new IRIValidator()); builder.addServlet("/validate/data", new DataValidator()); } if ( ! serverConfig.empty ) { if ( serverConfig.serverConfig != null ) // Config file. builder.parseConfigFile(serverConfig.serverConfig); else // One dataset. builder.add(serverConfig.datasetPath, serverConfig.dsg, serverConfig.allowUpdate); } if ( serverConfig.contentDirectory != null ) builder.setStaticFileBase(serverConfig.contentDirectory) ; return builder.build(); } private void info(FusekiServer server, ServerConfig serverConfig) { if ( super.isQuiet() ) return; Logger log = Fuseki.serverLog; String version = Fuseki.VERSION; String buildDate = Fuseki.BUILD_DATE ; if ( version != null && version.equals("${project.version}") ) version = null ; if ( buildDate != null && buildDate.equals("${build.time.xsd}") ) buildDate = DateTimeUtils.nowAsXSDDateTimeString() ; String name = Fuseki.NAME; name = name +" (basic server)"; if ( version != null ) { if ( Fuseki.developmentMode && buildDate != null ) FmtLog.info(log, "%s %s %s", name, version, buildDate) ; else FmtLog.info(log, "%s %s", name, version); } // Dataset -> Endpoints Map> mapDatasetEndpoints = description(DataAccessPointRegistry.get(server.getServletContext())); if ( serverConfig.empty ) { FmtLog.info(log, "No SPARQL datasets services"); } else { if ( serverConfig.datasetPath == null && serverConfig.serverConfig == null ) log.error("No dataset path nor server configuration file"); } if ( serverConfig.datasetPath != null ) { if ( mapDatasetEndpoints.size() != 1 ) { System.err.println(serverConfig.datasetPath); log.error("Expected only one dataset"); } List endpoints = mapDatasetEndpoints.get(serverConfig.datasetPath); FmtLog.info(log, "Dataset Type = %s", serverConfig.datasetDescription); FmtLog.info(log, "Path = %s; Services = %s", serverConfig.datasetPath, endpoints); } if ( serverConfig.serverConfig != null ) { // May be many datasets and services. FmtLog.info(log, "Configuration file %s", serverConfig.serverConfig); mapDatasetEndpoints.forEach((path, endpoints)->{ FmtLog.info(log, "Path = %s; Services = %s", path, endpoints); }); } if ( serverConfig.contentDirectory != null ) FmtLog.info(log, "Static files = %s", serverConfig.contentDirectory); if ( super.isVerbose() ) PlatformInfo.logDetailsVerbose(log); else if ( !super.isQuiet() ) PlatformInfo.logDetails(log); } private static Map> description(DataAccessPointRegistry reg) { Map> desc = new LinkedHashMap<>(); reg.forEach((ds,dap)->{ List endpoints = new ArrayList<>(); desc.put(ds, endpoints); DataService dSrv = dap.getDataService(); dSrv.getOperations().forEach((op)->{ dSrv.getEndpoints(op).forEach(ep-> { String x = ep.getEndpoint(); if ( x.isEmpty() ) x = "quads"; endpoints.add(x); }); }); }); return desc; } @Override protected String getCommandName() { return "fuseki"; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy