pho 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README ADDED
@@ -0,0 +1,56 @@
1
+ The Pho ruby module provides a lightweight Ruby client library for interacting with the Talis
2
+ Platform API (http://n2.talis.com/wiki/Platform_API).
3
+
4
+ == Author
5
+
6
+ Leigh Dodds (leigh.dodds@talis.com)
7
+
8
+ == Download
9
+
10
+ The latest version of this library can be downloaded from:
11
+
12
+ http://pho.rubyforge.net
13
+
14
+ == Usage
15
+
16
+ To use Pho you can:
17
+
18
+ require 'pho'
19
+
20
+ And then create an instance of the appropriate class, e.g Store:
21
+
22
+ store = Pho::Store.new("http://api.talis.com/testing", "user", "pass")
23
+ response = store.describe("http://www.example.org")
24
+
25
+ For more detailed examples consult the documentation for the Store class
26
+
27
+ == Control over HTTP interactions
28
+
29
+ Pho is dependent on the HTTPClient module and all HTTP interactions are delegated to
30
+ an instance of the HTTPClient class. In circumstances where greater control over the
31
+ HTTP interaction is required, e.g. to configure proxy servers, etc, an existing instance of
32
+ this class can be provided, e.g:
33
+
34
+ client = HTTPClient.new
35
+ => configure client as required
36
+ store = Pho::Store.new("http://api.talis.com/testing", "user", "pass", client)
37
+ => pass instance of client as parameter
38
+ response = store.describe("http://www.example.org")
39
+
40
+ == License
41
+
42
+ Copyright 2009 Leigh Dodds
43
+
44
+ Licensed under the Apache License, Version 2.0 (the "License");
45
+ you may not use this file except in compliance with the License.
46
+
47
+ You may obtain a copy of the License at
48
+
49
+ http://www.apache.org/licenses/LICENSE-2.0
50
+
51
+ Unless required by applicable law or agreed to in writing,
52
+ software distributed under the License is distributed on an "AS IS" BASIS,
53
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
54
+
55
+ See the License for the specific language governing permissions and limitations
56
+ under the License.
@@ -0,0 +1,63 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/testtask'
5
+ require 'rake/clean'
6
+
7
+ NAME = "pho"
8
+ VER = "0.0.1"
9
+
10
+ RDOC_OPTS = ['--quiet', '--title', 'Pho (Talis Platform Client) Reference', '--main', 'README']
11
+
12
+ PKG_FILES = %w( README Rakefile ) +
13
+ Dir.glob("{bin,doc,tests,lib}/**/*")
14
+
15
+ CLEAN.include ['*.gem', 'pkg']
16
+ SPEC =
17
+ Gem::Specification.new do |s|
18
+ s.name = NAME
19
+ s.version = VER
20
+ s.platform = Gem::Platform::RUBY
21
+ s.has_rdoc = true
22
+ s.extra_rdoc_files = ["README"]
23
+ s.rdoc_options = RDOC_OPTS
24
+ s.summary = "Ruby client for the Talis Platform"
25
+ s.description = s.summary
26
+ s.author = "Leigh Dodds"
27
+ s.email = 'leigh.dodds@talis.com'
28
+ s.homepage = 'http://pho.rubyforge.net'
29
+ s.rubyforge_project = 'pho'
30
+ s.files = PKG_FILES
31
+ s.require_path = "lib"
32
+ s.bindir = "bin"
33
+ s.test_file = "tests/ts_pho.rb"
34
+ s.add_dependency("httpclient", ">= 2.1.3.1")
35
+ s.add_dependency("json", ">= 1.1.3")
36
+ s.add_dependency("mocha", ">= 0.9.5")
37
+ end
38
+
39
+ Rake::GemPackageTask.new(SPEC) do |pkg|
40
+ pkg.need_tar = true
41
+ end
42
+
43
+ Rake::RDocTask.new do |rdoc|
44
+ rdoc.rdoc_dir = 'doc/rdoc'
45
+ rdoc.options += RDOC_OPTS
46
+ rdoc.main = "README"
47
+ rdoc.rdoc_files.add ["README"]
48
+ end
49
+
50
+
51
+ Rake::TestTask.new do |test|
52
+ test.test_files = FileList['tests/tc_*.rb']
53
+ end
54
+
55
+ task :install do
56
+ sh %{rake package}
57
+ sh %{sudo gem install pkg/#{NAME}-#{VER}}
58
+ end
59
+
60
+
61
+ task :uninstall => [:clean] do
62
+ sh %{sudo gem uninstall #{NAME}}
63
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'httpclient'
3
+ require 'json'
4
+
5
+ require 'pho/etags'
6
+ require 'pho/store'
7
+ require 'pho/rdf_collection'
8
+
9
+ module Pho
10
+
11
+ ACCEPT_RDF = {"Accept" => "application/rdf+xml"}.freeze
12
+ ACCEPT_JSON = { "Accept" => "application/json" }.freeze
13
+
14
+ RDF_XML = {"Content-Type"=>"application/rdf+xml"}.freeze
15
+
16
+ JOB_RESET = "http://schemas.talis.com/2006/bigfoot/configuration#ResetDataJob".freeze
17
+ JOB_SNAPSHOT = "http://schemas.talis.com/2006/bigfoot/configuration#SnapshotJob".freeze
18
+ JOB_REINDEX = "http://schemas.talis.com/2006/bigfoot/configuration#ReindexJob".freeze
19
+
20
+
21
+ end
@@ -0,0 +1,54 @@
1
+ require 'yaml'
2
+
3
+ module Pho
4
+
5
+ #Simple mechanism for managing etags
6
+ class Etags
7
+
8
+ attr_reader :file, :saved
9
+
10
+ def initialize(file = nil)
11
+ @file = file
12
+ @saved = true
13
+ @tags = Hash.new
14
+ if @file != nil
15
+ @tags = YAML::load(@file)[0]
16
+ end
17
+ end
18
+
19
+ def save(other=nil)
20
+
21
+ if (other != nil)
22
+ other.write( @tags.to_yaml() )
23
+ return
24
+ else
25
+ if (!saved && @file != nil )
26
+ @file.write( @tags.to_yaml() )
27
+ @file.close
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ def add(uri, tag)
34
+ if (uri != nil && tag != nil)
35
+ @tags[uri] = tag
36
+ @saved = false
37
+ end
38
+ end
39
+
40
+ def add_from_response(uri, response)
41
+ add(uri, response.header["ETag"][0])
42
+ end
43
+
44
+ def get(uri)
45
+ return @tags[uri]
46
+ end
47
+
48
+ def has_tag?(uri)
49
+ return @tags.has_key?(uri)
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,107 @@
1
+ module Pho
2
+
3
+ attr_reader :dir
4
+ attr_reader :store
5
+
6
+ # Provides a simple mechanism for managing a directory of RDF/XML documents
7
+ # and uploading them to platform store.
8
+ #
9
+ # Allows a collection to be mirrored into the platform
10
+ class RDFCollection
11
+
12
+ RDF = "rdf".freeze
13
+ OK = "ok".freeze
14
+ FAIL = "fail".freeze
15
+
16
+ def initialize(store, dir, rdf_suffix=RDF, ok_suffix=OK, fail_suffix=FAIL, sleep=1)
17
+ @store = store
18
+ @dir = dir
19
+ @sleep = sleep
20
+ @rdf_suffix = rdf_suffix
21
+ @ok_suffix = ok_suffix
22
+ @fail_suffix = fail_suffix
23
+ end
24
+
25
+ #Store all files that match the file name in directory
26
+ def store()
27
+ files_to_store = new_files()
28
+ files_to_store.each do |filename|
29
+ file = File.new(filename)
30
+ response = @store.store_file(file)
31
+ end
32
+ end
33
+
34
+ #Retry anything known to have failed
35
+ def retry_failures()
36
+ #TODO
37
+ end
38
+
39
+ #Reset the directory to clear out any previous statuses
40
+ #Store can also be reset at the same time: use with care!
41
+ def reset(reset_store=false)
42
+ Dir.glob( File.join(@dir, "*.#{@fail_suffix}") ).each do |file|
43
+ File.delete(file)
44
+ end
45
+ Dir.glob( File.join(@dir, "*.#{@ok_suffix}") ).each do |file|
46
+ File.delete(file)
47
+ end
48
+ end
49
+
50
+ #List files being managed
51
+ def list()
52
+ return Dir.glob( File.join(@dir, "*.#{@rdf_suffix}") )
53
+ end
54
+
55
+ #List failures
56
+ def failures()
57
+ fails = Array.new
58
+ Dir.glob( File.join(@dir, "*.#{@fail_suffix}") ).each do |file|
59
+ fails << file.gsub(/\.#{@fail_suffix}/, ".#{@rdf_suffix}")
60
+ end
61
+ return fails
62
+ end
63
+
64
+ #List successes
65
+ def successes()
66
+ successes = Array.new
67
+ Dir.glob( File.join(@dir, "*.#{@ok_suffix}") ).each do |file|
68
+ successes << file.gsub(/\.#{@ok_suffix}/, ".#{@rdf_suffix}")
69
+ end
70
+ return successes
71
+ end
72
+
73
+ #List any new files in the directory
74
+ def new_files()
75
+ newfiles = Array.new
76
+ Dir.glob( File.join(@dir, "*.#{@rdf_suffix}") ) do |file|
77
+ ok_file = get_ok_file_for(file)
78
+ fail_file = get_fail_file_for(file)
79
+ if !( File.exists?(ok_file) or File.exists?(fail_file) )
80
+ newfiles << file
81
+ end
82
+ end
83
+ return newfiles
84
+ end
85
+
86
+ #Summarize the state of the collection to the provied IO object
87
+ #Creates a simple report
88
+ def summary()
89
+ failures = failures()
90
+ successes = successes()
91
+ newfiles = new_files()
92
+ total = failures.size + successes.size + newfiles.size
93
+ summary = "#{@dir} contains #{total} files: #{successes.size} stored, #{failures.size} failed, #{newfiles.size} new"
94
+ return summary
95
+ end
96
+
97
+ def get_fail_file_for(filename)
98
+ return filename.gsub(/\.#{@rdf_suffix}/, ".#{@fail_suffix}")
99
+ end
100
+
101
+ def get_ok_file_for(filename)
102
+ return filename.gsub(/\.#{@rdf_suffix}/, ".#{@ok_suffix}")
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,389 @@
1
+ module Pho
2
+
3
+ #TODO:
4
+ #
5
+ # Changesets
6
+ # Multisparql
7
+ #
8
+ # Conditional deletions
9
+ # If-Modified-Since support
10
+ # Robustness in uri fetching
11
+ #
12
+ # RDOC
13
+
14
+ # The Store class acts as a lightweight client interface to the Talis Platform API
15
+ # (http://n2.talis.com/wiki/Platform_API). The class provides methods for interacting
16
+ # with each of the core platform services, e.g. retrieving and storing RDF, performing
17
+ # searches, SPARQL queries, etc.
18
+ #
19
+ # == Usage
20
+ #
21
+ # store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass")
22
+ # store.store_file( File.new("/tmp/example.rdf") )
23
+ # store.store_url( "http://www.example.org/example.rdf" )
24
+ # store.describe( "http://www.example.org/thing" )
25
+ # store.reset
26
+ #
27
+ # == Examples
28
+ #
29
+ class Store
30
+
31
+ #Retrieve the HTTPClient instance being used by this object
32
+ attr_reader :client
33
+ #Retrieve the admin username configured in this instance
34
+ attr_reader :username
35
+ #Retrieve the base uri of this store
36
+ attr_reader :storeuri
37
+
38
+ # Create an instance of the store class
39
+ #
40
+ # storeuri:: base uri for the Platform store to be accessed
41
+ # username:: admin username, may be nil
42
+ # password:: admin password, may be nil
43
+ # client:: an instance of HTTPClient
44
+ def initialize(storeuri, username=nil, password=nil, client = HTTPClient.new() )
45
+ @storeuri = storeuri.chomp("/")
46
+ @username = username
47
+ @password = password
48
+ @client = client
49
+ set_credentials(username, password) if username or password
50
+ end
51
+
52
+ # Set credentials that this store will use when carrying out authorization
53
+ #
54
+ # username:: admin username
55
+ # password:: admin password
56
+ def set_credentials(username, password)
57
+ @client.set_auth(@storeuri, username, password)
58
+ end
59
+
60
+ # Build a request uri, by concatenating it with the base uri of the store
61
+ # uri:: relative URI to store service, e.g. "/service/sparql"
62
+ def build_uri(uri)
63
+ if (uri.start_with?(@storeuri))
64
+ return uri
65
+ end
66
+ if uri.start_with?("/")
67
+ return @storeuri + uri
68
+ else
69
+ return @storeuri + "/" + uri
70
+ end
71
+ end
72
+
73
+ #############
74
+ # METABOX
75
+ #############
76
+
77
+ # Store some RDF in the Metabox associated with this store
78
+ # data:: a String containing the data to store
79
+ def store_data(data)
80
+ u = build_uri("/meta")
81
+ response = @client.post(u, data, RDF_XML )
82
+ return response
83
+ end
84
+
85
+ # Store the contents of a File (or any IO stream) in the Metabox associated with this store
86
+ # The client does not support streaming submissions of data, so the stream will be fully read before data is submitted to the platform
87
+ # file:: an IO object
88
+ def store_file(file)
89
+ data = file.read()
90
+ file.close()
91
+ return store_data(data)
92
+ end
93
+
94
+ # Retrieve RDF data from the specified URL and store it in the Store Metabox
95
+ #
96
+ # An Accept header of "application/rdf+xml" will be sent in the request to support retrieval of RDF from
97
+ # URLs that support Content Negotiation.
98
+ #
99
+ # u:: the url of the data
100
+ # parameters:: a Hash of url parameters to pass when requesting data from the specified URL
101
+ def store_url(u, parameters=nil)
102
+
103
+ headers = ACCEPT_RDF.clone()
104
+ dataresp = @client.get(u, parameters, headers )
105
+
106
+ #TODO make this more robust
107
+ if dataresp.status != 200
108
+ throw
109
+ end
110
+
111
+ return store_data(dataresp.content)
112
+
113
+ end
114
+
115
+ # Retrieve an RDF description of a specific URI. The default behaviour will be to retrieve an RDF/XML document, but other formats can be
116
+ # requested, as supported by the Talis Platform. E.g. application/json
117
+ #
118
+ # uri:: the URI of the resource to describe
119
+ # format:: the preferred response format
120
+ # etags:: an instance of the Pho::Etags class to support conditional GETs
121
+ # if_match:: specify true to retrieve data only if the version matches a known ETag, false to perform a Conditional GET
122
+ #
123
+ # Note that this method is different from sparql_describe in that it is intended to be used to generate a description of
124
+ # a single URI, using an separated service exposed by the Platform. This service is optimised for retrieval of descriptions for
125
+ # single resources and supports HTTP caching and conditional retrieval. The sparql_describe method should be used to submit
126
+ # more complex DESCRIBE queries to the Platform, e.g. to generate descriptions of resources matching a particular graph pattern.
127
+ def describe(uri, format="application/rdf+xml", etags=nil, if_match=false)
128
+ u = self.build_uri("/meta")
129
+ headers = {"Accept" => format}
130
+ headers = configure_headers_for_conditional_get("#{u}?about=#{uri}", headers, etags, if_match)
131
+ response = @client.get(u, {"about" => uri}, headers )
132
+ record_etags("#{u}?about=#{uri}", etags, response)
133
+ return response
134
+ end
135
+
136
+ #############
137
+ # SERVICES
138
+ #############
139
+
140
+ #Perform a SPARQL DESCRIBE query.
141
+ #
142
+ # query:: the SPARQL query
143
+ # format:: the preferred response format
144
+ def sparql_describe(query, format="application/rdf+xml")
145
+ return sparql(query, format)
146
+ end
147
+
148
+ #Perform a SPARQL CONSTRUCT query.
149
+ #
150
+ # query:: the SPARQL query
151
+ # format:: the preferred response format
152
+ def sparql_construct(query, format="application/rdf+xml")
153
+ return sparql(query, format)
154
+ end
155
+
156
+ #Perform a SPARQL ASK query.
157
+ #
158
+ # query:: the SPARQL query
159
+ # format:: the preferred response format
160
+ def sparql_ask(query, format="application/sparql-results+xml")
161
+ return sparql(query, format)
162
+ end
163
+
164
+ #Perform a SPARQL SELECT query.
165
+ #
166
+ # query:: the SPARQL query
167
+ # format:: the preferred response format
168
+ def sparql_select(query, format="application/sparql-results+xml")
169
+ return sparql(query, format)
170
+ end
171
+
172
+ #Perform a SPARQL query
173
+ #
174
+ # query:: the SPARQL query
175
+ # format:: the preferred response format
176
+ def sparql(query, format)
177
+ u = self.build_uri("/services/sparql")
178
+ params = {}
179
+ params["query"] = query
180
+ headers = {}
181
+ headers["Accept"] = format
182
+ response = @client.get(u, params, headers)
183
+ end
184
+
185
+ # Search the Metabox indexes.
186
+ #
187
+ # query:: the query to perform. See XXXX for query syntax
188
+ # params:: additional query parameters (see below)
189
+ #
190
+ # The _params_ hash can contain the following values:
191
+ # * *max*: The maximum number of results to return (default is 10)
192
+ # * *offset*: Offset into the query results (for paging; default is 0)
193
+ # * *sort*: ordered list of fields to be used when applying sorting
194
+ # * *xsl-uri*: URL of an XSLT transform to be applied to the results, transforming the default RSS 1.0 results format into an alternative representation
195
+ # * *content-type*: when applying an XSLT transform, the content type to use when returning the results
196
+ #
197
+ # Any additional entries in the _params_ hash will be passed through to the Platform.
198
+ # These parameters will only be used when an XSLT transformation is being applied, in which case they
199
+ # will be provided as parameters to the stylesheet.
200
+ def search(query, params=nil)
201
+ u = self.build_uri("/items")
202
+ search_params = get_search_params(u, query, params)
203
+ response = @client.get(u, search_params, nil)
204
+ return response
205
+
206
+ end
207
+
208
+ # Perform a facetted search against the Metabox indexes.
209
+ #
210
+ # query:: the query to perform. See XXXX for query syntax
211
+ # facets:: an ordered list of facets to be used
212
+ # params:: additional query parameters (see below)
213
+ #
214
+ # The _params_ hash can contain the following values:
215
+ # * *top*: the maximum number of results to return for each facet
216
+ # * *output*: the preferred response format, can be html or xml (the default)
217
+ def facet(query, facets, params=nil)
218
+ if facets == nil or facets.empty?
219
+ #todo
220
+ throw
221
+ end
222
+ u = self.build_uri("/services/facet")
223
+ search_params = get_search_params(u, query, params)
224
+ search_params["fields"] = facets.join(",")
225
+ response = @client.get(u, search_params, nil)
226
+ return response
227
+ end
228
+
229
+ def get_search_params(u, query, params)
230
+ if params != nil
231
+ search_params = params.clone()
232
+ else
233
+ search_params = Hash.new
234
+ end
235
+ search_params["query"] = query
236
+ return search_params
237
+ end
238
+
239
+ # Augment an RSS feed that can be retrieved from the specified URL, against data in this store
240
+ #
241
+ # uri:: the URL for the RSS 1.0 feed
242
+ def augment_uri(uri)
243
+ u = self.build_uri("/services/augment")
244
+ response = @client.get(u, {"data-uri" => uri}, nil)
245
+ return response
246
+ end
247
+
248
+ # Augment an RSS feed against data int this store by POSTing it to the Platform
249
+ #
250
+ # data:: a String containing the RSS feed
251
+ def augment(data)
252
+ u = self.build_uri("/services/augment")
253
+ response = @client.post(u, data, nil)
254
+ return response
255
+ end
256
+
257
+ #Added appropriate http header for conditional get requests
258
+ def configure_headers_for_conditional_get(u, headers, etags, if_match)
259
+ if etags != nil && etags.has_tag?(u)
260
+ if if_match
261
+ headers["If-Match"] = etags.get(u)
262
+ else
263
+ headers["If-None-Match"] = etags.get(u)
264
+ end
265
+ end
266
+ return headers
267
+ end
268
+
269
+ def record_etags(u, etags, response)
270
+ if (etags != nil && response.status = 200)
271
+ etags.add_from_response(u, response)
272
+ end
273
+ end
274
+
275
+
276
+ #############
277
+ # CONTENTBOX
278
+ #############
279
+
280
+ # Store an item in the Contentbox for this store
281
+ #
282
+ # f:: a File or other IO object from which data will be read
283
+ # mimetype:: the mimetype of the object to record in the Platform
284
+ # uri:: the URI at which to store the item (relative to base uri for the store). If nil, then a URI will be assigned by the Platform
285
+ #
286
+ # When a _uri_ is not specified, then the Platform will return a 201 Created response with a Location header containing the URI of the
287
+ # newly stored item. If a URI is specified then a successful request will result in a 200 OK response.
288
+ def upload_item(f, mimetype, uri=nil)
289
+ data = f.read()
290
+ f.close()
291
+ headers = {"Content-Type" => mimetype}
292
+ if uri == nil
293
+ u = self.build_uri("/items")
294
+ response = @client.post(u, data, headers)
295
+ else
296
+ if !uri.start_with?(@storeuri)
297
+ uri = build_uri(uri)
298
+ end
299
+ response = @client.put(uri, data, headers)
300
+ end
301
+ return response
302
+ end
303
+
304
+ # Delete an item from the Contentbox in this Store
305
+ # uri:: the URL of the item, can be relative
306
+ # TODO: conditional deletes
307
+ def delete_item(uri)
308
+ if !uri.start_with?(@storeuri)
309
+ uri = build_uri(uri)
310
+ end
311
+ return @client.delete(uri)
312
+ end
313
+
314
+ # Get an item from the Contebtbox.
315
+ # uri:: the URL of the item, can be relative.
316
+ #
317
+ # If the provided URL of the item is not in the Contentbox, then the response will be a redirect to the
318
+ # RDF description of this item, as available from the Metabox.
319
+ #
320
+ # TODO: document etags, redirects
321
+ def get_item(uri, etags=nil, if_match=false)
322
+ u = self.build_uri(uri)
323
+ headers = Hash.new
324
+ headers = configure_headers_for_conditional_get("#{u}", headers, etags, if_match)
325
+ response = @client.get(u, nil, headers)
326
+ record_etags("#{u}", etags, response)
327
+ return response
328
+ end
329
+
330
+ #############
331
+ # JOBS
332
+ #############
333
+
334
+ # Construct an RDF/XML document containing a job request for submitting to the Platform.
335
+ #
336
+ # t:: a Time object, specifying the time at which the request should be carried out
337
+ # joburi:: the URI for the JobType that should be created
338
+ # label:: a label for this job.
339
+ def build_job_request(t, joburi, label)
340
+ time = t.strftime("%Y-%m-%dT%H:%M:%SZ")
341
+ data = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" "
342
+ data << " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\" "
343
+ data << " xmlns:bf=\"http://schemas.talis.com/2006/bigfoot/configuration#\"> "
344
+ data << " <bf:JobRequest>"
345
+ data << " <rdfs:label>#{label}</rdfs:label>"
346
+ data << " <bf:jobType rdf:resource=\"#{joburi}\"/>"
347
+ data << " <bf:startTime>#{time}</bf:startTime>"
348
+ data << " </bf:JobRequest>"
349
+ data << "</rdf:RDF>"
350
+ return data
351
+ end
352
+
353
+ def reset(t=Time.now)
354
+ return submit_job(JOB_RESET, "Reset my store", t)
355
+ end
356
+
357
+ def reindex(t=Time.now)
358
+ return submit_job(JOB_REINDEX, "Reindex my store", t)
359
+ end
360
+
361
+ def snapshot(t=Time.now)
362
+ return submit_job(JOB_SNAPSHOT, "Snapshot my store", t)
363
+ end
364
+
365
+ def submit_job(joburi, label, t=Time.now)
366
+ u = build_uri("/jobs")
367
+ data = build_job_request(t, joburi, label)
368
+ response = @client.post(u, data, RDF_XML )
369
+ return response
370
+ end
371
+
372
+ #############
373
+ # ADMIN
374
+ #############
375
+
376
+ def status()
377
+ u = build_uri("/config/access-status")
378
+ response = @client.get_content(u, nil, ACCEPT_JSON )
379
+ json = JSON.parse( response )
380
+ state = Hash.new
381
+ state["retryInterval"] = json[u.to_s]["http:\/\/schemas.talis.com\/2006\/bigfoot\/configuration#retryInterval"][0]["value"]
382
+ state["statusMessage"] = json[u.to_s]["http:\/\/schemas.talis.com\/2006\/bigfoot\/configuration#statusMessage"][0]["value"]
383
+ state["accessMode"] = json[u.to_s]["http:\/\/schemas.talis.com\/2006\/bigfoot\/configuration#accessMode"][0]["value"]
384
+ return state
385
+ end
386
+
387
+ end
388
+
389
+ end