http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/soh ---------------------------------------------------------------------- diff --git a/jena-fuseki/soh b/jena-fuseki/soh new file mode 100755 index 0000000..4f6590d --- /dev/null +++ b/jena-fuseki/soh @@ -0,0 +1,713 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8 -*- + +# 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. + +# SPARQL HTTP Update, client. + +require 'optparse' +require 'net/http' +require 'uri' +require 'cgi' +require 'pp' +require 'ostruct' + +# ToDo +# Allow a choice of media type for GET +# --accept "content-type" (and abbreviations) +# --header "Add:this" +# --user, --password +# Basic authentication: request.basic_auth("username", "password") +# Follow redirects => 301: puts response["location"] # All headers are lowercase? + +SOH_NAME="SOH" +SOH_VERSION="0.0.0" + +$proxy = ENV['http_proxy'] ? URI.parse(ENV['http_proxy']) : OpenStruct.new + +# What about direct naming? + +# Names +$mtTurtle = 'text/turtle;charset=utf-8' +$mtRDF = 'application/rdf+xml' +$mtText = 'text/plain' +$mtNTriples = 'application/n-triples' +$mtNQuads = 'application/n-quads' +$mtJSONLD = 'application/ld+json' +$mtTriG = 'application/trig' +$mtSparqlResultsX = 'application/sparql-results+xml' +$mtSparqlResultsJ = 'application/sparql-results+json' +$mtAppJSON = 'application/json' +$mtAppXML = 'application/xml' +$mtSparqlResultsTSV = 'application/sparql-results+tsv' +$mtSparqlResultsCSV = 'application/sparql-results+csv' +$mtSparqlUpdate = 'application/sparql-update' +$mtWWWForm = 'application/x-www-form-urlencoded' +$mtSparqlQuery = "application/sparql-query" ; + +# Global media type table. +$fileMediaTypes = {} +$fileMediaTypes['ttl'] = $mtTurtle +$fileMediaTypes['n3'] = 'text/n3; charset=utf-8' +$fileMediaTypes['nt'] = $mtText +$fileMediaTypes['rdf'] = $mtRDF +$fileMediaTypes['owl'] = $mtRDF +$fileMediaTypes['nq'] = $mtNQuads +$fileMediaTypes['trig'] = $mtTriG +$fileMediaTypes['json-ld'] = $mtJSONLD +$fileMediaTypes['jsonld'] = $mtJSONLD + +# Global charset : no entry means "don't set" +$charsetUTF8 = 'utf-8' +$charset = {} +$charset[$mtTurtle] = 'utf-8' +$charset[$mtText] = 'ascii' +$charset[$mtTriG] = 'utf-8' +$charset[$mtNQuads] = 'utf-8' + +# Headers + +$hContentType = 'Content-Type' +# $hContentEncoding = 'Content-Encoding' +$hContentLength = 'Content-Length' +# $hContentLocation = 'Content-Location' +# $hContentRange = 'Content-Range' + +$hAccept = 'Accept' +$hAcceptCharset = 'Accept-Charset' +$hAcceptEncoding = 'Accept-Encoding' +$hAcceptRanges = 'Accept-Ranges' + +$headers = { "User-Agent" => "#{SOH_NAME}/Fuseki #{SOH_VERSION}"} +$print_http = false + +# Default for GET +# At least allow anything (and hope!) +$accept_rdf="#{$mtTurtle} , #{$mtNTriples};q=0.9 , #{$mtRDF};q=0.8 , #{$mtJSONLD};q=0.5" +# Datasets +$accept_ds="#{$mtTrig} , #{$mtNQuads};q=0.9 , #{$mtJSONLD};q=0.5" +# For SPARQL query +$accept_results="#{$mtSparqlResultsJ} , #{$mtSparqlResultsX};q=0.9 , #{$accept_rdf}" + +# Accept any in case of trouble. +$accept_rdf="#{$accept_rdf} , */*;q=0.1" +$accept_results="#{$accept_results} , */*;q=0.1" + +# The media type usually forces the charset. +$accept_charset=nil + +## Who we are. +## Two styles: +## s-query ..... +## soh query ..... + +$cmd = File.basename($0) +if $cmd == 'soh' +then + $cmd = (ARGV.size == 0) ? 'soh' : ARGV.shift +end + +if ! $cmd.start_with?('s-') && $cmd != 'soh' + $cmd = 's-'+$cmd +end + +## -------- + +def GET(dataset, graph) + print "GET #{dataset} #{graph}\n" if $verbose + requestURI = target(dataset, graph) + headers = {} + headers.merge!($headers) + headers[$hAccept] = $accept_rdf + headers[$hAcceptCharset] = $accept_charset unless $accept_charset.nil? + get_worker(requestURI, headers) +end + +def get_worker(requestURI, headers) + uri = URI.parse(requestURI) + request = Net::HTTP::Get.new(uri.request_uri) + request.initialize_http_header(headers) + print_http_request(uri, request) + response_print_body(uri, request) +end + +def HEAD(dataset, graph) + print "HEAD #{dataset} #{graph}\n" if $verbose + requestURI = target(dataset, graph) + headers = {} + headers.merge!($headers) + headers[$hAccept] = $accept_rdf + headers[$hAcceptCharset] = $accept_charset unless $accept_charset.nil? + uri = URI.parse(requestURI) + request = Net::HTTP::Head.new(uri.request_uri) + request.initialize_http_header(headers) + print_http_request(uri, request) + response_no_body(uri, request) +end + +def PUT(dataset, graph, file) + print "PUT #{dataset} #{graph} #{file}\n" if $verbose + send_body(dataset, graph, file, Net::HTTP::Put) +end + +def POST(dataset, graph, file) + print "POST #{dataset} #{graph} #{file}\n" if $verbose + send_body(dataset, graph, file, Net::HTTP::Post) +end + +def DELETE(dataset, graph) + print "DELETE #{dataset} #{graph}\n" if $verbose + requestURI = target(dataset, graph) + uri = URI.parse(requestURI) + request = Net::HTTP::Delete.new(uri.request_uri) + headers = {} + headers.merge!($headers) + request.initialize_http_header(headers) + print_http_request(uri, request) + response_no_body(uri, request) +end + +def uri_escape(string) + CGI.escape(string) +end + +def target(dataset, graph) + return dataset+"?default" if graph == "default" + return dataset+"?graph="+uri_escape(graph) +end + +def send_body(dataset, graph, file, method) + mt = content_type(file) + headers = {} + headers.merge!($headers) + headers[$hContentType] = mt + headers[$hContentLength] = File.size(file).to_s + ## p headers + + requestURI = target(dataset, graph) + uri = URI.parse(requestURI) + + request = method.new(uri.request_uri) + request.initialize_http_header(headers) + print_http_request(uri, request) + request.body_stream = File.open(file) + response_no_body(uri, request) +end + +def response_no_body(uri, request) + http = Net::HTTP::Proxy($proxy.host,$proxy.port).new(uri.host, uri.port) + http.read_timeout = nil + # check we can connect. + begin http.start + rescue Exception => e + # puts e.message + #puts e.backtrace.inspect + warn_exit "Failed to connect: #{uri.host}:#{uri.port}: #{e.message}", 3 + end + response = http.request(request) + print_http_response(response) + case response + when Net::HTTPSuccess, Net::HTTPRedirection + # OK + when Net::HTTPNotFound + warn_exit "404 Not found: #{uri}", 9 + #print response.body + else + warn_exit "#{response.code} #{response.message} #{uri}", 9 + # Unreachable + response.error! + end + # NO BODY IN RESPONSE +end + +def response_print_body(uri, request) + http = Net::HTTP::Proxy($proxy.host,$proxy.port).new(uri.host, uri.port) + http.read_timeout = nil + # check we can connect. + begin http.start + rescue => e + #puts e.backtrace.inspect + #print e.class + warn_exit "Failed to connect: #{uri.host}:#{uri.port}: #{e.message}", 3 + end + + # Add a blank line if headers were output. + print "\n" if $http_print ; + + begin + response = http.request(request) { |res| + print_http_response(res) + #puts res.code + res.read_body do |segment| + print segment + end + } + case response + when Net::HTTPSuccess, Net::HTTPRedirection + # OK + when Net::HTTPNotFound + warn_exit "404 Not found: #{uri}", 9 + #print response.body + else + warn_exit "#{response.code}: #{uri}", 9 + # Unreachable + response.error! + end + rescue EOFError => e + warn_exit "IO Error: "+e.message, 3 + end +end + +def print_http_request(uri, request) + return unless $print_http + #print "Request\n" + print request.method," ",uri, "\n" + print_headers(" ",request) +end + +def print_http_response(response) + return unless $print_http + #print "Response\n" + print response.code, " ", response.message, "\n" + print_headers(" ",response) +end + +def print_headers(marker, headers) + headers.each do |k,v| + k = k.split('-').map{|w| w.capitalize}.join('-')+':' + printf "%s%-20s %s\n",marker,k,v + end +end + +def content_type(file) + file =~ /\.([^.]*)$/ + ext = $1 + mt = $fileMediaTypes[ext] + cs = $charset[mt] + mt = mt+';charset='+cs if ! cs.nil? + return mt +end + +def charset(content_type) + return $charset[content_type] +end + +def warn_exit(msg, rc) + warn msg + exit rc ; +end + +def parseURI(uri_string) + begin + return URI.parse(uri_string).to_s + rescue URI::InvalidURIError => err + warn_exit "Bad URI: <#{uri_string}>", 2 + end +end + +## ---- Command + +def cmd_soh(command=nil) + ## Command line + options = {} + optparse = OptionParser.new do |opts| + # Set a banner, displayed at the top + # of the help screen. + case $cmd + when "s-http", "sparql-http", "soh" + banner="$cmd [get|post|put|delete] datasetURI graph [file]" + when "s-get", "s-head", "s-delete" + banner="$cmd datasetURI graph" + end + + opts.banner = $banner + # Define the options, and what they do + + options[:verbose] = false + opts.on( '-v', '--verbose', 'Verbose' ) do + options[:verbose] = true + end + + options[:version] = false + opts.on( '--version', 'Print version and exit' ) do + print "#{SOH_NAME} #{SOH_VERSION}\n" + exit + end + + # This displays the help screen, all programs are + # assumed to have this option. + opts.on( '-h', '--help', 'Display this screen and exit' ) do + puts opts + exit + end + end + + begin optparse.parse! + rescue OptionParser::InvalidArgument => e + warn e + exit + end + + $verbose = options[:verbose] + $print_http = $verbose + + if command.nil? + if ARGV.size == 0 + warn "No command given: expected one of 'get', 'put', 'post', 'delete', 'query' or 'update'" + exit 1 + end + cmdPrint=ARGV.shift + command=cmdPrint.upcase + else + cmdPrint=command + end + + case command + when "HEAD", "GET", "DELETE" + requiredFile=false + when "PUT", "POST" + requiredFile=true + when "QUERY" + cmd_sparql_query + when "UPDATE" + cmd_sparql_update + else + warn_exit "Unknown command: #{command}", 2 + end + + if requiredFile + then + if ARGV.size != 3 + warn_exit "Required: dataset URI, graph URI (or 'default') and file", 1 + end + else + if ARGV.size != 2 + warn_exit "Required: dataset URI and graph URI (or 'default')", 1 + end + end + + dataset=parseURI(ARGV.shift) + # Relative URI? + graph=parseURI(ARGV.shift) + file="" + if requiredFile + then + file = ARGV.shift if requiredFile + if ! File.exist?(file) + warn_exit "No such file: "+file, 3 + end + if File.directory?(file) + warn_exit "File is a directory: "+file, 3 + end + end + + case command + when "GET" + GET(dataset, graph) + when "HEAD" + HEAD(dataset, graph) + when "PUT" + PUT(dataset, graph, file) + when "DELETE" + DELETE(dataset, graph) + when "POST" + POST(dataset, graph, file) + else + warn_exit "Internal error: Unknown command: #{cmd}", 2 + end + exit 0 +end + +## -------- +def string_or_file(arg) + return arg if ! arg.match(/^@/) + a=(arg[1..-1]) + open(a, 'rb'){|f| f.read} +end + +## -------- SPARQL Query + +## Choose method +def SPARQL_query(service, query, query_file, forcePOST=false, args2={}) + if ! query_file.nil? + query = open(query_file, 'rb'){|f| f.read} + end + if forcePOST || query.length >= 2*1024 + SPARQL_query_POST(service, query, args2) + else + SPARQL_query_GET(service, query, args2) + end +end + +## By GET + +def SPARQL_query_GET(service, query, args2) + args = { "query" => query } + args.merge!(args2) + qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&') + action="#{service}?#{qs}" + headers={} + headers.merge!($headers) + headers[$hAccept]=$accept_results + get_worker(action, headers) +end + +## By POST + +def SPARQL_query_POST(service, query, args2) + # DRY - body/no body for each of request and response. + post_params={ "query" => query } + post_params.merge!(args2) + uri = URI.parse(service) + headers={} + headers.merge!($headers) + headers[$hAccept]=$accept_results + execute_post_form_body(uri, headers, post_params) +end + +def execute_post_form_body(uri, headers, post_params) + request = Net::HTTP::Post.new(uri.request_uri) + qs=post_params.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&') + headers[$hContentType] = $mtWWWForm + headers[$hContentLength] = qs.length.to_s + request.initialize_http_header(headers) + request.body = qs + print_http_request(uri, request) + response_print_body(uri, request) +end + +# Usage: -v --help --file= --query= +def cmd_sparql_query + options={} + optparse = OptionParser.new do |opts| + opts.banner = "Usage: #{$cmd} [--query QUERY] [--service URI] [--post] 'query' | @file" + opts.on('--service=URI', '--server=URI', 'SPARQL endpoint') do |uri| + options[:service]=uri + end + opts.on('--query=FILE','--file=FILE', 'Take query from a file') do |file| + options[:file]=file + end + opts.on('--output=TYPE', [:json,:xml,:text,:csv,:tsv], + 'Set the output argument') do |type| + options[:output]=type + end + opts.on('--accept=TYPE', [:json,:xml,:text,:csv,:tsv], + 'Set the accept header type') do |type| + options[:accept]=type + end + options[:verbose] = false + opts.on( '--post', 'Force use of POST' ) do + options[:post] = true + end + opts.on( '-v', '--verbose', 'Verbose' ) do + options[:verbose] = true + end + opts.on( '--version', 'Print version and exit' ) do + print "#{SOH_NAME} #{SOH_VERSION}\n" + exit + end + opts.on( '-h', '--help', 'Display this screen and exit' ) do + puts opts + exit + end + end + + begin optparse.parse! + rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e + warn e + exit 1 + end + + $verbose = options[:verbose] + $print_http = $verbose + usePOST = options[:post] + + service = options[:service] + warn_exit 'No service specified. Required --service=URI',1 if service.nil? + + # Query + query=nil + query_file=options[:file] + if query_file.nil? && ARGV.size == 0 + then + warn_exit 'No query specified.',1 + end + if query_file.nil? + query = ARGV.shift + if query.match(/^@/) + query_file = query[1..-1] + query = nil + end + end + + # --output ==> output= (non-standard) + args={} + case options[:output] + when nil + when "json","xml","text","csv","tsv" + args['output'] = options[:output] + when :json,:xml,:text,:csv,:tsv + args['output'] = options[:output].to_s + else + warn_exit "Unrecognized output type: "+options[:output],2 + end + + # --accept + # options[:accept] + + print "SPARQL #{service}\n" if $verbose + #args={"output"=>"text"} + SPARQL_query(service, query, query_file, usePOST, args) + exit(0) +end + +## -------- SPARQL Update + +# Update sent as a WWW form. +def SPARQL_update_by_form(service, update, args2={}) + args = {} + args.merge!(args2) + headers={} + headers.merge!($headers) + # args? encode? + body="update="+uri_escape(update) + headers[$hContentType] = $mtWWWForm + headers[$hContentLength] = body.length.to_s + uri = URI.parse(service) + execute_post_form(uri, headers, body) +end + +# DRY - query form. +def execute_post_form(uri, headers, body) + request = Net::HTTP::Post.new(uri.request_uri) + request.initialize_http_header(headers) + request.body = body + print_http_request(uri, request) + response_no_body(uri, request) +end + +def SPARQL_update(service, update, args2={}) + args = {} + args.merge!(args2) + headers={} + headers.merge!($headers) + headers[$hContentType] = $mtSparqlUpdate + uri = URI.parse(service) + request = Net::HTTP::Post.new(uri.request_uri) + request.initialize_http_header(headers) + request.body = update + print_http_request(uri, request) + response_no_body(uri, request) +end + +def cmd_sparql_update(by_raw_post=true) + # Share with cmd_sparql_query + options={} + optparse = OptionParser.new do |opts| + opts.banner = "Usage: #{$cmd} [--file REQUEST] [--service URI] 'request' | @file" + opts.on('--service=URI', '--server=URI', 'SPARQL endpoint') do |uri| + options[:service]=uri + end + opts.on('--update=FILE', '--file=FILE', 'Take update from a file') do |file| + options[:file]=file + end + options[:verbose] = false + opts.on( '-v', '--verbose', 'Verbose' ) do + options[:verbose] = true + end + opts.on( '--version', 'Print version and exit' ) do + print "#{SOH_NAME} #{SOH_VERSION}\n" + exit + end + opts.on( '-h', '--help', 'Display this screen and exit' ) do + puts opts + exit + end + end + + begin optparse.parse! + rescue OptionParser::InvalidArgument => e + warn e + exit + end + + $verbose = options[:verbose] + $print_http = $verbose + + service = options[:service] + warn_exit 'No service specified. Required --service=URI',1 if service.nil? + + update=nil + update_file=options[:file] + + if update_file.nil? && ARGV.size == 0 + then + warn_exit 'No update specified.',1 + end + if update_file.nil? + update = ARGV.shift + if update.match(/^@/) + update_file = update[1..-1] + update = nil + end + end + + print "SPARQL-Update #{service}\n" if $verbose + args={} + + # Reads in the file :-( + if update.nil? + then + update = open(update_file, 'rb'){|f| f.read} + else + update = string_or_file(update) + end + + if by_raw_post + SPARQL_update(service, update, args) + else + SPARQL_update_by_form(service, update, args) + end + exit(0) +end + +## ------- + +case $cmd +when "s-http", "sparql-http", "soh" + $banner="#{$cmd} [get|post|put|delete] datasetURI graph [file]" + cmd_soh +when "s-get", "s-head", "s-put", "s-delete", "s-post" + + case $cmd + when "s-get", "s-head", "s-delete" + $banner="#{$cmd} datasetURI graph" + when "s-put", "s-post" + $banner="#{$cmd} datasetURI graph file" + end + cmd2 = $cmd.sub(/^s-/, '').upcase + cmd_soh cmd2 + +when "s-query", "sparql-query" + cmd_sparql_query +when "s-update", "sparql-update" + cmd_sparql_update true +when "s-update-form", "sparql-update-form" + cmd_sparql_update false +else + warn_exit "Unknown: "+$cmd, 1 +end
http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src-dev/dev/BackwardForwardDescribeFactory.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src-dev/dev/BackwardForwardDescribeFactory.java b/jena-fuseki/src-dev/dev/BackwardForwardDescribeFactory.java new file mode 100644 index 0000000..2322929 --- /dev/null +++ b/jena-fuseki/src-dev/dev/BackwardForwardDescribeFactory.java @@ -0,0 +1,95 @@ +/* + * 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 dev; + +import com.hp.hpl.jena.query.Dataset; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.sparql.ARQConstants; +import com.hp.hpl.jena.sparql.core.Quad; +import com.hp.hpl.jena.sparql.core.describe.DescribeHandler; +import com.hp.hpl.jena.sparql.core.describe.DescribeHandlerFactory; +import com.hp.hpl.jena.sparql.core.describe.DescribeHandlerRegistry; +import com.hp.hpl.jena.sparql.util.Context; +import com.hp.hpl.jena.tdb.TDB ; +import com.hp.hpl.jena.util.iterator.ExtendedIterator; +import com.hp.hpl.jena.vocabulary.RDFS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BackwardForwardDescribeFactory implements DescribeHandlerFactory { + + final static Logger log = LoggerFactory.getLogger(BackwardForwardDescribeFactory.class); + + static { + TDB.init(); + log.info("Attaching replacement describe handler"); + DescribeHandlerRegistry reg = DescribeHandlerRegistry.get(); + log.info("Clearing existing describe handlers"); + reg.clear(); + reg.add(new BackwardForwardDescribeFactory()); + log.info("Attached"); + } + + @Override + public DescribeHandler create() { + return new BackwardForwardDescribe(); + } + + public static class BackwardForwardDescribe implements DescribeHandler { + + private Dataset dataset; + private Model result; + private Model defaultModel; + private Model unionModel; + + @Override + public void start(Model accumulateResultModel, Context qContext) { + this.result = accumulateResultModel; + this.dataset = (Dataset) qContext.get(ARQConstants.sysCurrentDataset); + this.defaultModel = dataset.getDefaultModel(); + this.unionModel = dataset.getNamedModel(Quad.unionGraph.getURI()); + } + + @Override + public void describe(Resource resource) { + result.add(defaultModel.listStatements(resource, null, (RDFNode) null)); + result.add(defaultModel.listStatements(null, null, resource)); + result.add(unionModel.listStatements(resource, null, (RDFNode) null)); + result.add(unionModel.listStatements(null, null, resource)); + + // Gather labels for dangling refs + Model labels = ModelFactory.createDefaultModel(); + ExtendedIterator<RDFNode> it = result.listObjects().andThen(result.listSubjects()); + while (it.hasNext()) { + RDFNode node = it.next(); + if (node.isLiteral() || resource.equals(node)) continue; + labels.add(defaultModel.listStatements((Resource) node, RDFS.label, (RDFNode) null)); + labels.add(unionModel.listStatements((Resource) node, RDFS.label, (RDFNode) null)); + } + result.add(labels); + } + + @Override + public void finish() { + } + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src-dev/dev/DevFuseki.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src-dev/dev/DevFuseki.java b/jena-fuseki/src-dev/dev/DevFuseki.java new file mode 100644 index 0000000..70bbd7b --- /dev/null +++ b/jena-fuseki/src-dev/dev/DevFuseki.java @@ -0,0 +1,149 @@ +/* + * 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 dev; + +public class DevFuseki +{ + // SPARQL_QueryDataset.vialidate query -- but FROM etc is important for TDB. + // DatasetDescription from protocol + // createDataset from the ARQ. + // SPARQL_QueryGeneral.datasetFromDescription + + // Config: + // fuseki:name ==> fuseki:serviceName of fuseki:endpointBase + // rdfs:label for log files. + + // sparql.jsp needs to switch on presence and name of service endpoints. + // --accept for to soh for construct queries (check can get CONSTRUCT in TTL). + + // application/json for application/sparql-results+json. + // application/xml for application/sparql-results+xml. + + // LimitingGraph, LimitingBulkUpdateHandler --> change to use a limiting Sink<> + // Finish: SPARQL_QueryGeneral + // Parse errors and etc need to be passed out. + // --jetty-config documentation + + // Rework arguments. + // Explicit install pages. + // Pages for read-only. + + // RDF/XML_ABBREV in ResponseModel + // Config Jetty from a file? + // Alternatibe way to run Fuseki + + // Flint? + // Pages for publish mode. + + // Multiple Accept headers + // WebContent and ContentType clean up. + + // SOH default to not needing 'default' + // More error handling. + + // Migrate ContentType to RIOT + // use in WebContent. + + //soh : --accept application/turtle for CONSTRUCT queries. + + // Direct naming. + // Use absence/presence of a query string to switch. + + // sparql.jsp ==> if no dataset, go to choosing page or error page linking to. + + // Better handling of bad URI name for a graph http:/example/X => stacktrace. + + // FUSEKI_ROOT + + // Documentation: + // Plan documentation. + // MIME types supported + // Include a data file in the distribution. + // curl as commandline + + // Dataset servers - bulk loader. + // Access the bulk loader via web. [later] + + // Structure pages, different static content servers + // /Main - index.html = fuseki.html + // /validate + // /admin + + // Server-local graph naming + + // Plain text error pages + + // Deploy to sparql.org -- need query form for read-only mode. + + // + LARQ + + // Testing: + // No file -> error. + + // Remove from package conneg - use code from ARQ/Atlas. + // TypedStream TypedInoputStrea, TypedOutputStream, MediaType, MediaRange + + // Bundle tdb scripts with Fuseki. + + // ParserFor - share between SPARQL_REST and SPARQL_Upload + // UploadTo dataset (TriG, N-Quads) + + // populate forms with prefixes (later) + + // Tests + // TestProtocol (HTTP update, query, update), inc status codes. + // SPARQL Query servlet / SPARQL Update servlet + // TestContentNegotiation - is coveage enough? + + // ?? Slug header: + // http://bitworking.org/projects/atom/rfc5023.html#rfc.section.9.7 + + // ETags. + + // Authentication + + // SOH + // Refactor into body/no_body send & body/no_body receive + // All: + // -v --help --accept --user/--password ( or --auth user:pass) + // Drop --service. + // Local config file - read to get service settings. + + // --accept line/shortname : s-get, s-query + // Basic authentication: --user --password + + // Argument names: --service naming seems inconsistent. + + // Plug-ins: + // Dataset (query, Update), HttpInternalIF? + // "Connection" + // Locking => transaction support (via default model?) + // HttpAction.beginRead() etc. + + // Java clients: + // DatasetAccessor : don't serialise to byte[] and then send. + // DatasetAccessor : check existence of endpoint. + + // Content-Length: SHOULD + // Transfer-Encoding: identity + // "chunked" encoding + // gzip + + // Code examples +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src-dev/dev/RunFuseki.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src-dev/dev/RunFuseki.java b/jena-fuseki/src-dev/dev/RunFuseki.java new file mode 100644 index 0000000..74f678c --- /dev/null +++ b/jena-fuseki/src-dev/dev/RunFuseki.java @@ -0,0 +1,90 @@ +/* + * 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 dev; + +import org.apache.jena.fuseki.FusekiCmd ; + +public class RunFuseki +{ + public static void main(String[] args) + { + //demo() ; + //FusekiCmd.main("--config=config.ttl") ; System.exit(0) ; + main1() ; + } + + public static void demo() + { + String DIR="DemoServer" ; + FusekiCmd.main("--config="+name(DIR,"config.ttl"), "--pages="+name(DIR, "demo-pages")) ; + System.exit(0) ; + } + + public static String name(String DIR, String filename) + { + StringBuilder sb = new StringBuilder() ; + if ( ! filename.startsWith("/") ) + { + sb.append(DIR) ; + if ( ! DIR.endsWith("/") ) + sb.append("/") ; + } + sb.append(filename) ; + return sb.toString() ; + } + + private static void main1() + { + String tmpdir = System.getenv("TMPDIR") ; + if ( tmpdir == null ) + tmpdir = System.getenv("TMP") ; + if ( tmpdir == null ) + tmpdir = System.getenv("HOME")+"/tmp" ; + if ( ! tmpdir.endsWith("/") ) + tmpdir = tmpdir+"/" ; + + FusekiCmd.main( + // "-v", + "--mem", "--update", "/ds" + //"--update", "--loc="+tmpdir+"DB", "--set=tdb:unionDefaultGraph=true", "/ds" + //"--update", "--mem", "/ds" + + //"--update", "--memtdb", "--set=tdb:unionDefaultGraph=true", "/ds" + + //"--debug", + //"--update", + //"--timeout=1000,5000", + //"--set=arq:queryTimeout=1000", + //"--port=3030", + //"--mgtPort=3031", + //"--mem", + //"--home=/home/afs/Projects/Fuseki", + //"--loc=DB", + //"--file=D.nt", + //"--gzip=no", + //"--desc=desc.ttl", + //--pages= + //"--jetty-config=jetty-fuseki.xml", + //"--config=config-tdb.ttl" + // "/ds" + ) ; + System.exit(0) ; + } + +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/DEF.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/DEF.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/DEF.java new file mode 100644 index 0000000..c24f7e3 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/DEF.java @@ -0,0 +1,66 @@ +/* + * 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; + +import static org.apache.jena.riot.WebContent.* ; +import org.apache.jena.atlas.web.AcceptList ; +import org.apache.jena.atlas.web.MediaType ; + +public class DEF +{ + public static final MediaType acceptRDFXML = MediaType.create(contentTypeRDFXML) ; + public static final MediaType acceptNQuads = MediaType.create(contentTypeNQuads) ; + public static final MediaType acceptRSXML = MediaType.create(contentTypeResultsXML) ; + + public static final AcceptList rdfOffer = AcceptList.create(contentTypeTurtle, + contentTypeTurtleAlt1, + contentTypeTurtleAlt2, + contentTypeNTriples, + contentTypeNTriplesAlt, + contentTypeRDFXML, + contentTypeJSONLD, + contentTypeRDFJSON, + contentTypeRDFThrift + ) ; + + public static final AcceptList quadsOffer = AcceptList.create(contentTypeTriG, + contentTypeTriGAlt1, + contentTypeTriGAlt2, + contentTypeJSONLD, + contentTypeNQuads, + contentTypeNQuadsAlt1, + contentTypeNQuadsAlt2 + ) ; + + public static final AcceptList rsOfferTable = AcceptList.create(contentTypeResultsJSON, + contentTypeTextCSV, + contentTypeTextTSV, + contentTypeResultsXML, + contentTypeResultsThrift, + contentTypeTextPlain + ) ; + + public static final AcceptList rsOfferBoolean = AcceptList.create(contentTypeResultsJSON, + contentTypeTextCSV, + contentTypeTextTSV, + contentTypeResultsXML, + contentTypeTextPlain + ) ; + +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/EmbeddedFusekiServer.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/EmbeddedFusekiServer.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/EmbeddedFusekiServer.java new file mode 100644 index 0000000..0261b67 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/EmbeddedFusekiServer.java @@ -0,0 +1,86 @@ +/* + * 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; + +import org.apache.jena.atlas.lib.FileOps ; +import org.apache.jena.fuseki.server.FusekiConfig ; +import org.apache.jena.fuseki.server.SPARQLServer ; +import org.apache.jena.fuseki.server.ServerConfig ; + +import com.hp.hpl.jena.sparql.core.DatasetGraph ; +import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ; +import com.hp.hpl.jena.tdb.TDBFactory ; + +/** Embedded (same JVM) server. + * <p>Example for one server per test suite: + * <pre> + private static EmbeddedFusekiServer server = null ; + \@BeforeClass public static void beforeClass() { + server = EmbeddedFusekiServer.createMemByPath(3030, "/test") ; + server.start() ; + \@AfterClass public static void afterClass() { + server.stop() ; + } + </pre> + */ +public class EmbeddedFusekiServer +{ + + public static EmbeddedFusekiServer mem(int port, String datasetPath) { + DatasetGraph dsg = DatasetGraphFactory.createMem() ; + return EmbeddedFusekiServer.create(port, dsg, datasetPath) ; + } + + public static EmbeddedFusekiServer memTDB(int port, String datasetPath) { + DatasetGraph dsg = TDBFactory.createDatasetGraph() ; + return EmbeddedFusekiServer.create(port, dsg, datasetPath) ; + } + + public static EmbeddedFusekiServer create(int port, DatasetGraph dsg, String datasetPath) { + ServerConfig conf = FusekiConfig.defaultConfiguration(datasetPath, dsg, true, true) ; + conf.port = port ; + conf.pagesPort = port ; + if ( ! FileOps.exists(conf.pages) ) + conf.pages = null ; + return new EmbeddedFusekiServer(conf) ; + } + + public static EmbeddedFusekiServer configure(int port, String fileConfig) { + ServerConfig conf = FusekiConfig.configure(fileConfig) ; + conf.port = port ; + conf.pagesPort = port ; + if ( ! FileOps.exists(conf.pages) ) + conf.pages = null ; + return new EmbeddedFusekiServer(conf) ; + } + + private SPARQLServer server = null ; + + public EmbeddedFusekiServer(ServerConfig conf) { + server = new SPARQLServer(conf) ; + } + + public void start() { + server.start() ; + } + + public void stop() { + server.stop() ; + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Fuseki.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/Fuseki.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Fuseki.java new file mode 100644 index 0000000..c62ba1f --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Fuseki.java @@ -0,0 +1,174 @@ +/* + * 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; + +import org.apache.jena.fuseki.server.SPARQLServer ; +import org.apache.jena.riot.RIOT ; +import org.apache.jena.riot.system.stream.LocatorFTP ; +import org.apache.jena.riot.system.stream.LocatorHTTP ; +import org.apache.jena.riot.system.stream.StreamManager ; +import org.slf4j.Logger ; +import org.slf4j.LoggerFactory ; + +import com.hp.hpl.jena.query.ARQ ; +import com.hp.hpl.jena.sparql.SystemARQ ; +import com.hp.hpl.jena.sparql.lib.Metadata ; +import com.hp.hpl.jena.sparql.mgt.SystemInfo ; +import com.hp.hpl.jena.sparql.util.Context ; +import com.hp.hpl.jena.sparql.util.MappingRegistry ; +import com.hp.hpl.jena.tdb.TDB ; +import com.hp.hpl.jena.tdb.transaction.TransactionManager ; + +/** + * <p>The main class enabling us to:</p> + * <ol> + * <li>create instances of a Fuseki server e.g. + * the ARQ, RIOT and TDB server stack</li> + * <li>get server global {@link com.hp.hpl.jena.sparql.util.Context} e.g. + * named values used to pass implementation-specific parameters across + * general interfaces.</li> + * <li>get the {@link org.apache.jena.fuseki.server.SPARQLServer} instance.</li> + * <li>set the {@link org.apache.jena.fuseki.server.SPARQLServer} instance.</li> + * + */ +public class Fuseki +{ + /** Path to ???*/ + static public String PATH = "org.apache.jena.fuseki" ; + + /** a unique IRI for the Fuseki namespace*/ + static public String FusekiIRI = "http://jena.apache.org/Fuseki" ; + + /** Fuseki home environment, usually set to $FUSEKI_HOME */ + static public String FusekiHomeEnv = "FUSEKI_HOME" ; + + /** a unique IRI including the symbol notation for which properties should be appended */ + static public String FusekiSymbolIRI = "http://jena.apache.org/fuseki#" ; + + /** ??? */ + static public String PagesStatic = "pages" ; + + /** + * TEMPORARY - this enables POST of triples to the dataset URI causing a graph to be created. + * POSTing to /dataset?graph=uri is preferred + */ + static public boolean graphStoreProtocolPostCreate = false ; + + /** an relative path to the location of <code>fuseki-properties.xml</code> file */ + static private String metadataLocation = "org/apache/jena/fuseki/fuseki-properties.xml" ; + + /** Object which holds metadata specified within {@link Fuseki#metadataLocation} */ + static private Metadata metadata = initMetadata() ; + + private static Metadata initMetadata() + { + Metadata m = new Metadata() ; + //m.addMetadata(metadataDevLocation) ; + m.addMetadata(metadataLocation) ; + return m ; + } + + /** The name of the Fuseki server. Set to the string <code>Fuseki</code> by default.*/ + static public final String NAME = "Fuseki" ; + + /** Version of this Fuseki instance */ + static public final String VERSION = metadata.get(PATH+".version", "development"); + + /** Date when Fuseki was built */ + static public final String BUILD_DATE = metadata.get(PATH+".build.datetime", "unknown") ; // call Date if unavailable. + + /** An identifier for the HTTP Fuseki server instance*/ + static public final String serverHttpName = NAME+" ("+VERSION+")" ; + + /** Actual log file for operations */ + public static final String requestLogName = PATH+".Fuseki" ; + + /** Instance of log for operations */ + public static final Logger requestLog = LoggerFactory.getLogger(requestLogName) ; + + /** Actual log file for general server messages.*/ + public static final String serverLogName = PATH+".Server" ; + + /** Instance of log for general server messages */ + public static final Logger serverLog = LoggerFactory.getLogger(serverLogName) ; + + /** Actual log file for config server messages. */ + public static final String configLogName = PATH+".Config" ; + + /** Instance of log for config server message s*/ + public static final Logger configLog = LoggerFactory.getLogger(configLogName) ; + + /** Instance of log for config server message s*/ + public static boolean verboseLogging = false ; + + /** An instance of management for stream opening, including redirecting through a + * location mapper whereby a name (e.g. URL) is redirected to another name (e.g. local file). + * */ + public static final StreamManager webStreamManager ; + static { + webStreamManager = new StreamManager() ; + // Only know how to handle http and ftp URLs - nothing local. + webStreamManager.addLocator(new LocatorHTTP()) ; + webStreamManager.addLocator(new LocatorFTP()) ; + } + + private static boolean initialized = false ; + + /** + * Initialize an instance of the Fuseki server stack. + */ + public synchronized static void init() + { + if ( initialized ) + return ; + initialized = true ; + ARQ.init() ; + SystemInfo sysInfo = new SystemInfo(FusekiIRI, PATH, VERSION, BUILD_DATE) ; + SystemARQ.registerSubSystem(sysInfo) ; + RIOT.init() ; + TDB.init() ; + MappingRegistry.addPrefixMapping("fuseki", FusekiSymbolIRI) ; + + TDB.setOptimizerWarningFlag(false) ; + // Don't set TDB batch commits. + // This can be slower, but it less memory hungry and more predictable. + TransactionManager.QueueBatchSize = 0 ; + } + + /** + * Get server global {@link com.hp.hpl.jena.sparql.util.Context}. + * @return {@link com.hp.hpl.jena.query.ARQ#getContext()} + */ + public static Context getContext() + { + return ARQ.getContext() ; + } + + // Temporary ... + private static SPARQLServer server ; + + /** set/specify the {@link org.apache.jena.fuseki.server.SPARQLServer} instance.*/ + public static void setServer(SPARQLServer _server) { server = _server ; } + + /** get the {@link org.apache.jena.fuseki.server.SPARQLServer} instance. */ + public static SPARQLServer getServer() { return server ; } + + // Force a call to init. + static { init() ; } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiCmd.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiCmd.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiCmd.java new file mode 100644 index 0000000..b076871 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiCmd.java @@ -0,0 +1,505 @@ +/* + * 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; + +import static org.apache.jena.fuseki.Fuseki.serverLog ; + +import java.io.File ; +import java.io.InputStream ; +import java.util.List ; + +import org.apache.jena.atlas.io.IO ; +import org.apache.jena.atlas.lib.FileOps ; +import org.apache.jena.atlas.lib.Lib ; +import org.apache.jena.atlas.lib.StrUtils ; +import org.apache.jena.atlas.logging.LogCtl ; +import org.apache.jena.fuseki.mgt.ManagementServer ; +import org.apache.jena.fuseki.server.FusekiConfig ; +import org.apache.jena.fuseki.server.SPARQLServer ; +import org.apache.jena.fuseki.server.ServerConfig ; +import org.apache.jena.riot.Lang ; +import org.apache.jena.riot.RDFDataMgr ; +import org.apache.jena.riot.RDFLanguages ; +import org.apache.jena.riot.SysRIOT ; +import org.eclipse.jetty.server.Server ; +import org.slf4j.Logger ; +import arq.cmd.CmdException ; +import arq.cmdline.ArgDecl ; +import arq.cmdline.CmdARQ ; +import arq.cmdline.ModDatasetAssembler ; + +import com.hp.hpl.jena.query.ARQ ; +import com.hp.hpl.jena.query.Dataset ; +import com.hp.hpl.jena.sparql.core.DatasetGraph ; +import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ; +import com.hp.hpl.jena.tdb.TDB ; +import com.hp.hpl.jena.tdb.TDBFactory ; +import com.hp.hpl.jena.tdb.sys.Names ; +import com.hp.hpl.jena.tdb.transaction.TransactionManager ; + +public class FusekiCmd extends CmdARQ +{ + private static String log4Jsetup = StrUtils.strjoinNL( + "## Plain output to stdout" + , "log4j.appender.jena.plain=org.apache.log4j.ConsoleAppender" + , "log4j.appender.jena.plain.target=System.out" + , "log4j.appender.jena.plain.layout=org.apache.log4j.PatternLayout" + , "log4j.appender.jena.plain.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n" + + , "## Plain output with level, to stderr" + , "log4j.appender.jena.plainlevel=org.apache.log4j.ConsoleAppender" + , "log4j.appender.jena.plainlevel.target=System.err" + , "log4j.appender.jena.plainlevel.layout=org.apache.log4j.PatternLayout" + , "log4j.appender.jena.plainlevel.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n" + + , "## Everything" + , "log4j.rootLogger=INFO, jena.plain" + , "log4j.logger.com.hp.hpl.jena=WARN" + , "log4j.logger.org.openjena=WARN" + , "log4j.logger.org.apache.jena=WARN" + + , "# Server log." + , "log4j.logger.org.apache.jena.fuseki.Server=INFO" + , "# Request log." + , "log4j.logger.org.apache.jena.fuseki.Fuseki=INFO" + , "log4j.logger.org.apache.jena.tdb.loader=INFO" + , "log4j.logger.org.eclipse.jetty=ERROR" + + , "## Parser output" + , "log4j.additivity."+SysRIOT.riotLoggerName+"=false" + , "log4j.logger."+SysRIOT.riotLoggerName+"=INFO, jena.plainlevel " + ) ; + + + // Set logging. + // 1/ Use log4j.configuration is defined. + // 2/ Use file:log4j.properties + // 3/ Use Built in. + + static void setLogging() { + // No loggers have been created but configuration may have been set up. + String x = System.getProperty("log4j.configuration", null) ; + + if ( x != null && ! x.equals("set") ) { + // "set" indicates that CmdMain set logging. + // Use standard log4j initialization. + return ; + } + + String fn = "log4j.properties" ; + File f = new File(fn) ; + if ( f.exists() ) { + System.out.println("File") ; + // Use file log4j.properties + System.setProperty("log4j.configuration", "file:"+fn) ; + return ; + } + // Use built-in for Fuseki. + LogCtl.resetLogging(log4Jsetup) ; + } + + static { setLogging() ; } + + // Arguments: + // --update + + // Specific switches: + + // --admin=on/off + + // --http-update + // --http-get + + // --sparql-query + // --sparql-update + + // pages/validators/ + // pages/control/ + // pages/query/ or /pages/sparql/ + + private static ArgDecl argMgtPort = new ArgDecl(ArgDecl.HasValue, "mgtPort", "mgtport") ; + private static ArgDecl argMem = new ArgDecl(ArgDecl.NoValue, "mem") ; + private static ArgDecl argAllowUpdate = new ArgDecl(ArgDecl.NoValue, "update", "allowUpdate") ; + private static ArgDecl argFile = new ArgDecl(ArgDecl.HasValue, "file") ; + private static ArgDecl argMemTDB = new ArgDecl(ArgDecl.NoValue, "memtdb", "memTDB") ; + private static ArgDecl argTDB = new ArgDecl(ArgDecl.HasValue, "loc", "location") ; + 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 argFusekiConfig = new ArgDecl(ArgDecl.HasValue, "config", "conf") ; + private static ArgDecl argJettyConfig = new ArgDecl(ArgDecl.HasValue, "jetty-config") ; + private static ArgDecl argGZip = new ArgDecl(ArgDecl.HasValue, "gzip") ; + private static ArgDecl argUber = new ArgDecl(ArgDecl.NoValue, "uber", "über") ; // Use the überservlet (experimental) + private static ArgDecl argBasicAuth = new ArgDecl(ArgDecl.HasValue, "basic-auth") ; + + private static ArgDecl argGSP = new ArgDecl(ArgDecl.NoValue, "gsp") ; // GSP compliance mode + + private static ArgDecl argHome = new ArgDecl(ArgDecl.HasValue, "home") ; + private static ArgDecl argPages = new ArgDecl(ArgDecl.HasValue, "pages") ; + + //private static ModLocation modLocation = new ModLocation() ; + private static ModDatasetAssembler modDataset = new ModDatasetAssembler() ; + + // fuseki [--mem|--desc assembler.ttl] [--port PORT] **** /datasetURI + + static public void main(String...argv) + { + // Just to make sure ... + ARQ.init() ; + TDB.init() ; + Fuseki.init() ; + new FusekiCmd(argv).mainRun() ; + } + + private int port = 3030 ; + private int mgtPort = -1 ; + private boolean listenLocal = false ; + + private DatasetGraph dsg = null ; + private String datasetPath = null ; + private boolean allowUpdate = false ; + + private String fusekiConfigFile = null ; + private boolean enableCompression = true ; + private String jettyConfigFile = null ; + private String authConfigFile = null ; + private String homeDir = null ; + private String pagesDir = null ; + + public FusekiCmd(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(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(argPort, "--port", "Listen on this port number") ; + add(argPages, "--pages=DIR", "Set of pages to serve as static content") ; + // Set via jetty config file. + 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(argAllowUpdate, "--update", "Allow updates (via SPARQL Update and SPARQL HTTP Update)") ; + add(argFusekiConfig, "--config=", "Use a configuration file to determine the services") ; + add(argJettyConfig, "--jetty-config=FILE", "Set up the server (not services) with a Jetty XML file") ; + add(argBasicAuth, "--basic-auth=FILE", "Configure basic auth using provided Jetty realm file, ignored if --jetty-config is used") ; + add(argMgtPort, "--mgtPort=port", "Enable the management commands on the given port") ; + add(argHome, "--home=DIR", "Root of Fuseki installation (overrides environment variable FUSEKI_HOME)") ; + add(argGZip, "--gzip=on|off", "Enable GZip compression (HTTP Accept-Encoding) if request header set") ; + + add(argUber) ; + //add(argGSP) ; + + 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 ; + + if ( contains(argFusekiConfig) ) + fusekiConfigFile = getValue(argFusekiConfig) ; + + ArgDecl assemblerDescDecl = new ArgDecl(ArgDecl.HasValue, "desc", "dataset") ; + if ( contains(argMem) ) x++ ; + if ( contains(argFile) ) x++ ; + if ( contains(assemblerDescDecl) ) x++ ; + if ( contains(argTDB) ) x++ ; + if ( contains(argMemTDB) ) x++ ; + + if ( fusekiConfigFile != null ) + { + if ( x > 1 ) + throw new CmdException("Dataset specificed on the command line and also a configuration file specificed.") ; + } + else + { + if ( x == 0 ) + throw new CmdException("Required: either --config=FILE or one of --mem, --file, --loc or --desc") ; + } + + if ( contains(argMem) ) + { + log.info("Dataset: in-memory") ; + dsg = DatasetGraphFactory.createMem() ; + } + if ( contains(argFile) ) + { + dsg = DatasetGraphFactory.createMem() ; + // replace by RiotLoader after ARQ refresh. + String filename = getValue(argFile) ; + log.info("Dataset: in-memory: load file: "+filename) ; + if ( ! FileOps.exists(filename) ) + throw new CmdException("File not found: "+filename) ; + + Lang language = RDFLanguages.filenameToLang(filename) ; + if ( language == null ) + throw new CmdException("Can't guess language for file: "+filename) ; + InputStream input = IO.openFile(filename) ; + + if ( RDFLanguages.isQuads(language) ) + RDFDataMgr.read(dsg, filename) ; + else + RDFDataMgr.read(dsg.getDefaultGraph(), filename) ; + } + + if ( contains(argMemTDB) ) + { + log.info("TDB dataset: in-memory") ; + dsg = TDBFactory.createDatasetGraph() ; + } + + if ( contains(argTDB) ) + { + String dir = getValue(argTDB) ; + + if ( Lib.equal(dir, Names.memName) ) { + log.info("TDB dataset: in-memory") ; + } else { + if ( ! FileOps.exists(dir) ) + throw new CmdException("Directory not found: "+dir) ; + log.info("TDB dataset: directory="+dir) ; + } + dsg = TDBFactory.createDatasetGraph(dir) ; + } + + // Otherwise + if ( contains(assemblerDescDecl) ) + { + log.info("Dataset from assembler") ; + Dataset ds = modDataset.createDataset() ; + if ( ds != null ) + dsg = ds.asDatasetGraph() ; + } + + if ( contains(argFusekiConfig) ) + { + if ( dsg != null ) + throw new CmdException("Dataset specificed on the command line and also a configuration file specificed.") ; + fusekiConfigFile = getValue(argFusekiConfig) ; + } + + if ( contains(argPort) ) + { + String portStr = getValue(argPort) ; + try { + port = Integer.parseInt(portStr) ; + } catch (NumberFormatException ex) + { + throw new CmdException(argPort.getKeyName()+" : bad port number: "+portStr) ; + } + } + + if ( contains(argMgtPort) ) + { + String mgtPortStr = getValue(argMgtPort) ; + try { + mgtPort = Integer.parseInt(mgtPortStr) ; + } catch (NumberFormatException ex) + { + throw new CmdException(argMgtPort.getKeyName()+" : bad port number: "+mgtPortStr) ; + } + } + + if ( contains(argLocalhost) ) + listenLocal = true ; + + if ( fusekiConfigFile == null && dsg == null ) + throw new CmdException("No dataset defined and no configuration file: "+argUsage) ; + + if ( dsg != null ) + { + if ( getPositional().size() == 0 ) + throw new CmdException("No dataset path name given") ; + if ( getPositional().size() > 1 ) + throw new CmdException("Multiple dataset path names given") ; + datasetPath = getPositionalArg(0) ; + if ( datasetPath.length() > 0 && ! datasetPath.startsWith("/") ) + throw new CmdException("Dataset path name must begin with a /: "+datasetPath) ; + + allowUpdate = contains(argAllowUpdate) ; + } + + if ( contains(argTimeout) ) + { + String str = getValue(argTimeout) ; + ARQ.getContext().set(ARQ.queryTimeout, str) ; + } + + if ( contains(argJettyConfig) ) + { + jettyConfigFile = getValue(argJettyConfig) ; + if ( !FileOps.exists(jettyConfigFile) ) + throw new CmdException("No such file: "+jettyConfigFile) ; + } + + if ( contains(argBasicAuth) ) + { + authConfigFile = getValue(argBasicAuth) ; + if ( !FileOps.exists(authConfigFile) ) + throw new CmdException("No such file: " + authConfigFile) ; + } + + if ( contains(argHome) ) + { + List<String> args = super.getValues(argHome) ; + homeDir = args.get(args.size()-1) ; + } + + if ( contains(argPages) ) + { + List<String> args = super.getValues(argPages) ; + pagesDir = args.get(args.size()-1) ; + } + + if ( contains(argGZip) ) + { + if ( ! hasValueOfTrue(argGZip) && ! hasValueOfFalse(argGZip) ) + throw new CmdException(argGZip.getNames().get(0)+": Not understood: "+getValue(argGZip)) ; + enableCompression = super.hasValueOfTrue(argGZip) ; + } + + if ( contains(argUber) ) + SPARQLServer.überServlet = true ; + + if ( contains(argGSP) ) + { + SPARQLServer.überServlet = true ; + Fuseki.graphStoreProtocolPostCreate = true ; + } + + } + + private static String sort_out_dir(String path) + { + path.replace('\\', '/') ; + if ( ! path.endsWith("/")) + path = path +"/" ; + return path ; + } + + @Override + protected void exec() + { + if ( homeDir == null ) + { + if ( System.getenv(Fuseki.FusekiHomeEnv) != null ) + homeDir = System.getenv(Fuseki.FusekiHomeEnv) ; + else + homeDir = "." ; + } + + homeDir = sort_out_dir(homeDir) ; + Fuseki.configLog.info("Home Directory: " + FileOps.fullDirectoryPath(homeDir)); + if ( ! FileOps.exists(homeDir) ) + Fuseki.configLog.warn("No such directory for Fuseki home: "+homeDir) ; + + String staticContentDir = pagesDir ; + if ( staticContentDir == null ) + staticContentDir = homeDir+Fuseki.PagesStatic ; + + Fuseki.configLog.debug("Static Content Directory: "+ FileOps.fullDirectoryPath(staticContentDir)) ; + + if ( ! FileOps.exists(staticContentDir) ) { + Fuseki.configLog.warn("No such directory for static content: " + FileOps.fullDirectoryPath(staticContentDir)) ; + Fuseki.configLog.warn("You may need to set the --pages or --home option to configure static content correctly"); + } + + if ( jettyConfigFile != null ) + Fuseki.configLog.info("Jetty configuration: "+jettyConfigFile) ; + + ServerConfig serverConfig ; + + if ( fusekiConfigFile != null ) + { + Fuseki.configLog.info("Configuration file: "+fusekiConfigFile) ; + serverConfig = FusekiConfig.configure(fusekiConfigFile) ; + } + else + { + serverConfig = FusekiConfig.defaultConfiguration(datasetPath, dsg, allowUpdate, listenLocal) ; + if ( ! allowUpdate ) + Fuseki.serverLog.info("Running in read-only mode."); + } + + // TODO Get from parsing config file. + serverConfig.port = port ; + serverConfig.pages = staticContentDir ; + serverConfig.mgtPort = mgtPort ; + serverConfig.pagesPort = port ; + serverConfig.loopback = listenLocal ; + serverConfig.enableCompression = enableCompression ; + serverConfig.jettyConfigFile = jettyConfigFile ; + serverConfig.authConfigFile = authConfigFile ; + serverConfig.verboseLogging = ( super.isVerbose() || super.isDebug() ) ; + + SPARQLServer server = new SPARQLServer(serverConfig) ; + + // Temporary + Fuseki.setServer(server) ; + + Server mgtServer = null ; + + if ( mgtPort > 0 ) + { + Fuseki.configLog.info("Management services on port "+mgtPort) ; + mgtServer = ManagementServer.createManagementServer(mgtPort) ; + try { mgtServer.start() ; } + catch (java.net.BindException ex) + { serverLog.error("SPARQLServer: Failed to start management server: " + ex.getMessage()) ; System.exit(1) ; } + catch (Exception ex) + { serverLog.error("SPARQLServer: Failed to start management server: " + ex.getMessage(), ex) ; System.exit(1) ; } + } + + server.start() ; + try { server.getServer().join() ; } catch (Exception ex) {} + + if ( mgtServer != null ) + { + try { mgtServer.stop() ; } + catch (Exception e) { serverLog.warn("Failed to cleanly stop the management server", e) ; } + } + System.exit(0) ; + } + + + @Override + protected String getCommandName() + { + return "fuseki" ; + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java new file mode 100644 index 0000000..5e1b018 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java @@ -0,0 +1,28 @@ +/* + * 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; + + +public class FusekiConfigException extends FusekiException +{ + public FusekiConfigException(String msg, Throwable cause) { super(msg, cause) ; } + public FusekiConfigException(String msg) { super(msg) ; } + public FusekiConfigException(Throwable cause) { super(cause) ; } + public FusekiConfigException() { super() ; } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiException.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiException.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiException.java new file mode 100644 index 0000000..04953ce --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiException.java @@ -0,0 +1,29 @@ +/* + * 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; + +import com.hp.hpl.jena.sparql.ARQException ; + +public class FusekiException extends ARQException +{ + public FusekiException(String msg, Throwable cause) { super(msg, cause) ; } + public FusekiException(String msg) { super(msg) ; } + public FusekiException(Throwable cause) { super(cause) ; } + public FusekiException() { super() ; } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiLib.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiLib.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiLib.java new file mode 100644 index 0000000..5324793 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiLib.java @@ -0,0 +1,148 @@ +/* + * 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; + +import java.util.Iterator ; + +import javax.servlet.http.HttpServletRequest ; + +import org.apache.commons.lang.StringUtils ; +import org.apache.jena.atlas.lib.MultiMap ; +import org.apache.jena.atlas.lib.MultiMapToList ; +import org.apache.jena.atlas.web.ContentType ; +import org.apache.jena.fuseki.servlets.HttpAction ; +import org.apache.jena.riot.Lang ; +import org.apache.jena.riot.RDFLanguages ; + +import com.hp.hpl.jena.graph.Graph ; +import com.hp.hpl.jena.graph.Node ; +import com.hp.hpl.jena.graph.Triple ; +import com.hp.hpl.jena.shared.PrefixMapping ; +import com.hp.hpl.jena.sparql.core.DatasetGraph ; +import com.hp.hpl.jena.sparql.core.Quad ; +import com.hp.hpl.jena.sparql.util.Convert ; + +public class FusekiLib { + /** Get the content type of an action or return the default. + * @param action + * @return ContentType + */ + public static ContentType getContentType(HttpAction action) { + return getContentType(action.request) ; + } + + /** Get the content type of an action or return the default. + * @param request + * @return ContentType + */ + public static ContentType getContentType(HttpServletRequest request) { + String contentTypeHeader = request.getContentType() ; + if ( contentTypeHeader == null ) + return null ; + return ContentType.create(contentTypeHeader) ; + } + + /** Get the incoming Lang based on Content-Type of an action. + * @param action + * @param dft Default if no "Content-Type:" found. + * @return ContentType + */ + public static Lang getLangFromAction(HttpAction action, Lang dft) { + String contentTypeHeader = action.request.getContentType() ; + if ( contentTypeHeader == null ) + return dft ; + return RDFLanguages.contentTypeToLang(contentTypeHeader) ; + } + + static String fmtRequest(HttpServletRequest request) { + StringBuilder sbuff = new StringBuilder() ; + sbuff.append(request.getMethod()) ; + sbuff.append(" ") ; + sbuff.append(Convert.decWWWForm(request.getRequestURL())) ; + + String qs = request.getQueryString() ; + if ( qs != null ) { + String tmp = request.getQueryString() ; + tmp = Convert.decWWWForm(tmp) ; + tmp = tmp.replace('\n', ' ') ; + tmp = tmp.replace('\r', ' ') ; + sbuff.append("?").append(tmp) ; + } + return sbuff.toString() ; + } + + /** Parse the query string - do not process the body even for a form */ + public static MultiMap<String, String> parseQueryString(HttpServletRequest req) { + MultiMap<String, String> map = MultiMapToList.create() ; + + // Don't use ServletRequest.getParameter or getParamterNames + // as that reads form data. This code parses just the query string. + if ( req.getQueryString() != null ) { + String[] params = req.getQueryString().split("&") ; + for ( String p : params ) + { + String[] x = p.split( "=", 2 ); + String name = null; + String value = null; + + if ( x.length == 0 ) + { // No "=" + name = p; + value = ""; + } + else if ( x.length == 1 ) + { // param= + name = x[0]; + value = ""; + } + else + { // param=value + name = x[0]; + value = x[1]; + } + map.put( name, value ); + } + } + return map ; + } + + public static String safeParameter(HttpServletRequest request, String pName) { + String value = request.getParameter(pName) ; + value = StringUtils.replaceChars(value, "\r", "") ; + value = StringUtils.replaceChars(value, "\n", "") ; + return value ; + } + + // Do the addition directly on the dataset + public static void addDataInto(Graph data, DatasetGraph dsg, Node graphName) { + // Prefixes? + if ( graphName == null ) + graphName = Quad.defaultGraphNodeGenerated ; + + Iterator<Triple> iter = data.find(Node.ANY, Node.ANY, Node.ANY) ; + for (; iter.hasNext();) { + Triple t = iter.next() ; + dsg.add(graphName, t.getSubject(), t.getPredicate(), t.getObject()) ; + } + + PrefixMapping pmapSrc = data.getPrefixMapping() ; + PrefixMapping pmapDest = dsg.getDefaultGraph().getPrefixMapping() ; + pmapDest.setNsPrefixes(pmapSrc) ; + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java new file mode 100644 index 0000000..be9be90 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java @@ -0,0 +1,26 @@ +/* + * 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; + +import org.apache.jena.web.HttpSC ; + +public class FusekiNotFoundException extends FusekiRequestException +{ + public FusekiNotFoundException(String msg) { super(HttpSC.NOT_FOUND_404, msg) ; } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java new file mode 100644 index 0000000..e197be2 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java @@ -0,0 +1,57 @@ +/* + * 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; + +import org.apache.jena.web.HttpSC ; + + +public class FusekiRequestException extends FusekiException +{ + public static FusekiRequestException create(int code, String msg) + { + if ( code == HttpSC.NOT_FOUND_404 ) + return new FusekiNotFoundException(msg) ; + return new FusekiRequestException(code, msg) ; + } + + private final int statusCode ; + private final String responseMessage ; + protected FusekiRequestException(int code, String msg) + { + super(msg) ; + this.statusCode = code ; + responseMessage = msg ; + } + + public int getStatusCode() + { + return statusCode ; + } + + public String getResponseMessage() + { + return responseMessage ; + } + + @Override + public String toString() + { + return "HTTP: "+statusCode+" "+getMessage() ; + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/HttpNames.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/HttpNames.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/HttpNames.java new file mode 100644 index 0000000..f6cee56 --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/HttpNames.java @@ -0,0 +1,93 @@ +/* + * 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; + +public class HttpNames +{ + // Request + public static final String hAccept = "Accept" ; + public static final String hAcceptEncoding = "Accept-Encoding" ; + public static final String hAcceptCharset = "Accept-Charset" ; + //public static final String hAcceptLanguage = "Accept-Language" ; + + // Response + public static final String xhAcceptRanges = "Accept-Ranges" ; + public static final String hAllow = "Allow" ; + public static final String hContentEncoding = "Content-Encoding" ; + public static final String hContentLengh = "Content-Length" ; + public static final String hContentLocation = "Content-Location" ; + public static final String hContentRange = "Content-Range" ; + public static final String hContentType = "Content-Type" ; + public static final String hRetryAfter = "Retry-After" ; + public static final String hServer = "Server" ; + public static final String hLocation = "Location" ; + public static final String hVary = "Vary" ; + public static final String charset = "charset" ; + + // CORS: + // http://www.w3.org/TR/cors/ http://esw.w3.org/CORS_Enabled + public static final String hAccessControlAllowOrigin = "Access-Control-Allow-Origin" ; + + // Fuseki parameter names + public static final String paramGraph = "graph" ; + public static final String paramGraphDefault = "default" ; + + public static final String paramQuery = "query" ; + public static final String paramQueryRef = "query-ref" ; + public static final String paramDefaultGraphURI = "default-graph-uri" ; + public static final String paramNamedGraphURI = "named-graph-uri" ; + + public static final String paramStyleSheet = "stylesheet" ; + public static final String paramAccept = "accept" ; + public static final String paramOutput1 = "output" ; // See Yahoo! developer: http://developer.yahoo.net/common/json.html + public static final String paramOutput2 = "format" ; // Alternative name + public static final String paramCallback = "callback" ; + public static final String paramForceAccept = "force-accept" ; // Force the accept header at the last moment + public static final String paramTimeout = "timeout" ; + + public static final String paramUpdate = "update" ; + public static final String paramRequest = "request" ; + public static final String paramUsingGraphURI = "using-graph-uri" ; + public static final String paramUsingNamedGraphURI = "using-named-graph-uri" ; + + public static final String METHOD_DELETE = "DELETE"; + public static final String METHOD_HEAD = "HEAD"; + public static final String METHOD_GET = "GET"; + public static final String METHOD_OPTIONS = "OPTIONS"; + public static final String METHOD_PATCH = "PATCH" ; + public static final String METHOD_POST = "POST"; + public static final String METHOD_PUT = "PUT"; + public static final String METHOD_TRACE = "TRACE"; + + public static final String HEADER_IFMODSINCE = "If-Modified-Since"; + public static final String HEADER_LASTMOD = "Last-Modified"; + + // Names for services in the default configuration + public static final String ServiceQuery = "query" ; + public static final String ServiceQueryAlt = "sparql" ; + public static final String ServiceUpdate = "update" ; + public static final String ServiceData = "data" ; + public static final String ServiceUpload = "upload" ; + public static final String ServiceGeneralQuery = "/sparql" ; + + // Posisble values of fields. + // TODO Pull in from results writer. + public static final String valueDefault = "default" ; + +} http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Test.java ---------------------------------------------------------------------- diff --git a/jena-fuseki/src/main/java/org/apache/jena/fuseki/Test.java b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Test.java new file mode 100644 index 0000000..b4f5fed --- /dev/null +++ b/jena-fuseki/src/main/java/org/apache/jena/fuseki/Test.java @@ -0,0 +1,25 @@ +/* + * 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; + +public class Test +{ + public static void init() { System.out.println("INIT called") ; } +} +