AtteanX-Endpoint
view release on metacpan or search on metacpan
AtteanX::Endpoint
=================
Created: 2016-03-25
Home page: <http://search.cpan.org/dist/AtteanX::Endpoint/>
Bug tracker: <https://github.com/kasei/atteanx-endpoint/issues>
0.002 2017-10-26
- (Update) Change hashbang to use env (#2 from KjetilK).
- (Update) Replace use of HTML::HTML5::Parser with XML::LibXML::Parser (#4
from @kjetilk).
- (Update) Updated copyright year and added text about CodeMirror license.
0.001 2016-03-25
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The CodeMirror sources included in share/endpoint/www/ are
Copyright (C) 2012 by Marijn Haverbeke <marijnh@gmail.com>
and are also licensed under the MIT License. More information may be found at
<https://github.com/codemirror/CodeMirror>.
inc/Module/Install/Share.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
lib/AtteanX/Endpoint.pm
LICENSE
Makefile.PL
MANIFEST This list of files
META.yml
meta/changes.ttl
README.md
scripts/endpoint.psgi
share/endpoint/index.html
share/endpoint/results.html
share/endpoint/www/css/docs.css
share/endpoint/www/css/sparqlcolors.css
share/endpoint/www/favicon.ico
share/endpoint/www/js/codemirror.js
share/endpoint/www/js/editor.js
share/endpoint/www/js/highlight.js
share/endpoint/www/js/mirrorframe.js
share/endpoint/www/js/parsecss.js
share/endpoint/www/js/parsedummy.js
share/endpoint/www/js/parsehtmlmixed.js
share/endpoint/www/js/parsejavascript.js
share/endpoint/www/js/parsesparql.js
share/endpoint/www/js/parsexml.js
share/endpoint/www/js/select.js
share/endpoint/www/js/sparql_form.js
share/endpoint/www/js/stringstream.js
share/endpoint/www/js/tokenize.js
share/endpoint/www/js/tokenizejavascript.js
share/endpoint/www/js/undo.js
share/endpoint/www/js/unittests.js
share/endpoint/www/js/util.js
t/00.load.t
t/simple.t
xt/pod-coverage.t
xt/pod.t
SIGNATURE Public-key signature (added by MakeMaker)
Moo: 1.006
MooX::Log::Any: 0
Plack: 0
TryCatch: 0
Types::Standard: 0
XML::LibXML: 1.7
namespace::clean: 0
perl: 5.14.0
resources:
IRC: irc://irc.perl.org/#perlrdf
bugtracker: https://github.com/kasei/atteanx-endpoint/issues
homepage: http://search.cpan.org/dist/AtteanX-Endpoint/
license: http://dev.perl.org/licenses/
repository: http://github.com/kasei/atteanx-endpoint/
version: '0.002'
Makefile.PL view on Meta::CPAN
requires 'List::MoreUtils' => 0;
requires 'Moo' => 1.006000;
requires 'MooX::Log::Any' => 0;
requires 'namespace::clean' => 0;
requires 'Plack' => 0;
requires 'TryCatch' => 0;
requires 'Types::Standard' => 0;
resources(
'homepage' => "http://search.cpan.org/dist/AtteanX-Endpoint/",
'repository' => "http://github.com/kasei/atteanx-endpoint/",
'bugtracker' => "https://github.com/kasei/atteanx-endpoint/issues",
'IRC' => "irc://irc.perl.org/#perlrdf",
);
author_tests('xt');
install_share;
write_doap_changes "meta/changes.ttl", "Changes", "turtle";
sign;
SHA1 c7f311a5bc5a7f96e9105d5f16a0e13fc596899d inc/Module/Install/Can.pm
SHA1 470809a1dbe03e197e74dde79c6af40b5f7f9b26 inc/Module/Install/DOAPChangeSets.pm
SHA1 8c8f9ff5b0a536af59814e16a901ce39fbc23299 inc/Module/Install/Fetch.pm
SHA1 4f77eb02e104324b08a047585c498146b045613b inc/Module/Install/Makefile.pm
SHA1 2f5be6af6098acf6d786a4a7299a34d0c6c04ef9 inc/Module/Install/Metadata.pm
SHA1 f7882569ead92975e7559e169c2a2e86c3de1e57 inc/Module/Install/Share.pm
SHA1 aa6723cc4a8d4475026f6ceb28e1f16459e8a11b inc/Module/Install/Win32.pm
SHA1 6661285caedfe012cb5a1ca915a422ffc292ae2b inc/Module/Install/WriteAll.pm
SHA1 e854e152322a355b9d195920c2dd4a26ee78b608 lib/AtteanX/Endpoint.pm
SHA1 078450ece1f78535d63b1020cde797a5a40ce8b5 meta/changes.ttl
SHA1 e0ed180620d47f429917d290445ac27b13173f89 scripts/endpoint.psgi
SHA1 19ac766464ef05698ac985e2a42e87dbb7912f3f share/endpoint/index.html
SHA1 6dd0cf355b49dcb0fdfe9203c68917d5320584f8 share/endpoint/results.html
SHA1 c40ebad09f7e1d92ad0228a0625d730ba2f57b84 share/endpoint/www/css/docs.css
SHA1 398bae2ae66a19ab8976036b50a2d20041b67fe5 share/endpoint/www/css/sparqlcolors.css
SHA1 aa6874f2bad5f0b75b0ff52760f5e6b48ec933ae share/endpoint/www/favicon.ico
SHA1 13fece7654a01193013d3d96528c851bfc79a300 share/endpoint/www/js/codemirror.js
SHA1 d372c911fcc2bd030da800fdeedfbcd6b0100c83 share/endpoint/www/js/editor.js
SHA1 551ff99056361eebfba2a32ea7445502a6eb4f21 share/endpoint/www/js/highlight.js
SHA1 5bff996ab2564db1a998de30cb9e1ae07cbe62b5 share/endpoint/www/js/mirrorframe.js
SHA1 d7540f8390913afc0d58484bf5161cf9b9aad9f8 share/endpoint/www/js/parsecss.js
SHA1 a0028275114eaedf7ddcf57976c99c32ecb2c1d3 share/endpoint/www/js/parsedummy.js
SHA1 39383cdfc93568cc5673e2b71f681e2811fb5463 share/endpoint/www/js/parsehtmlmixed.js
SHA1 d5319247a4b26cafccfd4f26621918f0f4d22ef4 share/endpoint/www/js/parsejavascript.js
SHA1 c6597fb9a5c7969237f7f039f2d0bc6968ef7ce7 share/endpoint/www/js/parsesparql.js
SHA1 ae75f537ad61277a21a8ec423f5deffed8454e22 share/endpoint/www/js/parsexml.js
SHA1 85cdbc16cd1581f441480d91fa5c0a50f234ff0b share/endpoint/www/js/select.js
SHA1 d3261a5ddb7e5835c7abed5d5c343f0ef98637a5 share/endpoint/www/js/sparql_form.js
SHA1 19cc324cce7165c868a60d523b2462c648f20887 share/endpoint/www/js/stringstream.js
SHA1 5fdb14f3db575d0ce6a7113f96ea5a530f4f1941 share/endpoint/www/js/tokenize.js
SHA1 7f581a2b4647f1214d1bc3160eb4e166a1261e4f share/endpoint/www/js/tokenizejavascript.js
SHA1 9bba7456d4a25b23e805bc2d1d5bde61371c4e82 share/endpoint/www/js/undo.js
SHA1 26ff15a8f6c196e8bd9f5d7e7b628a6ee9b0dfaa share/endpoint/www/js/unittests.js
SHA1 201409b1d00a8df0b65b00a1b92ab62d9e0bbd7a share/endpoint/www/js/util.js
SHA1 ba3972579f5adab59fefb48dee2f8d59247e37e6 t/00.load.t
SHA1 6c81693f964d4569f641101787e648b6a8a16272 t/simple.t
SHA1 61bf86179ce63f1148d1fb8c7a4c57bee395f7fc xt/pod-coverage.t
SHA1 6387af7a5fde0747be5bc9ad2ec15ca9759bd95a xt/pod.t
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
iEYEARECAAYFAlnyCuwACgkQhPK6VMqoyC1DXwCcDnvOYVW7g092trkfG/w9l0Rt
DrwAn3gTRxb770EnaSywBir0XrE5PDW7
=/Ref
lib/AtteanX/Endpoint.pm view on Meta::CPAN
sub configure {
my $self = shift;
$self->{config} = shift;
return $self;
}
sub prepare_app {
my $self = shift;
my $config = $self->{config};
$self->{endpoint} = eval { AtteanX::Endpoint->new( $config ) };
if ($@) {
warn $@;
}
}
sub call {
my($self, $env) = @_;
my $req = Plack::Request->new($env);
unless ($req->method =~ /^(GET|HEAD|POST)$/) {
return [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ];
}
my $ep = $self->{endpoint};
my $resp = $ep->run( $req );
return $resp->finalize;
}
}
=head1 NAME
AtteanX::Endpoint - SPARQL 1.1 Protocol Endpoint
=head1 VERSION
This document describes AtteanX::Endpoint version 0.002
=head1 SYNOPSIS
use v5.14;
use Attean;
=head1 DESCRIPTION
The AtteanX::Endpoint class implements a PSGI SPARQL Protocol endpoint.
=head1 ATTRIBUTES
=over 4
=item C<< planner >>
=item C<< model >>
=item C<< conf >>
A hash reference containing configuration data for the endpoint. For example:
{
endpoint => {
service_description => {
named_graphs => 1,
default => 1,
},
html => {
embed_images => 1,
image_width => 200,
resource_links => 1,
},
load_data => 0,
lib/AtteanX/Endpoint.pm view on Meta::CPAN
}
return $resp;
}
}
sub _run {
my $self = shift;
my $req = shift;
my $config = $self->{conf};
my $endpoint_path = $config->{endpoint}{endpoint_path} || '/sparql';
my $model = $self->{model};
my $response = Plack::Response->new;
our $VERSION;
my $server = "AtteanX::Endpoint/$VERSION";
$server .= " " . $response->headers->header('Server') if defined($response->headers->header('Server'));
$response->headers->header('Server' => $server);
unless ($req->path eq $endpoint_path) {
my $content;
my $path = $req->path_info;
$path =~ s#^/##;
my $dir = $ENV{ATTEAN_ENDPOINT_SHAREDIR} || File::Spec->catdir((eval { dist_dir('AtteanX-Endpoint') } || 'share'), 'endpoint');
my $abs = File::Spec->rel2abs($dir);
my $file = File::Spec->catfile($abs, 'www', $path);
if (-r $file) {
open( my $fh, '<', $file ) or croak $!;
$response->status(200);
$content = $fh;
} else {
my $path = $req->path;
$response->status(404);
$content = <<"END";
lib/AtteanX/Endpoint.pm view on Meta::CPAN
my $ae = $req->headers->header('Accept-Encoding') || '';
my $sparql;
my $content;
my $ct = $req->header('Content-type');
if ($req->method !~ /^(GET|POST)$/i) {
my $method = uc($req->method);
$content = "Unexpected method $method (expecting GET or POST)";
$self->log_error( $req, $content );
$response->header('Allow' => 'GET, POST');
die AtteanX::Endpoint::ClientError->new(code => 405, message => 'Method not allowed', uri => 'http://id.kasei.us/rdf-endpoint/error/bad_http_method');
} elsif (defined($ct) and $ct eq 'application/sparql-query') {
$sparql = $req->content;
} elsif (defined($ct) and $ct eq 'application/sparql-update') {
if ($config->{endpoint}{update} and $req->method eq 'POST') {
$sparql = $req->content;
}
} elsif ($req->param('query')) {
my @sparql = $req->param('query');
if (scalar(@sparql) > 1) {
$content = "More than one query string submitted";
$self->log_error( $req, $content );
die AtteanX::Endpoint::ClientError->new(code => 400, message => 'Multiple query strings not allowed', uri => 'http://id.kasei.us/rdf-endpoint/error/multiple_queries');
} else {
$sparql = $sparql[0];
}
} elsif ($req->param('update')) {
my @sparql = $req->param('update');
if (scalar(@sparql) > 1) {
$content = "More than one update string submitted";
$self->log_error( $req, $content );
die AtteanX::Endpoint::ClientError->new(code => 400, message => 'Multiple update strings not allowed', uri => 'http://id.kasei.us/rdf-endpoint/error/multiple_updates');
}
if ($config->{endpoint}{update} and $req->method eq 'POST') {
$sparql = $sparql[0];
} elsif ($req->method ne 'POST') {
my $method = $req->method;
$content = "Update operations must use POST";
$self->log_error( $req, $content );
$response->header('Allow' => 'POST');
die AtteanX::Endpoint::ClientError->new(code => 405, message => "$method Not Allowed for Update Operation", uri => 'http://id.kasei.us/rdf-endpoint/error/bad_http_method_update');
}
}
if ($sparql) {
my %args;
$args{ update } = 1 if ($config->{endpoint}{update} and $req->method eq 'POST');
$args{ load_data } = 1 if ($config->{endpoint}{load_data});
my $protocol_specifies_update_dataset = 0;
{
my @default = $req->param('default-graph-uri');
my @named = $req->param('named-graph-uri');
if (scalar(@default) or scalar(@named)) {
delete $args{ load_data };
# TODO: handle custom-dataset
$self->log->warn('custom query datasets not supported yet');
# $model = Attean::MutableQuadModel->new( store => Attean->get_store('Memory')->new() );
lib/AtteanX/Endpoint.pm view on Meta::CPAN
my $base = $req->base;
my $parser = Attean->get_parser('SPARQL')->new(base => $base);
$parser->update(1) if ($args{update});
my ($algebra) = eval { $args{update} ? $parser->parse_update($sparql, base => $base) : $parser->parse($sparql, base => $base) };
if ($@ or not($algebra)) {
my $error = $@ || 'Internal error';
$self->log_error( $req, $error );
my $eclass = ($error =~ /Syntax/) ? 'AtteanX::Endpoint::ClientError' : 'AtteanX::Endpoint::ServerError';
if ($req->method ne 'POST' and $error =~ /read-only queries/sm) {
$error = 'Updates must use a HTTP POST request.';
die $eclass->new(message => 'Updates must use a HTTP POST request', uri => 'http://id.kasei.us/rdf-endpoint/error/bad_http_method_update');
} else {
die $eclass->new(message => 'SPARQL query/update parse error', uri => 'http://id.kasei.us/rdf-endpoint/error/parse_error', details => { error => $error, sparql => $sparql });
}
} else {
$self->log_query( $req, $sparql );
# TODO: handle case where query specifies update dataset
# if ($protocol_specifies_update_dataset and $query->specifies_update_dataset) {
# my $method = $req->method;
# $content = "Update operations cannot specify a dataset in both the query and with protocol parameters";
# $self->log_error( $req, $content );
# die AtteanX::Endpoint::ClientError->new(code => 400, message => 'Multiple datasets specified for update', uri => 'http://id.kasei.us/rdf-endpoint/error/update_specifies_multiple_datasets');
# }
if ($self->log->is_trace) {
$self->log->trace("Algebra:\n" . $algebra->as_string);
}
my $graph = $self->graph;
my $default_graphs = [$graph];
my $planner = $self->planner;
if ($self->log->is_trace) {
$self->log->debug('Planning with default graphs:');
foreach my $g (@$default_graphs) {
lib/AtteanX/Endpoint.pm view on Meta::CPAN
my $sclass = Attean->negotiate_serializer(request_headers => $headers) // Attean->get_serializer('sparqlxml');
$self->log->debug("Serializer class: $sclass");
my $s = $sclass->new();
$content = $s->serialize_iter_to_bytes($iter);
my $stype = $s->canonical_media_type;
$response->headers->content_type($stype);
};
if ($@) {
my $error = $@;
$self->log->fatal($error);
die AtteanX::Endpoint::ServerError->new(code => 500, message => 'SPARQL query/update execution error', uri => 'http://id.kasei.us/rdf-endpoint/error/execution_error', details => { error => $@, sparql => $sparql });
}
}
} elsif ($req->method eq 'POST') {
$content = "POST without recognized query or update";
$self->log_error( $req, $content );
die AtteanX::Endpoint::ClientError->new(message => 'Missing SPARQL Query/Update String', uri => 'http://id.kasei.us/rdf-endpoint/error/missing_sparql_string');
} else {
my $stype = 'text/html';
my $dir = $ENV{ATTEAN_ENDPOINT_SHAREDIR} || File::Spec->catdir((eval { dist_dir('AtteanX-Endpoint') } || 'share'), 'endpoint');
my $template = File::Spec->catfile($dir, 'index.html');
my $parser = XML::LibXML->new(validation => 0, suppress_errors => 1, no_network => 1, recover => 2);
my $doc = $parser->parse_file( $template );
# my $gen = RDF::RDFa::Generator->new( style => 'HTML::Head');
# $gen->inject_document($doc, $sdmodel);
my $writer = HTML::HTML5::Writer->new( markup => 'xhtml', doctype => DOCTYPE_XHTML_RDFA );
$content = encode_utf8( $writer->document($doc) );
$response->status(200);
$response->headers->content_type('text/html');
lib/AtteanX/Endpoint.pm view on Meta::CPAN
1;
__END__
=back
=head1 BUGS
Please report any bugs or feature requests to through the GitHub web interface
at L<https://github.com/kasei/atteanx-endpoint/issues>.
=head1 SEE ALSO
L<http://www.perlrdf.org/>
=head1 AUTHOR
Gregory Todd Williams C<< <gwilliams@cpan.org> >>
=head1 COPYRIGHT
meta/changes.ttl view on Meta::CPAN
.
my:project
a :Project ;
:name "AtteanX::Endpoint" ;
:shortdesc "An Attean SPARQL 1.1 Endpoint implementation." ;
:programming-language "Perl" ;
:created "2016-03-25"^^xsd:date ;
:maintainer my:developer ;
:homepage <http://search.cpan.org/dist/AtteanX::Endpoint/> ;
:bug-database <https://github.com/kasei/atteanx-endpoint/issues> ;
doap:download-page <http://search.cpan.org/dist/AtteanX-Endpoint/> ;
doap:download-mirror <http://kasei.us/code/files/> ;
.
my:project :release my:v_0-002 .
my:v_0-002
a :Version ;
dc:issued "2017-10-26"^^xsd:date ;
:revision "0.002" ;
dcs:changeset [
scripts/endpoint.psgi view on Meta::CPAN
add_type( 'text/plain' => qw(nt) );
add_type( 'text/x-nquads' => qw(nq) );
add_type( 'text/json' => qw(json) );
add_type( 'text/html' => qw(html xhtml htm) );
my $config;
if (my $file = $ENV{RDF_ENDPOINT_FILE}) {
my $abs = File::Spec->rel2abs( $file );
$config = {
store => "Memory;$abs",
endpoint => {
service_description => {
named_graphs => 1,
default => 1,
},
html => {
embed_images => 1,
image_width => 200,
resource_links => 1,
},
load_data => 0,
update => 1,
}
};
} elsif ($config = eval { Config::JFDI->open( name => "AtteanX::Endpoint") }) {
} else {
$config = {
store => "Memory",
endpoint => {
service_description => {
named_graphs => 1,
default => 1,
},
html => {
embed_images => 1,
image_width => 200,
resource_links => 1,
},
load_data => 0,
share/endpoint/www/js/select.js view on Meta::CPAN
start: innerNode(range.startContainer, range.startOffset),
end: innerNode(range.endContainer, range.endOffset),
changed: false
};
};
select.selectMarked = function () {
var cs = currentSelection;
// on webkit-based browsers, it is apparently possible that the
// selection gets reset even when a node that is not one of the
// endpoints get messed with. the most common situation where
// this occurs is when a selection is deleted or overwitten. we
// check for that here.
function focusIssue() {
if (cs.start.node == cs.end.node && cs.start.offset == cs.end.offset) {
var selection = window.getSelection();
if (!selection || selection.rangeCount == 0) return true;
var range = selection.getRangeAt(0), point = innerNode(range.startContainer, range.startOffset);
return cs.start.node != point.node || cs.start.offset != point.offset;
}
}
use warnings;
no warnings 'redefine';
use Attean::RDF;
use AtteanX::Endpoint;
use Test::WWW::Mechanize::PSGI;
sub mech_for_nquads {
my $nquads = shift;
my $config = {
endpoint => {
service_description => {
named_graphs => 1,
default => 1,
},
html => {
embed_images => 1,
image_width => 200,
resource_links => 1,
},
load_data => 0,
( run in 0.913 second using v1.01-cache-2.11-cpan-49f99fa48dc )