Coverage report: /development/source/library/org/datagraph/spocq-shard/src/spocq-server/sesame.lisp

KindCoveredAll%
expression0830 0.0
branch034 0.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.server.implementation; -*-
2
 ;;;  Copyright 2013 [james anderson](mailto:james.anderson@setf.de) All Rights Reserved
3
 
4
 (in-package :org.datagraph.spocq.server.implementation)
5
 
6
 (:documentation "sparql sesame2 protocol"
7
 
8
 "This file implements ths responses to the documented 'HTTP communication protocol for Sesame 2'
9
 (http://openrdf.callimachus.net/sesame/2.7/docs/system.docbook?view#chapter-http-protocol),
10
 whereby operations defined in the graph store protocol are delegated to its response operator.
11
  
12
         ${STORE_URL}
13
          /${STORE_ACCOUNT}
14
           /protocol              : protocol version (GET)
15
           /repositories          : overview of available repositories (GET)
16
            /${STORE_REPOSITORY}  : query evaluation and administration tasks on 
17
                                    a repository (GET/POST/DELETE)
18
             /statements          : repository statements (GET/POST/PUT/DELETE)
19
             /contexts            : context overview (GET)
20
             /size                : #statements in repository (GET)
21
             /rdf-graphs          : named graphs overview (GET)
22
                 /service         : Graph Store operations on indirectly referenced named graphs 
23
                                    in repository (GET/PUT/POST/DELETE)
24
                                    includes the query argument graph=${STORE_IGRAPH}
25
                 /${STORE_RGRAPH} : Graph Store operations on directly referenced named graphs 
26
                                    in repository (GET/PUT/POST/DELETE)
27
             /namespaces          : overview of namespace definitions (GET/DELETE)
28
                 /${STORE_PREFIX} : namespace-prefix definition (GET/PUT/DELETE)
29
 
30
 See resources.lisp for the class definitions
31
 
32
 ")
33
 
34
 (http:def-resource-function sesame-protocol-id (resource request response)
35
   (:log )
36
   (:encode :default mime:text/plain)
37
   (:get ((resource |/:account/protocol|) request response (request-type t) (response-type t))
38
     (setf (http:response-content-disposition response) '("attachment" "filename" "protocol.txt"))
39
     +sesame-version+))
40
 
41
 
42
 
43
 (http:def-resource-function sesame-metadata-as-sparql-results (resource request response)
44
   (:documentation
45
     "Respond to requests for repository metadata: 
46
      contexts, namespaces, size are implemented directly.
47
      statements operations relegate to the graph store implementation.")
48
 
49
   (:log )
50
 
51
   (:auth http:authenticate-request-password)
52
   (:auth http:authenticate-request-token)
53
   (:auth http:authenticate-request-session)
54
   (:auth http:authenticate-request-location)
55
 
56
   (:auth http:authorize-request)
57
 
58
   (:encode :default mime:application/sparql-results+json)
59
   (:encode mime:application/sparql-results+xml)
60
   (:encode mime:application/json)
61
 
62
   (:decode mime:application/json)
63
 
64
   (:get ((resource |/:account/repositories|) request response)
65
     "Return a list of the account repositories with access information
66
      respective the request agent. This includes only those repositories with
67
      read or write access, which means, absent an authenticated agent, just the
68
      public repositories."
69
     (compute-get-accounts-repositories (resource-account resource) (http:request-agent request)))
70
 
71
   (:post ((resource |/:account/repositories|) request response)
72
     "create a repository"
73
     (let* ((specification (call-next-method))
74
            (account (resource-account resource))
75
            (repository-spec (rest (assoc "repository" specification :test #'equalp)))
76
            (repository-name (typecase repository-spec
77
                               (cons (rest (assoc "name" repository-spec :test #'equalp)))
78
                               (string repository-spec))))
79
       (if repository-name
80
         (compute-post-accounts-repositories account request response `(:name ,repository-name))
81
         (http:bad-request "A repository name is required."))))
82
 
83
   (:get ((resource |/:account/repositories/:repository/contexts|) request response request-type mime:application/sparql-results)
84
     (compute-get-contexts (resource-repository resource) (http:request-agent request)))
85
 
86
   (:get ((resource |/:account/repositories/:repository/namespaces|) request response)
87
     (let ((bindings (dydra:metadata-namespace-bindings (resource-repository resource))))
88
       (dydra:make-list-solution-field :dimensions '(?::prefix ?::namespace)
89
                                       :solutions (loop for (prefix . iri) in bindings
90
                                                        collect (list prefix (dydra:iri-lexical-form iri))))))
91
 
92
   (:delete ((resource |/:account/repositories/:repository/namespaces|) request response)
93
     (http:not-implemented))
94
 
95
   )
96
 
97
 (http:def-resource-function sesame-metadata-as-text (resource request response)
98
   (:documentation
99
     "Respond to requests for repository metadata for which the default response media type is text/plain:
100
       an individual namespace
101
       size")
102
 
103
   (:log )
104
 
105
   (:auth http:authenticate-request-password)
106
   (:auth http:authenticate-request-token)
107
   (:auth http:authenticate-request-session)
108
   (:auth http:authenticate-request-location)
109
 
110
   (:auth http:authorize-request)
111
 
112
   (:encode :default mime:text/plain)
113
   (:encode mime:application/sparql-results+json)
114
   (:encode mime:application/sparql-results+xml)
115
 
116
   (:decode mime:application/json)
117
 
118
   (:get ((resource |/:account/repositories/:repository/namespaces/:prefix|) request response (request-type t) (response-type mime:application/sparql-results))
119
     (let* ((bindings (dydra:metadata-namespace-bindings (resource-repository resource)))
120
            (prefix (resource-prefix resource))
121
            (namespace-iri (rest (assoc prefix bindings :test #'equal))))
122
       (cond (namespace-iri
123
              (dydra:make-list-solution-field :dimensions '(?::namespace)
124
                                       :solutions `((,(dydra:iri-lexical-form namespace-iri)))))
125
             (t
126
              (http:not-found "Undefined prefix: ~a" prefix)))))
127
   (:get ((resource |/:account/repositories/:repository/namespaces/:prefix|) request response (request-type t) (response-type mime:text/plain))
128
     (let* ((bindings (dydra:metadata-namespace-bindings (resource-repository resource)))
129
            (prefix (resource-prefix resource))
130
            (namespace-iri (rest (assoc prefix bindings :test #'equal))))
131
       (cond (namespace-iri
132
              (dydra:iri-lexical-form namespace-iri))
133
             (t
134
              (http:not-found "Undefined prefix: ~a" prefix)))))
135
 
136
   (:put ((resource |/:account/repositories/:repository/namespaces/:prefix|) request response)
137
     (http:not-implemented))
138
 
139
   (:delete ((resource |/:account/repositories/:repository/namespaces/:prefix|) request response)
140
     (http:not-implemented))
141
 
142
   (:get ((resource |/:account/repositories/:repository/size|) request response (request-type t) (response-type mime:application/sparql-results))
143
     (let ((size (compute-get-size (resource-repository resource) :context-list (http:request-query-arguments request "context"))))
144
       (dydra:make-list-solution-field :dimensions '(?::size)
145
                                       :solutions `((,size)))))
146
   (:get ((resource |/:account/repositories/:repository/size|) request response (request-type t) (response-type mime:text/plain))
147
         (compute-get-size (resource-repository resource) :context-list (http:request-query-arguments request "context")))
148
   )
149
 
150
 
151
 (http:def-resource-function sesame-statements (resource request response)
152
   (:documentation
153
     "Respond to requests for repository content, whereby the response it an rdf document.
154
      statements operations relegate to the graph store implementation.")
155
 
156
   (:log )
157
 
158
   (:auth http:authenticate-request-password)
159
   (:auth http:authenticate-request-token)
160
   (:auth http:authenticate-request-session)
161
 
162
   (:auth http:authorize-request)
163
 
164
   (:encode mime:application/trix)
165
   (:encode mime:application/rdf+json)
166
   (:encode :default mime:application/n-quads)
167
   (:encode mime:application/n-triples)
168
   (:encode mime:application/ld+json)
169
   (:encode mime:application/rdf+xml)
170
   (:encode mime:application/vnd.dydra.sparql-query-algebra)
171
   (:encode mime:application/sparql-results+json)
172
   (:encode mime:application/sparql-results+xml)
173
   (:encode mime:text/csv)
174
   (:encode mime:text/tab-separated-values)
175
   (:encode mime:text/turtle)
176
   (:encode mime:text/vnd.dydra.sparql-query-algebra+graphviz)
177
   (:encode mime:text/x-graphviz)
178
 
179
   #+(or)                                ; incorrect, get must be a sparql request
180
   (:get ((resource |/:account/repositories/:repository|) request response request-type (response-type mime:rdf))
181
     (graph-store-get-graph resource request response request-type response-type))
182
   #+(or)                                ; incorrect, post must be a sparql request
183
   (:post ((resource |/:account/repositories/:repository|) request response (request-type mime:rdf) response-type)
184
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
185
       (unwind-protect (progn (graph-store-post-content resource request response pathname effective-content-type)
186
                              nil)
187
         (conditional-delete-file pathname))))
188
 
189
   #+(or)
190
   ;; this approach to create a repository does not work, as it introduces a repository instance
191
   ;; but fails to authenticate it
192
   (:put ((resource |/:account/repositories/:repository|) request response)
193
         "create a repository. idempotent"
194
         (let ((repository (resource-repository resource)))
195
           (dydra:create-repository repository :if-exists nil)
196
           (setf (http:response-location response) (request-resource-location request resource))
197
           (setf (http:response-etag response) (spocq.i::resolve-repository-revision-id repository))
198
           (setf (http:response-status-code response) http:no-content)))
199
 
200
   ;; for ask and select
201
   (:get ((resource |/:account/repositories/:repository|) request response (request-type null) (response-type mime:application/sparql-results))
202
     (let ((query (http:request-query-argument request "query")))
203
       (if (plusp (length query))
204
         (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))
205
         (http:bad-request "The request must include a query."))))
206
 
207
   ;; for queries (construct and describe) and for graph content
208
   (:get ((resource |/:account/repositories/:repository|) request response (request-type null) (response-type mime:rdf))
209
     (let ((query (http:request-query-argument request "query")))
210
       (if (plusp (length query))
211
         (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))
212
         (graph-store-get-graph resource request response request-type response-type))))
213
 
214
   (:get ((resource |/:account/repositories/:repository|) request response (request-type null) (response-type mime:text/x-graphviz))
215
     (let ((query (http:request-query-argument request "query")))
216
       (if (plusp (length query))
217
         (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))
218
         (graph-store-get-graph resource request response request-type response-type))))
219
 
220
   (:get ((resource |/:account/repositories/:repository|) request response (request-type null) (response-type mime:text/csv))
221
     (let ((query (http:request-query-argument request "query")))
222
       (if (plusp (length query))
223
         (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))
224
         (graph-store-get-graph resource request response request-type response-type))))
225
 
226
   (:get ((resource |/:account/repositories/:repository|) request response (request-type null) (response-type mime:text/tab-separated-values))
227
     (let ((query (http:request-query-argument request "query")))
228
       (if (plusp (length query))
229
         (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))
230
         (graph-store-get-graph resource request response request-type response-type))))
231
 
232
 
233
   (:post ((resource |/:account/repositories/:repository|) request response (request-type mime:application/sparql-query) (response-type mime:application/sparql-results))
234
     ;; given a body with just the query text accept the entire body.
235
     (graph-store-query resource (http:request-body request) request response request-type (http:response-media-type response)))
236
 
237
   (:post ((resource |/:account/repositories/:repository|) request response (request-type mime:application/x-www-form-urlencoded) (response-type mime:application/sparql-results))
238
     ;; given a form body, decode it ans extract the query
239
     (let ((query (http:request-post-argument request "query")))
240
       (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))))
241
 
242
   (:post ((resource |/:account/repositories/:repository|) request response (request-type mime:application/sparql-query) (response-type mime:rdf))
243
     ;; given a body with just the query text accept the entire body.
244
     (graph-store-query resource (http:request-body request) request response request-type (http:response-media-type response)))
245
 
246
   (:post ((resource |/:account/repositories/:repository|) request response (request-type mime:application/x-www-form-urlencoded) (response-type mime:rdf))
247
     ;; given a form body, decode it ans extract the query
248
     (let ((query (http:request-post-argument request "query")))
249
       (graph-store-query resource query request response mime:application/sparql-query (http:response-media-type response))))
250
 
251
 
252
   (:delete ((resource |/:account/repositories/:repository|) request response)
253
     (http:not-implemented))
254
   
255
   (:get ((resource |/:account/repositories/:repository/statements|) request response request-type response-type)
256
     "Return the repository content which satisfies the contraints.
257
      Pass the subject/predicate/object as supplied, but use the interned context from the graph-resource mix-in.
258
      If there is no matched content, do not issue a 404, but rather just return no content.
259
      in order to support multiple contexts, if the are context arguments, iterate over them and encode each response in turn.
260
      If none is provided, then just return the stream from the global match"
261
     (let ((graphs (resource-graphs resource)))
262
       (if graphs
263
         (loop for graph in graphs
264
               for content-stream = (handler-case (graph-store-get-graph resource request response request-type response-type
265
                                                                         :subject (http:request-query-argument request "subj")
266
                                                                         :predicate (http:request-query-argument request "pred")
267
                                                                         :object (http:request-query-argument request "obj")
268
                                                                         :context graph)
269
                                      (http:not-found () nil))
270
               when content-stream
271
               do (http:encode-response content-stream response(http:response-media-type response)))
272
         (handler-case (graph-store-get-graph resource request response request-type response-type
273
                                                                         :subject (http:request-query-argument request "subj")
274
                                                                         :predicate (http:request-query-argument request "pred")
275
                                                                         :object (http:request-query-argument request "obj"))
276
                                      (http:not-found () nil)))))                      
277
 
278
   (:post ((resource |/:account/repositories/:repository/statements|) request response request-type response-type)
279
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
280
       (unwind-protect (progn (unless (resource-graph resource)
281
                                ;; sesame requests w/o a graph do not create a new one
282
                                ;; "The operation is executed on all statements that are in the repository if no context is specified"
283
                                ;; (see http://openrdf.callimachus.net/sesame/2.7/docs/system.docbook?view#repository-statements)
284
                                (setf (resource-graph resource) |urn:dydra|:|default|))
285
                              (graph-store-post-content resource request response pathname effective-content-type)
286
                              nil)
287
         (conditional-delete-file pathname))
288
       (http:no-content)))
289
 
290
   (:put ((resource |/:account/repositories/:repository/statements|) request response request-type response-type)
291
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
292
       (unwind-protect (progn (graph-store-put-content resource request response pathname effective-content-type)
293
                              nil)
294
         (conditional-delete-file pathname))
295
       (http:no-content)))
296
 
297
   (:delete ((resource |/:account/repositories/:repository/statements|) request response request-type response-type)
298
     "delete repository content, but permit it to be idempotent."
299
     (let ((*graph-store-if-empty-condition* 'http:no-content))
300
       (graph-store-delete-graph resource request response)
301
       (http:no-content)))
302
 
303
   (:decode mime:text/plain :as mime:application/n-triples)
304
 
305
   (:decode ((resource |/:account/repositories/:repository/statements|) request response (request-type mime:rdf) (response-type t))
306
            (let* ((repository (resource-repository resource))
307
                   (pathname (tmp-import-pathname (dydra:repository-account repository) repository))
308
                   (content-length (http:request-content-length request))
309
                   (import-limit (spocq.e:import-limit)))
310
              (when content-length 
311
                (unless (<= content-length import-limit)
312
                  (http:request-entity-too-large "Content exceeds length limit: ~s." import-limit)))
313
              (http:copy-stream (http:request-content-stream request) pathname :length (or content-length import-limit))
314
              (values pathname request-type)))
315
   
316
   (:decode ((resource |/:account/repositories/:repository/statements|) request response (request-type mime:application/trix) (response-type t))
317
            "translate trix into nquads"
318
            (let* ((repository (resource-repository resource))
319
                   (pathname (call-next-method))
320
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
321
                   (process (unwind-protect (run-program "/opt/dydra/bin/trix2nq" ()
322
                                                         :input pathname :output nq-pathname
323
                                                         :wait t)
324
                              (conditional-delete-file pathname))))
325
              (unless (and process (zerop (run-program-exit-code process)))
326
                (conditional-delete-file nq-pathname)
327
                (http:bad-request "Failed to convert trix content."))
328
              (when process (run-program-close process))
329
              (values nq-pathname mime:application/n-quads)))
330
   
331
   (:decode ((resource |/:account/repositories/:repository/statements|) request response (request-type mime:application/rdf+json) (response-type t))
332
            "transate rdf+json into nquads"
333
            (let* ((repository (resource-repository resource))
334
                   (pathname (call-next-method))
335
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
336
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "json" "-o" "nquads"
337
                                                                                   ,(namestring (truename pathname)) "-")
338
                                                         
339
                                                         :output nq-pathname
340
                                                         :wait t)
341
                              (conditional-delete-file pathname))))
342
              (unless (and process (zerop (run-program-exit-code process)))
343
                (conditional-delete-file nq-pathname)
344
                (http:bad-request "Failed to convert json content."))
345
              (when process (run-program-close process))
346
              (values nq-pathname mime:application/n-quads)))
347
   
348
   (:decode ((resource |/:account/repositories/:repository/statements|) request response (request-type mime:application/xhtml+xml) (response-type t))
349
            "transate application/xhtml+xml as rdfa into nquads. allows for non-standard 'application/xhtml+rdfa'.
350
      (see http://www.w3.org/TR/rdfa-in-html/)"
351
            (let* ((repository (resource-repository resource))
352
                   (pathname (call-next-method))
353
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
354
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "rdfa" "-o" "nquads"
355
                                                                                   ,(namestring (truename pathname)) "-")
356
                                                         
357
                                                         :output nq-pathname
358
                                                         :wait t)
359
                              (conditional-delete-file pathname))))
360
              (unless (and process (zerop (run-program-exit-code process)))
361
                (conditional-delete-file nq-pathname)
362
                (http:bad-request "Failed to convert xhtml+rdfa content."))
363
              (when process (run-program-close process))
364
              (values nq-pathname mime:application/n-quads)))
365
   
366
   (:decode ((resource |/:account/repositories/:repository/statements|) request response (request-type mime:text/html) (response-type t))
367
            "transate text/html as rdfa into nquads. allows for non-standard 'text/html+rdfa'.
368
      (see http://www.w3.org/TR/rdfa-in-html/)"
369
            (let* ((repository (resource-repository resource))
370
                   (pathname (call-next-method))
371
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
372
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "rdfa" "-o" "nquads"
373
                                                                                   ,(namestring (truename pathname)) "-")
374
                                                         
375
                                                         :output nq-pathname
376
                                                         :wait t)
377
                              (conditional-delete-file pathname))))
378
              (unless (and process (zerop (run-program-exit-code process)))
379
                (conditional-delete-file nq-pathname)
380
                (http:bad-request "Failed to convert text/html content."))
381
              (when process (run-program-close process))
382
              (values nq-pathname mime:application/n-quads)))
383
   )
384
 
385
 (defmethod http.i::log-http-function ((function-name t) (resource repository-resource) (request t) (response t) (content-type t) (accept-type t) (methods t))
386
   (call-next-method)
387
   (format *trace-output* "~%graph:~11t~s" (resource-graphs resource)))
388
 
389
 
390
 
391
 
392
 
393
 (http:def-resource-function sesame-service (resource request response)
394
   (:log )
395
 
396
   (:auth http:authenticate-request-password)
397
   (:auth http:authenticate-request-token)
398
   (:auth http:authenticate-request-session)
399
   (:auth http:authenticate-request-location)
400
 
401
   (:auth http:authorize-request)
402
 
403
   ;; responses are just the rdf document media types
404
   (:encode mime:application/trix)
405
   (:encode mime:application/rdf+json)
406
   (:encode :default mime:application/n-quads)
407
   (:encode mime:application/n-triples)
408
   (:encode mime:application/ld+json)
409
   (:encode mime:application/rdf+xml)
410
   (:encode mime:text/turtle)
411
   (:encode mime:text/x-graphviz)
412
 
413
   (:get ((resource |/:account/repositories/:repository/rdf-graphs|) request response request-type response-type)
414
     (multiple-value-bind (solutions dimensions)
415
                              (dydra:sparql-query "SELECT DISTINCT ?contextID WHERE {GRAPH ?contextID {?s ?p ?o}}"
416
                                           :repository (resource-repository resource))
417
           (dydra:make-list-solution-field :dimensions dimensions
418
                                      :solutions solutions)))
419
 
420
   (:get ((resource |/:account/repositories/:repository/rdf-graphs/service|) request response request-type (response-type mime:rdf))
421
     (graph-store-get-graph resource request response request-type response-type))
422
 
423
   (:get ((resource |/:account/repositories/:repository/rdf-graphs/service|) request response request-type (response-type mime:text/x-graphviz))
424
     (graph-store-get-graph resource request response request-type response-type))
425
 
426
   (:post ((resource |/:account/repositories/:repository/rdf-graphs/service|) request response request-type response-type)
427
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
428
       (unwind-protect (progn (graph-store-post-content resource request response pathname effective-content-type)
429
                              nil)
430
         (conditional-delete-file pathname))))
431
 
432
   (:put ((resource |/:account/repositories/:repository/rdf-graphs/service|) request response request-type response-type)
433
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
434
       (unwind-protect (progn (graph-store-put-content resource request response pathname effective-content-type)
435
                              nil)
436
         (conditional-delete-file pathname))))
437
 
438
   (:delete ((resource |/:account/repositories/:repository/rdf-graphs/service|) request response request-type response-type)
439
     (graph-store-delete-graph resource request response))
440
 
441
   (:get ((resource |/:account/repositories/:repository/rdf-graphs/:graph|) request response request-type (response-type mime:rdf))
442
     (graph-store-get-graph resource request response request-type response-type))
443
 
444
   (:get ((resource |/:account/repositories/:repository/rdf-graphs/:graph|) request response request-type (response-type mime:text/x-graphviz))
445
     (graph-store-get-graph resource request response request-type response-type))
446
 
447
   (:post ((resource |/:account/repositories/:repository/rdf-graphs/:graph|) request response request-type response-type)
448
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
449
       (unwind-protect (progn (graph-store-post-content resource request response pathname effective-content-type)
450
                              nil)
451
         (conditional-delete-file pathname))))
452
 
453
   (:put ((resource |/:account/repositories/:repository/rdf-graphs/:graph|) request response request-type response-type)
454
     (multiple-value-bind (pathname effective-content-type) (call-next-method)
455
       (unwind-protect (progn (graph-store-put-content resource request response pathname effective-content-type)
456
                              nil)
457
         (conditional-delete-file pathname))))
458
 
459
   (:delete ((resource |/:account/repositories/:repository/rdf-graphs/:graph|) request response (request-type t) (response-type t))
460
     (graph-store-delete-graph resource request response))
461
 
462
 
463
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:rdf) (response-type t))
464
            (let* ((repository (resource-repository resource))
465
                   (pathname (tmp-import-pathname (dydra:repository-account repository) repository))
466
                   (content-length (http:request-content-length request))
467
                   (import-limit (spocq.e:import-limit)))
468
              (when content-length 
469
                (unless (<= content-length import-limit)
470
                  (http:request-entity-too-large "Content exceeds length limit: ~s." import-limit)))
471
              (http:copy-stream (http:request-content-stream request) pathname :length (or content-length import-limit))
472
              (values pathname request-type)))
473
   
474
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:application/trix) (response-type t))
475
            "translate trix into nquads"
476
            (let* ((repository (resource-repository resource))
477
                   (pathname (call-next-method))
478
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
479
                   (process (unwind-protect (run-program "/opt/dydra/bin/trix2nq" ()
480
                                                         :input pathname :output nq-pathname
481
                                                         :wait t)
482
                              (conditional-delete-file pathname))))
483
              (unless (and process (zerop (run-program-exit-code process)))
484
                (conditional-delete-file nq-pathname)
485
                (http:internal-error "trix to nquad conversion failed."))
486
              (when process (run-program-close process))
487
              (values nq-pathname mime:application/n-quads)))
488
   
489
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:application/rdf+json) (response-type t))
490
            "transate rdf+json into nquads"
491
            (let* ((repository (resource-repository resource))
492
                   (pathname (call-next-method))
493
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
494
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "json" "-o" "nquads"
495
                                                                                   ,(namestring (truename pathname)) "-")
496
                                                         
497
                                                         :output nq-pathname
498
                                                         :wait t)
499
                              (conditional-delete-file pathname))))
500
              (unless (and process (zerop (run-program-exit-code process)))
501
                (conditional-delete-file nq-pathname)
502
                (http:internal-error "trix to nquad conversion failed."))
503
              (when process (run-program-close process))
504
              (values nq-pathname mime:application/n-quads)))
505
   
506
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:application/xhtml+xml) (response-type t))
507
            "transate application/xhtml+xml as rdfa into nquads. allows for non-standard 'application/xhtml+rdfa'.
508
      (see http://www.w3.org/TR/rdfa-in-html/)"
509
            (let* ((repository (resource-repository resource))
510
                   (pathname (call-next-method))
511
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
512
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "rdfa" "-o" "nquads"
513
                                                                                   ,(namestring (truename pathname)) "-")
514
                                                         
515
                                                         :output nq-pathname
516
                                                         :wait t)
517
                              (delete-file pathname))))
518
              (unless (and process (zerop (run-program-exit-code process)))
519
                (conditional-delete-file nq-pathname)
520
                (http:internal-error "xhtml+rdfa to nquad conversion failed."))
521
              (when process (run-program-close process))
522
              (values nq-pathname mime:application/n-quads)))
523
   
524
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:text/html) (response-type t))
525
            "transate text/html as rdfa into nquads. allows for non-standard 'text/html+rdfa'.
526
      (see http://www.w3.org/TR/rdfa-in-html/)"
527
            (let* ((repository (resource-repository resource))
528
                   (pathname (call-next-method))
529
                   (nq-pathname (tmp-import-pathname (dydra:repository-account repository) repository))
530
                   (process (unwind-protect (run-program "/opt/dydra/bin/rapper" `("-q" "-i" "rdfa" "-o" "nquads"
531
                                                                                   ,(namestring (truename pathname)) "-")
532
                                                         :output nq-pathname
533
                                                         :wait t)
534
                              (delete-file pathname))))
535
              (unless (and process (zerop (run-program-exit-code process)))
536
                (conditional-delete-file nq-pathname)
537
                (http:internal-error "html+rdfa to nquad conversion failed."))
538
              (when process (run-program-close process))
539
              (values nq-pathname mime:application/n-quads)))
540
 
541
   (:decode ((resource |/:account/repositories/:repository/rdf-graphs|) request response (request-type mime:text/plain) (response-type t))
542
     "Perform the receive of text/plain request data into a file and return the pathname to
543
      be used directly as n-triples"
544
     (let* ((repository (resource-repository resource))
545
            (pathname (tmp-import-pathname (dydra:repository-account repository) repository))
546
            (content-length (http:request-content-length request))
547
            (import-limit (spocq.e:import-limit)))
548
       (when content-length 
549
         (unless (<= content-length import-limit)
550
           (http:request-entity-too-large "Content exceeds length limit: ~s." import-limit)))
551
       (http:copy-stream (http:request-content-stream request) pathname :length (or content-length import-limit))
552
       (values pathname mime:application/n-triples)))
553
   
554
   )