Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/ssl/ssl-api-internal.lisp
| Kind | Covered | All | % |
| expression | 0 | 719 | 0.0 |
| branch | 0 | 42 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- package: org.dataagraph.spocq.implementation -*-
3
;;; define the internal operators which implement the SSL core api
5
;;; (load (compile-file "/opt/spocq/patches/ssl/ssl-api-internal.lisp"))
7
;;; see file:///Development/Downloads/VOWL/WebVOWL_Single_Ont/webvowl.html
8
;;; for the ontology diagram generator
10
;;; http : http://www.w3.org/TR/HTTP-in-RDF10
11
;;; http-headers : http://www.w3.org/2011/http-headers
15
(defparameter *request-http-method* "POST")
17
(define-condition ssl::control-condition (condition)
18
((tag :initform (error "tag is required")
20
:reader ssl::condition-tag)))
22
(defun ssl::control-condition (tag)
23
(make-condition 'ssl::control-condition :tag tag))
27
;;; operator implementations
29
(defgeneric ssl::abort-transaction (transaction)
30
(:documentation "Abort the given transaction.
31
If either no transaction exists, or the current transactionis no longer active, the operation
33
Returns the transaction.")
34
(:method ((targets list))
35
;; allow null at this level
36
(loop for target in targets do (ssl::abort-transaction target)))
37
(:method ((transaction transaction))
38
(transaction-close transaction :abort)
40
(:method ((dataset string))
41
(ssl::abort-transaction (repository dataset)))
42
(:method ((dataset repository))
43
(let ((transaction (task-dataset-transaction *task* dataset)))
45
(ssl::abort-transaction transaction)
46
(error "No transaction active for specified dataset: ~s" dataset)))))
49
(defgeneric ssl::begin-transaction (task dataset &key mode)
50
(:documentation "Begin a new transaction for the given dataset in the active thread for the active task.
51
If the dataset is the task's primary, then the transaction should become its primary transaction.
52
The default dataset is the thread's current dataset.
53
If there is no transaction for the dataset, create a new one and register it.
54
If there is one reuse it.
55
In either case, ensure it is bound as the task's primary.
56
As the last step, ensure that it is open.
59
nb. this operation does not apply any authorization constraints. Within the query processor,
60
protection rules are applied at the point where a dataset is instantiated, as they apply
61
to entities other than just repositories - for example notification and federation client
62
request streams. Within the store, the read/write authorization are applied independent of
63
any within the query processor.")
65
(:method ((task task) (revision repository-revision) &key (mode (task-access-mode task)))
66
;; (print (list :begin-transaction task revision (repository-id revision) mode) *trace-output*)
67
(let ((transaction (ensure-task-dataset-transaction task revision mode)))
68
;; (print (list :begin-transaction transaction) *trace-output*)
69
(when (and (eq revision (task-revision task)) (null (get-task-transaction task)))
70
(setq *transaction* transaction)
71
(setf-task-transaction transaction task))
72
(unless (transaction-open-p transaction)
73
(transaction-open transaction :if-does-not-exist :error))
77
(defgeneric ssl::bind-task (task dataset method)
78
(:method ((task task) (dataset string) method)
79
(ssl::bind-task task (repository dataset) method))
81
(:method ((task task) (dataset t) (method symbol))
82
"If provided just a method name, presume the target repository contains also the entailment
83
regime definition and instantiate the regime accordingly."
84
(ssl::bind-task task dataset (make-instance method :task task :dataset dataset)))
86
(:method ((task task) (dataset repository-revision) (method t))
87
"The base method compiles the query and initializes it - which activates its threaded
91
(assert (eq *task* task) ()
92
"Task incompatible: ~s != !s" *task* task))
93
#+(or)(when (null (task-revision task))
94
(setf (slot-value task 'revision) dataset))
96
(if (null *repository*)
97
(setq *repository* dataset)
98
(assert (eq *repository* dataset) ()
99
"Repository incompatible : ~s != ~s" *repository* dataset))
100
(setq *repository* dataset)
101
(setf (task-revision task) (repository-revision dataset))
102
(setf (query-entailment-method task) method)
103
;; ensure there is an active transaction
104
(ssl::begin-transaction task dataset)
105
(add-task-thread task (bt:current-thread))
106
(initialize-task task)
107
;; outside of the local contour
110
(:method :after ((task t) (dataset t) (method t))
111
(generate-accounting-note :abstract)))
114
(defgeneric ssl::commit-transaction (transaction)
115
(:method ((targets list))
116
;; allow null at this level
117
(loop for target in targets do (ssl::commit-transaction target)))
118
(:method ((transaction transaction))
119
(transaction-close transaction :commit)
121
(:method ((dataset string))
122
(ssl::commit-transaction (repository dataset)))
123
(:method ((dataset repository))
124
(let ((transaction (task-dataset-transaction *task* dataset)))
126
(ssl::commit-transaction transaction)
127
(error "No transaction active for specified dataset: ~s" dataset))))
129
(:method :after ((transaction transaction))
130
;; process provenance information to any declared destination
131
(log-debug "commit-transaction: process declared provenance: ~s" *task*)
132
(process-provenance-information *task*)))
135
(defgeneric ssl::compose (steps)
136
(:method ((steps list))
140
(defgeneric ssl::conditional (value consequent alternative)
141
(:method ((value t) consequent alternative)
142
(ssl:if value consequent alternative)))
145
(defgeneric ssl::configure (location)
146
(:method ((location null))
148
(:method ((run-time request-processor))
149
(ssl::configure (processor-configuration-location run-time)))
150
(:method ((location stream))
151
(case (peek-char nil location)
152
(#\( (let* ((*package* (find-package :org.datagraph.spocq.implementation))
153
(configuration (read location)))
154
(load-configuration configuration)))
155
(t (load-configuration location)))
157
;; allow for http and amqp to take the cfg from their headers
161
(defgeneric ssl::constrain (steps &key dataset name source)
162
(:method :before (steps &rest args)
163
(declare (dynamic-extent args))
164
(log-debug "ssl::constrain : (~s . ~s)" steps args))
166
(:method ((steps list) &key (dataset (task-repository *task*))
167
(source (error "notify: source is required"))
169
(with-task (query :user-id name
170
:request-location source
171
:repository (when dataset (repository dataset)))
172
(let ((complete-p nil))
173
(unwind-protect (progn (ssl:run steps)
174
(task-close-transactions *task* :disposition nil)
175
(log-debug "ssl:constrain: ~s: transaction close upon completion" *task*)
178
(task-close-transactions *task* :disposition :abort)
179
(log-debug "ssl:constrain: ~s: transaction abort upon completion" *task*)
180
(log-debug "ssl:constrain complete: :task ~s :transaction ~s :generator ~s"
181
*task* (task-transaction *task*)
182
(task-result-generator *task*))
183
(task-result-generator *task*)))))))
186
(defclass ssl::dataset ()
188
:initarg :location :initform (error "location is requires")
189
:reader ssl::dataset-location)
191
:initarg :operation :initform |acl|:|Read|
192
:reader ssl::dataset-operation)))
194
(defclass ssl::iri-dataset (ssl::dataset)
197
(defgeneric ssl::dataset (location &key operation)
198
(:documentation "Resolve the location to a concrete instance and return the instance.
199
Enforce task agent access authorization restrictions with respect to the specific
200
(location x operation) combination.
201
LOCATION : (or string repository iri) : the intended dataset location
202
:OPERATION : string : defaults to the current task operation
203
VALUES : (or stream dataset repository)
205
The primay case is the <account-name>/<repository-name> combination for local repositories.
206
Additional possibilities are
207
- iri : an internal federation location a remote one
208
- request content designator : for graph store operations
209
- response content designator : the standard for results
210
- remote git repository : for query or data sources
211
- remote http location : for notification
212
Authorization constraints are applied here for the cases which will not include
213
transaction creation, as there are more situations than just repository access.
214
This means repositories are not checked until a transaction is created -
215
perhaps implicitly by begin-transaction.")
217
(:method ((location string) &rest args)
218
"Given a string, apply patterns to distinguish the entity type creation."
219
(declare (dynamic-extent args))
220
(cond ((repository-string-p location)
221
(apply #'ssl::dataset (repository location) args))
222
((url-string-p location)
223
(apply #'ssl::dataset (iri location) args))
225
(error "invalid dataset location: ~s" location))))
227
(:method ((location spocq:iri) &key (operation (task-operation *task*)))
228
;; make a remote location dataset for query retrieval, federation, or result delivery,
229
(let ((local-repository (and (iri-service-repository-id location)
230
(service-repository location :if-does-not-exist nil))))
231
(cond (local-repository
232
(ssl::dataset local-repository :operation operation))
233
((access-authorized-p location (task-agent *task*) operation)
234
(make-instance 'ssl::iri-dataset :location location :operation operation))
236
(spocq.e:task-authorization-error :task *task* :operation operation)))))
238
(:method ((location stream) &key operation)
239
(declare (ignore operation))
242
(:method ((location (eql |http|:|body|)) &key operation)
243
(if (access-authorized-p location (task-agent *task*) operation)
245
((|acl|:|Execute| |acl|:|Read|) (ssl::request-stream))
246
(|acl|:|Write| (ssl::response-stream))
247
(t (error "invalid dataset location: ~s . ~s" location operation)))
248
(spocq.e:task-authorization-error :task *task* :operation operation)))
250
(:method ((repository repository) &key operation)
251
(declare (ignore operation))
254
(defgeneric ssl::decode (location media-type)
255
(:argument-precedence-order media-type location)
256
(:method :before ((source t) (media-type t))
257
(log-debug "ssl::decode : (~s ~s)" source media-type))
259
(:method ((source (eql '|http|:|body|)) (media-type t))
260
(ssl::decode (ssl::dataset source :operation |acl|:|Execute|) media-type))
261
(:method ((source t) (media-type (eql '|http-headers|:|content-type|)))
262
(ssl::decode source (ssl::request-content-type)))
263
(:method ((source t) (media-type mime:application/sparql-query+cascalog))
264
(parse-cascalog source))
266
(:method ((source t) (media-type mime:application/sparql-query+arq-sse))
267
(parse-arq-sse source))
268
(:method ((source t) (media-type mime:application/sparql-query+sse))
269
(parse-sparql-sse source))
271
(:method ((source t) (media-type mime:application/sparql-query))
272
(multiple-value-bind (sse-expression options query-tokens index)
273
(parse-sparql source)
274
(declare (ignore query-tokens index))
275
(apply #'reinitialize-instance *task*
276
:sse-expression sse-expression
277
:dataset-graphs *dataset-graphs* ; as parsed when not asserted by the request
281
(:method ((source t) (media-type mime:application/vnd.dydra.sparql-query-algebra))
282
(multiple-value-bind (operation options)
283
(parse-sparql-sse source)
284
(apply #'reinitialize-instance *task*
289
(:method ((source t) (media-type mime:application/sparql-query+cascalog))
290
(multiple-value-bind (operation options)
291
(parse-cascalog source)
292
(apply #'reinitialize-instance *task*
299
(defgeneric ssl::encode (result-field location media-type &key)
300
(:documentation "Given a solution field, encode its content as a response to
301
the given destination location as per the given media type.
302
The principle use-case is to encode sparql results, but it can also serve to
303
send visualizations or execution plans and/or statistics.
305
It handles also authorization:
306
- streams are accepted always; they are present as the process input and output streams and are
308
- a dataset argument implies that it has authorized access from the current agent and
309
the method can delegate to a stream implementation.
310
- any other argument type is wrapped first in a dataset for that to effect authorization
311
and signal an exception for violations, and then re-iterated with the dataset argument.")
313
(:method ((result solution-generator) (destination stream) (media-type mime:application/vnd.dydra.sparql-query-algebra) &key)
314
"An algebra response encodes the task script/query as per themedia type"
315
(send-response-message :abstract (task-sse-expression *task*) destination media-type)
318
(:method ((result t) (destination stream) (media-type mime:mime-type) &key)
319
"The default message delegates to send-response, which specializes for the media types"
320
(send-response-message (task-operation *task*) result destination media-type)
323
(:method ((solution-field solution-generator) (destination repository) (media-type t) &key)
324
"given a generator and a destination repository, copy the content,
325
!!! without provenance recording"
326
(let* ((dimensions (abstract-field-generator-dimensions solution-field))
327
(arity (length dimensions)))
330
(with-open-repository (destination :read-only-p nil :normal-disposition :commit)
331
(let ((%transaction (transaction-record *transaction*)))
332
(do-solution-field (subject predicate object) solution-field
333
(when (and (/= subject 0) (/= predicate 0) (/= object 0))
334
(rdfcache::insert-statement %transaction
335
rdfcache:*default-context-number*
336
subject predicate object))))))
338
(with-open-repository (destination :read-only-p nil :normal-disposition :commit)
339
(let ((%transaction (transaction-record *transaction*)))
340
(do-solution-field (subject predicate object graph) solution-field
341
(when (and (/= subject 0) (/= predicate 0) (/= object 0) (/= graph 0))
342
(rdfcache::insert-statement %transaction graph subject predicate object))))))
344
(invalid-argument-type ssl::encode solution-field graph-generator))))
347
(defgeneric ssl::end-transaction (transaction)
348
(:documentation "use the first argument on the stack to designate a repository/revision/transaction to close without disposition")
350
(:method ((transaction transaction))
351
(transaction-close transaction nil)
352
(setq *transaction* nil)
356
(defgeneric ssl:for (projection code)
357
(:documentation "Iterate over a solution field. For each solution, extend the
358
initial script environment for all bound dimensions and execute the code sequence
359
with the initial stack and that extended environment.
360
Upon completion, retain the last stack, but restore the environment")
362
(:method ((projection solution-generator) (code list))
363
(sslr:do-field (projection code))))
365
(defgeneric ssl:for-every (projection code)
366
(:documentation "Iterate over a solution field. For each solution, extend the
367
initial script environment for all bound dimensions and execute the code sequence
368
with the initial stack and that extended environment.
369
If any execution does not yield true, terminate the iteration.
370
Yield the final value on the stack
371
Upon completion, but restore the environment")
373
(:method ((projection solution-generator) (code list))
375
(sslr:do-field (projection code)
376
(setf last (sslr:pop))
377
(unless (ssl:true last) (return)))
380
(defgeneric ssl:for-some (projection code)
381
(:documentation "Iterate over a solution field. For each solution, extend the
382
script environment for all _bound_ dimensions and execute the code sequence
383
in the extended environment. If any execution returns true, terminate the iteration
384
and return that value.")
386
(:method ((projection solution-generator) (code list))
387
(sslr:do-field (projection code)
388
(let ((result (sslr:pop)))
389
(when (ssl:true result) (return result))))))
392
(defgeneric ssl::graph-matcher (method dataset)
396
(defun ssl::run-block (body-operator &optional (name |rdf|:|nil|))
397
(declare (dynamic-extent body-operator))
398
(restart-bind ((nil (lambda (&optional (value nil)) (return-from ssl::run-block value))
399
:test-function (lambda (c)
401
(ssl::control-condition
402
(let ((tag (ssl::condition-tag c)))
403
(or (equalp tag name)
404
(and (or (stringp tag) (symbolp tag))
405
(string-equal tag name)))))
408
:report-function (lambda (stream) (format stream "Return from block (~a)." name))))
409
(funcall body-operator)))
411
(defmacro ssl::block (name &body body)
412
(let ((block-body-op (gensym "block")))
413
`(flet ((,block-body-op () ,@body))
414
(declare (dynamic-extent #',block-body-op))
415
(ssl::run-block #',block-body-op ,name))))
418
(defgeneric ssl::loop (steps &key name)
419
(:method ((steps list) &key (name |rdf|:|nil|))
421
(loop (ssl:run steps)))))
423
(defgeneric ssl::notify (steps &key dataset source destination mode)
424
(:documentation "Perform a query with the intent to project the result to a
426
:dataset : the target dataet : default is the current task _repository_,
427
which may resolve to some other revsion than that for the task
428
:source : the source for the query text. for direct http, this could be a
429
mime section, otherwise the body is already consumed for the main query,
430
which means, this must name an autonomous resource
431
:destination : the destination for the result.
432
must be some external location in order to serve as notification.
433
iri are handled with external /opt/dydra/lib/exec/curl
434
default remains, however the response content stream.
436
intends to operate in the context of an activ query/update, from which it
437
adopts various parameters ")
439
(:method :before (steps &rest args)
440
(declare (dynamic-extent args))
441
(log-debug "ssl::notify : (~s . ~s)" steps args))
443
(:method ((location t) &rest args)
444
(declare (dynamic-extent args))
445
(apply #'ssl::notify (load-ssl-graph location) args))
447
(:method ((steps list) &rest args &key
448
((:name *task-name*) *task-name*)
449
((:dataset *repository-id*) *repository-id*)
450
((:revision *revision-id*) *revision-id*)
451
((:source *request-location*) *request-location*)
452
((:source-type *request-content-type*) mime:application/sparql-query)
453
((:destination *response-location*) *response-location*)
454
((:destination-type *response-content-type*) mime:application/sparql-results+json)
455
(mode |urn:dydra|:|synchronous|))
456
"Implement notify the same as a normal query.
457
It differs only in that the default encoding location is not the response content stream,
458
but instead configuration parameter."
462
(let ((*task-parent* *task*)
468
(unwind-protect (ssl::block *task-name*
469
(ssl:run steps) ; these make the task
470
(task-close-transactions *task* :disposition nil)
471
(log-debug "ssl:notify: ~s: transaction close upon completion" *task*)
475
(task-close-transactions *task* :disposition :abort)
476
(log-debug "ssl:query: ~s: transaction abort upon completion" *task*)))
478
(log-debug "ssl:notify no task ~s" args))))
479
(log-debug "ssl:notify complete: :task ~s" *task*)
482
(|urn:dydra|:|synchronous|
484
(|urn:dydra|:|asynchronous|
485
(bt:make-thread #'do-notify
487
:initial-bindings `((*thread-name* . ,*task-name*)
489
(*request-processor* . ',*request-processor*)))
490
;; there is no task to be returned
494
(defgeneric ssl::project (query quad-field method media-type)
495
(:documentation "Project a task as per the given media type.
496
This includes query processing as well as depictions of introspective analysis.")
498
(:method :before (task (field t) (method t) (media-type t))
499
(log-debug "ssl::project : (~s ~s ~s ~s)" task field method media-type))
501
(:method ((query query) (source-quad-field repository) (method t) (media-type mime:application/sparql-results))
502
"Apply a query to a dataset quad field to yield a solution field.
503
Establishes the query's dynamic context to perform compilation if necessary and then
504
sets the threads task instance to the given query."
506
(declare (ignore method))
507
(with-task-environment (:task query)
508
(add-task-thread query (bt:current-thread))
509
;; (re)build the data from graph anew each time in order to creae fresh queues
510
(initialize-task query)
511
;; initiate task processsing thread for the top node
512
(let ((generator (task-result-generator query)))
513
(query-run-in-thread query generator)
514
(log-debug "project-data: task: ~s; generator: ~s" query generator)
515
;; return the field generator
518
(:method ((task task) (source t) (method t) (media-type mime:application/sparql-query))
519
"If the response type is itself a query variation, yield the query and leave
520
the work to the encode operation"
524
(defgeneric ssl::query (steps &key dataset name revision source destination)
525
(:method :before (steps &rest args)
526
(declare (dynamic-extent args))
527
(log-debug "ssl::query : (~s . ~s)" steps args))
529
(:method ((location t) &rest args)
530
(declare (dynamic-extent args))
531
(apply #'ssl::query (load-ssl-graph location) args))
533
(:method ((steps list) &rest args &key
534
((:name *task-name*) *task-name*)
535
((:dataset *repository-id*) *repository-id*)
536
((:revision *revision-id*) *revision-id*)
537
((:source *request-location*) *request-location*)
538
((:source-type *request-content-type*) mime:application/sparql-query)
539
((:destination *response-location*) *response-location*)
540
((:destination-type *response-content-type*) mime:application/sparql-results+json))
541
(let ((*task-parent* *task*)
547
(unwind-protect (ssl::block *task-name*
548
(ssl:run steps) ; these make the task
549
(task-close-transactions *task* :disposition nil)
550
(log-debug "ssl:query: ~s: transaction close upon completion" *task*)
554
(task-close-transactions *task* :disposition :abort)
555
(log-debug "ssl:query: ~s: transaction abort upon completion" *task*))
556
(generate-accounting-note :complete :task *task*)
557
(finalize-task *task*))
559
(log-debug "ssl:query no task ~s" args))))
560
(log-debug "ssl:query complete: :task ~s" *task*)
564
(defgeneric ssl::request (content location request-media-type response-media-type &key method)
565
(:documentation "Given a request location - in particular http, connect, send the request and/or retrieve content")
566
(:argument-precedence-order request-media-type response-media-type content location)
568
(:method (content location (request-media-type string) response-media-type &rest args)
569
(declare (dynamic-extent args))
570
(apply #'ssl::request content location (mime:mime-type request-media-type) response-media-type args))
571
(:method (content location request-media-type (response-media-type string) &rest args)
572
(declare (dynamic-extent args))
573
(apply #'ssl::request content location request-media-type (mime:mime-type response-media-type) args))
575
(:method ((content solution-field) (location spocq:http-url) (request-media-type mime:mime-type) (response-media-type t) &key (method *request-http-method*))
576
"Given an http location, the combinations are
577
:get - response content
578
:put - request content
579
:post - request content and response content given a type"
580
(let ((pathname (make-pathname :directory '(:absolute "tmp")
581
:name (string (gensym (task-id *task*)))))
583
;; buffer the output to a temporary file in order to size it
586
(with-open-file (tmp-stream pathname :direction :output :if-does-not-exist :create :if-exists :error)
587
(ssl::encode content tmp-stream request-media-type))
588
(with-http-request-stream (request-http-stream response-http-stream location
589
:content-type request-media-type
590
:content-pathname pathname
591
:accept response-media-type
593
(if (mime:mime-type-p response-media-type)
594
(setf result (ssl::decode response-http-stream response-media-type))
595
(loop for byte = (read-char response-http-stream nil nil)
597
do (write-char byte)))))
598
(when (probe-file pathname) (delete-file pathname)))
601
(:method ((content solution-field) (location spocq:mailto-url) (request-media-type mime:mime-type) (response-media-type t) &key method)
602
"Given a mailto location, encode the content as mail"
603
(declare (ignore method))
604
(let* ((address (subseq (spocq:iri-lexical-form location) 7))
605
(from (format nil "spocq@~a" (site-name)))
606
(process (or (run-program "/usr/sbin/sendmail" `("-f" ,from ,address)
610
(error "ssl:request: run-program-failed.")))
611
(mail-stream (run-program-input process)))
614
(format mail-stream "From: ~a~c~cSubject: ~a~c~c~c~c"
615
from #\return #\linefeed (task-id *task*) #\return #\linefeed #\return #\linefeed )
616
(ssl::encode content mail-stream request-media-type)
617
(fresh-line mail-stream)
618
(force-output mail-stream)
620
(run-program-wait process)
622
(run-program-close process))))
624
(:method ((content (eql |rdf|:|nil|)) (location spocq:url) (request-media-type t) (response-media-type mime:mime-type) &key (method :get))
625
"Given an http location, and no content the request must be :GET
626
make the request, decode and return the response"
627
(with-http-request-stream (request-http-stream response-http-stream location
628
:accept response-media-type
630
(declare (ignore request-http-stream))
631
(ssl::decode response-http-stream response-media-type)))
633
(:method ((result-field t) (dataset ssl::iri-dataset) request-media-type response-media-type &rest args)
634
(apply #'ssl::request result-field (ssl::dataset-location dataset) request-media-type response-media-type
640
(defgeneric ssl::return (&key name value)
641
(:documentation "Returned from the named loop, by default rdf:nil.")
642
(:method (&key (name |rdf|:|nil|) (value nil v-s))
643
(let ((restart (first (compute-restarts (ssl::control-condition name)))))
646
(invoke-restart restart value)
647
(invoke-restart restart))
648
(error "Attempt to return from an unknown loop: (~a)." name)))))
651
(defgeneric ssl::update (steps &key dataset name source destination)
652
(:method :before (steps &rest args)
653
(declare (dynamic-extent args))
654
(log-debug "ssl::notify : (~s . ~s)" steps args))
656
(:method ((location t) &rest args)
657
(declare (dynamic-extent args))
658
(apply #'ssl::update (load-ssl-graph location) args))
660
(:method ((steps list) &rest args &key
661
((:name *task-name*) *task-name*)
662
((:dataset *repository-id*) *repository-id*)
663
((:revision *revision-id*) *revision-id*)
664
((:source *request-location*) *request-location*)
665
((:source-type *request-content-type*) mime:application/sparql-query)
666
((:destination *response-location*) *response-location*)
667
((:destination-type *response-content-type*) mime:application/sparql-results+json))
668
(let ((*task-parent* *task*)
674
(unwind-protect (ssl::block *task-name*
675
(ssl:run steps) ; these make the task
676
(task-close-transactions *task* :disposition nil)
677
(log-debug "ssl:update: ~s: transaction close upon completion" *task*)
681
(task-close-transactions *task* :disposition :abort)
682
(log-debug "ssl:update: ~s: transaction abort upon completion" *task*)))
684
(log-warn "ssl:update no task ~s" args))))
685
(log-debug "ssl:update complete: :task ~s" *task*)