| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
4
|
|
|
4
|
|
67866
|
use strict; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
95
|
|
|
2
|
4
|
|
|
4
|
|
12
|
use warnings; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
161
|
|
|
3
|
|
|
|
|
|
|
package Plack::App::DAIA; |
|
4
|
|
|
|
|
|
|
{ |
|
5
|
|
|
|
|
|
|
$Plack::App::DAIA::VERSION = '0.45_1'; |
|
6
|
|
|
|
|
|
|
} |
|
7
|
|
|
|
|
|
|
#ABSTRACT: DAIA Server as Plack application |
|
8
|
|
|
|
|
|
|
|
|
9
|
4
|
|
|
4
|
|
14
|
use feature ':5.10'; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
434
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
4
|
|
|
4
|
|
348
|
use parent 'Plack::Component'; |
|
|
4
|
|
|
|
|
204
|
|
|
|
4
|
|
|
|
|
18
|
|
|
12
|
4
|
|
|
4
|
|
36686
|
use LWP::Simple qw(get); |
|
|
4
|
|
|
|
|
170384
|
|
|
|
4
|
|
|
|
|
28
|
|
|
13
|
4
|
|
|
4
|
|
629
|
use Encode; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
203
|
|
|
14
|
4
|
|
|
4
|
|
1557
|
use JSON; |
|
|
4
|
|
|
|
|
24903
|
|
|
|
4
|
|
|
|
|
25
|
|
|
15
|
4
|
|
|
4
|
|
1998
|
use DAIA; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Scalar::Util qw(blessed); |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Plack::Util::Accessor qw(xsd xslt warnings code idformat initialized html); |
|
19
|
|
|
|
|
|
|
use Plack::Middleware::Static; |
|
20
|
|
|
|
|
|
|
use File::ShareDir qw(dist_dir); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use Plack::Request; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our %FORMATS = DAIA->formats; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub prepare_app { |
|
27
|
|
|
|
|
|
|
my $self = shift; |
|
28
|
|
|
|
|
|
|
return if $self->initialized; |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
$self->warnings(1) unless defined $self->warnings; |
|
31
|
|
|
|
|
|
|
$self->idformat(qr{^.*$}) unless defined $self->idformat; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
if ($self->html) { |
|
34
|
|
|
|
|
|
|
$self->html( Plack::Middleware::Static->new( |
|
35
|
|
|
|
|
|
|
path => qr{daia\.(xsl|css)$|xmlverbatim\.xsl$|icon/[a-z0-9_-]+\.png$}, |
|
36
|
|
|
|
|
|
|
root => dist_dir('Plack-App-DAIA') |
|
37
|
|
|
|
|
|
|
)); |
|
38
|
|
|
|
|
|
|
$self->xslt( '/daia.xsl' ) unless $self->xslt; # TODO: fix base path |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
$self->init; |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
$self->initialized(1); |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub init { |
|
47
|
|
|
|
|
|
|
# initialization hook |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub call { |
|
51
|
|
|
|
|
|
|
my ($self, $env) = @_; |
|
52
|
|
|
|
|
|
|
my $req = Plack::Request->new($env); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my $id = $req->param('id') // ''; |
|
55
|
|
|
|
|
|
|
my $invalid_id = ''; |
|
56
|
|
|
|
|
|
|
my %parts; |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
if ( $self->html and $id eq '' ) { |
|
59
|
|
|
|
|
|
|
my $resp = $self->html->_handle_static( $env ); |
|
60
|
|
|
|
|
|
|
if ($resp and $resp->[0] eq 200) { |
|
61
|
|
|
|
|
|
|
return $resp; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
if ( $id ne '' and ref $self->idformat ) { |
|
66
|
|
|
|
|
|
|
if ( ref $self->idformat eq 'Regexp' ) { |
|
67
|
|
|
|
|
|
|
if ( $id =~ $self->idformat ) { |
|
68
|
|
|
|
|
|
|
%parts = %+; # named capturing groups |
|
69
|
|
|
|
|
|
|
} else { |
|
70
|
|
|
|
|
|
|
$invalid_id = $id; |
|
71
|
|
|
|
|
|
|
$id = ""; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
my $format = lc($req->param('format')) || ""; |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
if (!$format) { |
|
79
|
|
|
|
|
|
|
# TODO: guess format via content negotiation |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
my $status = 200; |
|
83
|
|
|
|
|
|
|
my $daia = $self->retrieve( $id, %parts ); |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
if (!$daia) { |
|
86
|
|
|
|
|
|
|
$daia = DAIA::Response->new; |
|
87
|
|
|
|
|
|
|
$status = 500; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
if ( $self->warnings ) { |
|
91
|
|
|
|
|
|
|
if ( $invalid_id ne '' ) { |
|
92
|
|
|
|
|
|
|
$daia->addMessage( 'en' => 'unknown identifier format', errno => 400 ); |
|
93
|
|
|
|
|
|
|
} elsif ( $id eq "" ) { |
|
94
|
|
|
|
|
|
|
$daia->addMessage( 'en' => 'please provide a document identifier', errno => 400 ); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
$self->as_psgi( $status, $daia, $format, $req->param('callback') ); |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub retrieve { |
|
102
|
|
|
|
|
|
|
my $self = shift; |
|
103
|
|
|
|
|
|
|
return $self->code ? $self->code->(@_) : undef; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub as_psgi { |
|
107
|
|
|
|
|
|
|
my ($self, $status, $daia, $format, $callback) = @_; |
|
108
|
|
|
|
|
|
|
my ($content, $type); |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
$type = $FORMATS{$format} unless $format eq 'xml'; |
|
111
|
|
|
|
|
|
|
$content = $daia->serialize($format) if $type; |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
if (!$content) { |
|
114
|
|
|
|
|
|
|
$type = "application/xml; charset=utf-8"; |
|
115
|
|
|
|
|
|
|
if ( $self->warnings ) { |
|
116
|
|
|
|
|
|
|
if ( not $format ) { |
|
117
|
|
|
|
|
|
|
$daia->addMessage( 'en' => 'please provide an explicit parameter format=xml', 300 ); |
|
118
|
|
|
|
|
|
|
} elsif ( $format ne 'xml' ) { |
|
119
|
|
|
|
|
|
|
$daia->addMessage( 'en' => 'unknown or unsupported format', 300 ); |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
$content = $daia->xml( header => 1, xmlns => 1, ( $self->xslt ? (xslt => $self->xslt) : () ) ); |
|
123
|
|
|
|
|
|
|
} elsif ( $type =~ qr{^application/javascript} and ($callback || '') =~ /^[\w\.\[\]]+$/ ) { |
|
124
|
|
|
|
|
|
|
$content = "$callback($content)"; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
return [ $status, [ "Content-Type" => $type ], [ encode('utf8',$content) ] ]; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
1; |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
__END__ |
|
134
|
|
|
|
|
|
|
=pod |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head1 NAME |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Plack::App::DAIA - DAIA Server as Plack application |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head1 VERSION |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
version 0.45_1 |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
To quickly hack a DAIA server, create a simple C<app.psgi>: |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
use Plack::App::DAIA; |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Plack::App::DAIA->new( code => sub { |
|
151
|
|
|
|
|
|
|
my $id = shift; |
|
152
|
|
|
|
|
|
|
# ...construct and return DAIA object |
|
153
|
|
|
|
|
|
|
} ); |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
To create your own DAIA server, you should better derive from this class: |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
package Your::App; |
|
158
|
|
|
|
|
|
|
use parent 'Plack::App::DAIA'; |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub retrieve { |
|
161
|
|
|
|
|
|
|
my ($self, $id, %parts) = @_; |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# construct DAIA object (you must extend this in your application) |
|
164
|
|
|
|
|
|
|
my $daia = DAIA::Response->new; |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
return $daia; |
|
167
|
|
|
|
|
|
|
}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
1; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Then create an C<app.psgi> that returns an instance of your class: |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
use Your::App; |
|
174
|
|
|
|
|
|
|
Your::App->new; |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
You can also mix this application with L<Plack> middleware. |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
It is highly recommended to test your services! Testing is made as easy as |
|
179
|
|
|
|
|
|
|
possible with the L<provedaia> command line script. |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
This module contains a dummy application C<app.psgi> and a more detailed |
|
182
|
|
|
|
|
|
|
example C<examples/daia-ubbielefeld.pl>. |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
This module implements a L<DAIA> server as PSGI application. It provides |
|
187
|
|
|
|
|
|
|
serialization in DAIA/XML and DAIA/JSON and automatically adds some warnings |
|
188
|
|
|
|
|
|
|
and error messages. The core functionality must be implemented by deriving |
|
189
|
|
|
|
|
|
|
from this class and implementing the method C<retrieve>. The following |
|
190
|
|
|
|
|
|
|
serialization formats are supported by default: |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=over 4 |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=item xml |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
DAIA/XML format (default) |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=item json |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
DAIA/JSON format |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item rdfjson |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
DAIA/RDF in RDF/JSON. |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=back |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
In addition you get DAIA/RDF in several RDF formats (C<rdfxml>, |
|
209
|
|
|
|
|
|
|
C<turtle>, and C<ntriples> if L<RDF::Trine> is installed. If L<RDF::NS> is |
|
210
|
|
|
|
|
|
|
installed, you also get known namespace prefixes for RDF/Turtle format. |
|
211
|
|
|
|
|
|
|
Furthermore the output formats C<svg> and C<dot> are supported if |
|
212
|
|
|
|
|
|
|
L<RDF::Trine::Exporter::GraphViz> is installed to visualize RDF graphs |
|
213
|
|
|
|
|
|
|
(you may need to make sure that C<dot> is in your C<$ENV{PATH}>). |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head1 METHODS |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head2 new ( [%options] ) |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Creates a new DAIA server. Supported options are |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=over 4 |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item xslt |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Path of a DAIA XSLT client to attach to DAIA/XML responses. Not required if |
|
226
|
|
|
|
|
|
|
option "html" is set. |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=item html |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Enable HTML client for DAIA/XML via XSLT. The client is returned in form of |
|
231
|
|
|
|
|
|
|
three files (C<daia.xsl>, C<daia.css>, C<xmlverbatim.xsl>) and approriate |
|
232
|
|
|
|
|
|
|
icons, that are all shipped with this module. |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item xsd |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Path of a DAIA XML Schema to validate DAIA/XML response. |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item warnings |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Enable warnings in the DAIA response (enabled by default). |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=item code |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Code reference to the 'retrieve' method if you prefer not to create a |
|
245
|
|
|
|
|
|
|
module derived from this module. |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=item idformat |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Optional regular expression to validate identifiers. Invalid identifiers |
|
250
|
|
|
|
|
|
|
are set to the empty string before they are passed to the 'retrieve' |
|
251
|
|
|
|
|
|
|
method. In addition an error message "unknown identifier format" is |
|
252
|
|
|
|
|
|
|
added to the response, if warnings are enabled. |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
It is recommended to use regular expressions with named capturing groups |
|
255
|
|
|
|
|
|
|
as introduced in Perl 5.10. The named parts are also passed to the |
|
256
|
|
|
|
|
|
|
retrieve method. For instance: |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
idformat => qr{^ (?<prefix>[a-z]+) : (?<local>.+) $}x |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
will give you C<$parts{prefix}> and C<$parts{local}> in the retrieve method. |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=item initialized |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Stores whether the application had been initialized. |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=back |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=head2 retrieve ( $id [, %parts ] ) |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
Must return a status and a L<DAIA::Response> object. Override this method |
|
271
|
|
|
|
|
|
|
if you derive an application from Plack::App::DAIA. By default it either |
|
272
|
|
|
|
|
|
|
calls the retrieve code, as passed to the constructor, or returns undef, |
|
273
|
|
|
|
|
|
|
so a HTTP 500 error is returned. |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
This method is passed the original query identifier and a hash of named |
|
276
|
|
|
|
|
|
|
capturing groups from your identifier format. |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head2 init |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
This method is called by L<Plack::Component>::prepare_app, once before the |
|
281
|
|
|
|
|
|
|
first request. You can define this method in you subclass as initialization |
|
282
|
|
|
|
|
|
|
hook, for instance to set default option values. Initialization during runtime |
|
283
|
|
|
|
|
|
|
can be triggered by setting C<initialized> to false. |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head2 as_psgi ( $status, $daia [, $format [, $callback ] ] ) |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Serializes a L<DAIA::Response> in some DAIA serialization format (C<xml> by |
|
288
|
|
|
|
|
|
|
default) and returns a a PSGI response with given HTTP status code. |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
L<Plack::App::DAIA::Validator> and L<Plack::DAIA::Test>. |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 AUTHOR |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Jakob Voss |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
This software is copyright (c) 2012 by Jakob Voss. |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
303
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
|
306
|
|
|
|
|
|
|
|