myexperiment-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[myexperiment-hackers] [3193] branches/wf4ever/vendor/plugins: added ros


From: noreply
Subject: [myexperiment-hackers] [3193] branches/wf4ever/vendor/plugins: added rosrs (04eba3bc) as a temporary plugin with modifications
Date: Fri, 23 Nov 2012 11:21:16 +0000 (UTC)

Revision
3193
Author
dgc
Date
2012-11-23 11:21:15 +0000 (Fri, 23 Nov 2012)

Log Message

added rosrs (04eba3bc) as a temporary plugin with modifications

Added Paths

Diff

Added: branches/wf4ever/vendor/plugins/rosrs/.gitignore (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/.gitignore	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/.gitignore	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,24 @@
+*.gem
+*.rbc
+.bundle
+.config
+coverage
+InstalledFiles
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+Gemfile.lock
+
+# YARD artifacts
+.yardoc
+_yardoc
+doc/
+
+# Other arfifacts
+*~
+*.log
+

Added: branches/wf4ever/vendor/plugins/rosrs/.rvmrc (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/.rvmrc	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/.rvmrc	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1 @@
+rvm --create use address@hidden

Added: branches/wf4ever/vendor/plugins/rosrs/Gemfile (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/Gemfile	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/Gemfile	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem "json"
+gem "rdf"
+gem "rdf-raptor"
+
+# Add dependencies to develop your gem here.
+# Include everything needed to run rake, tests, features, etc.
+group :development do
+  gem "rdoc", "~> 3.12"
+  gem "bundler", "~> 1.2.1"
+  gem "jeweler", "~> 1.8.4"
+end

Added: branches/wf4ever/vendor/plugins/rosrs/LICENSE.txt (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/LICENSE.txt	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/LICENSE.txt	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,20 @@
+Copyright (c) 2012 Finn Bacall
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: branches/wf4ever/vendor/plugins/rosrs/README.md (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/README.md	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/README.md	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,181 @@
+ROSRSClient
+=================
+
+Partial port of Python ROSRS_Session code to Ruby.
+
+[This project [8]][ref8] is intended to provide a Ruby-callable API for [myExperiment [9]][ref9] to access [Research Objects [1]][ref1], [[2]][ref2] stored in RODL, using the [ROSRS API [3]][ref3].  The functions provided closely follow the ROSRS API specification.  The code is based on an implementation in Python used by the RO_Manager utility; a full implementat ROSRS test suite can be found in the [GitHub `wf4ever/ro-manager` project [7]][ref7].
+
+[ref1]: http://www.wf4ever-project.org/wiki/pages/viewpage.action?pageId=2065079 "What is an RO?"
+
+[ref2]: http://wf4ever.github.com/ro/ "Wf4Ever Research Object Model"
+
+[ref3]: http://www.wf4ever-project.org/wiki/display/docs/RO+SRS+interface+6 "ROSRS interface (v6)"
+
+[ref7]: https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/ROSRS_Session.py "Python ROSRS_Session in RO Manager.  See also test suite: https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/test/TestROSRS_Session.py"
+ 
+[ref8]: https://github.com/gklyne/ruby-http-session "ruby-http-session project, or successor"
+
+[ref9]: http://www.myexperiment.org/ "De Roure, D., Goble, C. and Stevens, R. (2009) The Design and Realisation of the myExperiment Virtual Research Environment for Social Sharing of Workflows. Future Generation Computer Systems 25, pp. 561-567. doi:10.1016/j.future.2008.06.010"
+
+
+## Contents
+
+* Contents
+* Package structure
+* API calling conventions
+* A simple example
+* Development setup
+* URIs
+* Further work
+* References
+
+
+## Package structure
+
+Key functions are currently contained in four files:
+
+* `lib/wf4ever/rosrs_session.rb`
+* `lib/wf4ever/rdf_graph.rb`
+* `lib/wf4ever/namespaces.rb`
+* `lib/wf4ever/folders.rb`
+* `test/test_rosrs_session`
+
+The main functions provided by this package are in `rosrs_session`.  This module provides a class whose instances manage a session with a specified ROSRS service endpoint.  A service URI is provided when an instance is created, and is used as a base URI for accessing ROs and other resources using relative URI references.  Any attempt to access a resource on a different host or post is rejected.
+
+`rdf_graph` implements a simplified interface to the [Ruby RDF library [4]][ref4], handling parsing of RDF from strings, serialization to strings and simplified search and access to individual triples.  Most of the functions provided are quite trivial; the module is intended to provide (a) a distillation of knowledge about how to perform desired functions using the RDF and associated libraries, and (b) a shim layer for adapting between different conventions used by the RDF libraries and the `rosrs_session` library.  The [Raptor library [5]][ref5] and its [Ruby RDF interface[6]][ref6] are used for RDF/XML parsing and serialization.
+
+[ref4]: http://rdf.rubyforge.org/ "RDF.rb: Linked Data for Ruby"
+
+[ref5]: http://librdf.org/raptor/ "Raptor RDF Syntax Library"
+
+[ref6]: http://rdf.rubyforge.org/raptor/ "Raptor RDF Parser Plugin for RDF.rb"
+
+`namespaces` provides definitions of URIs for namespaces and namespace terms used in RDF graphs.  These are in similar form to the namespaces provided by the RDF library.
+
+`folders` contains objects to represent and traverse RO's folder structure.
+
+`test_rosrs_session` is a test suite for all the above.  It serves to provide regression testing for implemented functions, and also to provide examples of how the various ROSRS API functions provided can be accessed.
+
+
+## API calling conventions
+
+Many API functions have a small number of mandatory parameters which are provided as normal positional parameters, and a (possibly larger) number of optional keyword parameters that are provided as a Ruby hash.  The Ruby calling convention of collecting multiple `key => value` parameter expressions into a single has is used.
+
+Return values are generally in the form of an array, which can be used with parallel assignment for easy access to the return values.
+
+Example:
+
+    code, reason, headers, body = rosrs.do_request("POST", rouri,
+        :body   => data
+        :ctype  => "text/plain"
+        :accept => "application/rdf+xml"
+        :headers    => reqheaders)
+
+
+## A simple example
+
+Here is a flavour of how the `rosrs_session` module may be used:
+
+    # Create an ROSRS session
+    rosrs = ROSRSSession.new(
+        "http://sandbox.wf4ever-project.org/rodl/ROs/", 
+        "47d5423c-b507-4e1c-8")
+
+    # Create a new RO
+    code, reason, rouri, manifest = @rosrs.create_research_object("Test-RO-name",
+        "Test RO for ROSRSSession", "TestROSRS_Session.py", "2012-09-28")
+    if code != 201
+        raise "Failed to create new RO: "+reason
+    end
+
+    # Aggregate a resource into the new RO
+    res_body = %q(
+        New resource body
+        )
+    options = { :body => res_body, :ctype => "text/plain" }
+
+    # Create and aggregate "internal" resource in new RO
+    code, reason, proxyuri, resourceuri = rosrs.aggregate_internal_resource(
+        rouri, "data/test_resource",
+        :body => res_body,
+        :ctype => "text/plain")
+    if code != 201
+        raise "Failed to create new resource: "+reason
+
+    # Create a new folder
+    folder_contents = [{:name => 'test_data.txt', :uri => 'http://www.example.com/ro/file1.txt'},
+                       {:uri => 'http://www.myexperiment.org/workflows/7'}]
+    folder_uri = rosrs.create_folder(rouri, "Input Data", folder_contents).uri
+
+    # Examine a folder
+    folder = rosrs.get_folder(folder_uri)
+    puts folder.name
+    puts folder.contents.inspect
+
+
+
+
+    # When finished, close session
+    rosrs.close
+
+
+## Development setup
+
+Development has been performed using Ruby 1.8.7 on Ubuntu Linux 10.04 and 12.04.  The code uses `rubygems`, `json`, `rdf` and `rdf-raptor` libraries beyond the standard Ruby libraries.
+
+The `rdf-raptor` Ruby library uses the Ubuntu `raptor-util` and `libraptor-dev` packages.  NOTE: the Ruby RDF documentation does not mention `libraptor-dev`, but I found that without this the RDF libraries would not work for parsing and serializing RDF/XML.
+
+Once the environment is set up, I find the following statements are sufficient include the required libraries:
+
+    require "wf4ever/rosrs_client"
+
+## URIs
+
+Be aware that the standard Ruby library provides a URI class, and that the RDF library provides a different, incompatible URI class:
+
+    # Standard Ruby library URI:
+    uri1 = URI("http://example.com/")
+    
+    # URI class used by RDF library:
+    uri2 = RDF::URI("http://example.com")
+
+These URIs are not equivalent, and are not even directly comparable.
+
+Currently, the HTTP handling code uses the standard Ruby library URIs, and the RDF handling code uses URIs provided by the RDF library.  The `namespaces` module returns `RDF::URI` values.
+
+I'm not currently sure if this will prove to cause problems.  Take care when dereferencing URIs obtained from RDF.
+
+## Further work
+
+At the time of writing this, the code is very much a work in progress.  Some of the things possibly yet to-do include:
+
+* Fork project into the wf4ever organization.  Rename to rosrs_session.
+* Complete the APi functions
+* Work out strategy for dealing with different URI classes.
+* When creating an RO, use the supplied RO information to create some initial annotations (similar to RO Manager)?
+* Refactor `rosrs_session.rb` to separate out `http_session`
+* May want to investigate "streaming" RDF data between HTTP and RDF libraries, or using RDF reader/writer classes, rather than transferring via strings.  Currently, I assume the RDF is small enough that this doesn't matter.
+* Refactor test suite per tested module (may require simple HTTP server setup if HTTP factored out as above)
+
+
+## References
+
+[[1] _What is an RO?_][ref1]; Wf4Ever Research Object description and notes.
+
+[[2] _Wf4Ever Research Object Model_][ref2]; Specification of RO model.
+
+[[3] _Wf4ever ROSRS interface (v6)_][ref3]; Description of the HTTP/REST interface for accessing and updating Research Objects, implemented by Wf4Ever RODL.
+
+[[4] `RDF.rb`][ref4]; Linked Data for Ruby
+
+[[5] _Raptor_][ref5]; Raptor RDF Syntax Library
+
+[[6] `rdf_raptor`][ref6]; Raptor RDF Parser Plugin for RDF.rb
+
+[[7] _Python ROSRS\_Session in RO Manager_][ref7];  See also the test suite: [TestROSRS_Session.py ](https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/test/TestROSRS_Session.py).
+
+[[8] `ruby-http-session` project, or successor][ref8]
+
+[[9] _myExperiment_][ref9];  "De Roure, D., Goble, C. and Stevens, R. (2009) The Design and Realisation of the myExperiment Virtual Research Environment for Social Sharing of Workflows. Future Generation Computer Systems 25, pp. 561-567. doi:10.1016/j.future.2008.06.010"
+
+

Added: branches/wf4ever/vendor/plugins/rosrs/Rakefile (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/Rakefile	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/Rakefile	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,44 @@
+# encoding: utf-8
+
+require 'rubygems'
+require 'bundler'
+begin
+  Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+  $stderr.puts e.message
+  $stderr.puts "Run `bundle install` to install missing gems"
+  exit e.status_code
+end
+require 'rake'
+
+require 'jeweler'
+Jeweler::Tasks.new do |gem|
+  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
+  gem.name = "wf4ever-rosrs-client"
+  gem.homepage = "http://github.com/fbacall/rosrs_client"
+  gem.summary = %Q{A client to interact with the ROSRS API.}
+  gem.description = %Q{A port of the ROSRS API Python client into Ruby.}
+  gem.email = "address@hidden"
+  gem.authors = ["Graham Klyne","Finn Bacall"]
+  # dependencies defined in Gemfile
+end
+Jeweler::RubygemsDotOrgTasks.new
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+  test.libs << 'lib' << 'test'
+  test.pattern = 'test/**/test_*.rb'
+  test.verbose = true
+end
+
+task :default => :test
+
+require 'rdoc/task'
+Rake::RDocTask.new do |rdoc|
+  version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title = "rosrs_client #{version}"
+  rdoc.rdoc_files.include('README*')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end

Added: branches/wf4ever/vendor/plugins/rosrs/VERSION (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/VERSION	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/VERSION	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1 @@
+0.1.0

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/annotation.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/annotation.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/annotation.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,69 @@
+module ROSRS
+  class Annotation
+
+    attr_reader :uri, :body_uri, :resource_uri, :created_at, :created_by, :research_object
+
+    def initialize(research_object, uri, body_uri, resource_uri, created_at = nil, created_by = nil, options = {})
+      @research_object = research_object
+      @session = @research_object.session
+      @uri = uri
+      @body_uri = body_uri
+      @resource_uri = resource_uri
+      @created_at = created_at
+      @created_by = created_by
+      @loaded = false
+      if options[:body]
+        @body = options[:body]
+        @loaded = true
+      end
+      load! if options[:load]
+    end
+
+    def loaded?
+      @loaded
+    end
+
+    def load!
+      @body = @session.get_annotation(body_uri || uri)
+      @loaded = true
+    end
+
+    def body
+      load! unless loaded?
+      @body
+    end
+
+    def delete!
+      @session.remove_annotation(uri)
+      true
+    end
+
+    def self.create(ro, resource_uri, annotation_graph)
+      code, reason, annotation_uri, body_uri = ro.session.create_internal_annotation(ro.uri, resource_uri, annotation_graph)
+      self.new(ro, annotation_uri, body_uri, resource_uri, :body => annotation_graph)
+    end
+
+    def self.create_remote(ro, resource_uri, body_uri)
+      code, reason, annotation_uri = ro.session.create_annotation_stub(ro.uri, resource_uri, body_uri)
+      self.new(ro, annotation_uri, body_uri, resource_uri)
+    end
+
+    def update!(resource_uri, annotation_graph)
+      code, reason, body_uri = @session.update_internal_annotation(@research_object.uri, @uri, resource_uri, annotation_graph)
+      @resource_uri = resource_uri
+      @body_uri = body_uri
+      @body = annotation_graph
+      @loaded = true
+      self
+    end
+
+    def update_remote!(resource_uri, body_uri)
+      code, reason = @session.update_annotation_stub(@research_object.uri, @uri, resource_uri, body_uri)
+      @resource_uri = resource_uri
+      @body_uri = body_uri
+      @loaded = false
+      self
+    end
+
+  end
+end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/exceptions.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/exceptions.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/exceptions.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,7 @@
+  # Exception class used to signal HTTP Session errors
+  module ROSRS
+
+    class Exception < Exception
+    end
+
+  end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,120 @@
+module ROSRS
+
+  # A representation of a folder in a Research Object.
+
+  class Folder
+
+    attr_reader :research_object, :name, :uri
+
+    ##
+    # +research_object+:: The Wf4Ever::ResearchObject that aggregates this folder.
+    # +name+::            The display name of the Folder.
+    # +uri+::             The URI for the resource referred to by the Folder.
+    # +options+::         A hash of options:
+    # [:eager_load]       Whether or not to eagerly load the entire Folder hierarchy within in this Folder.
+    def initialize(research_object, name, uri, options = {})
+      @name = name
+      @uri = uri
+      @research_object = research_object
+      @session = research_object.session
+      @loaded = false
+      @contents = []
+      load! if (@eager_load = options[:eager_load])
+    end
+
+    ##
+    # Fetch the entry with name +child_name+ from the Folder's contents
+    def child(child_name)
+      contents.select {|child| child.name == child_name}.first
+    end
+
+    ##
+    # Returns boolean stating whether or not a description of this Folder's contents has been fetched and loaded.
+    def loaded?
+      @loaded
+    end
+
+    ##
+    # Returns an array of FolderEntry and Folder objects.
+    def contents
+      load! unless loaded?
+      @contents
+    end
+
+    ##
+    # Returns the number of entries within the folder.
+    def size
+      contents.size
+    end
+
+    ##
+    # Fetch and parse the Folder's description to get the Folder's contents.
+    def load!
+      fetch_folder_contents!
+      @loaded = true
+    end
+
+    ##
+    # Manually set the Folder's contents.
+    #
+    # Saves making an HTTP request if you already have the folder description.
+    def set_contents!(contents)
+      @contents = contents
+      @loaded = true
+    end
+
+    ##
+    # Delete this folder from the RO. Contents will be preserved.
+    # Also deletes any entries in other folders pointing to this one.
+    def delete!
+      @session.delete_folder(@uri)
+      true
+    end
+
+    ##
+    # Add a resource to this folder. The resource must already be present in the RO.
+    def add(resource_uri, resource_name = nil)
+      @session.add_folder_entry(@uri, resource_uri, resource_name, :parent => self)
+    end
+
+    def remove(entry)
+
+    end
+
+    def self.create(ro, name, contents)
+      @session.create_folder(ro, name, contents)
+    end
+
+    private
+
+    # Get folder contents from resource map
+    def fetch_folder_contents!
+      code, reason, headers, uripath, graph = @session.do_request_rdf("GET", uri,
+                                                                      :accept => 'application/vnd.wf4ever.folder')
+      set_contents!(graph)
+    end
+
+    def parse_folder_description(graph)
+      contents = []
+
+      query = RDF::Query.new do
+        pattern [:folder_entry, RDF.type,  RDF::RO.FolderEntry]
+        pattern [:folder_entry, RDF::RO.entryName, :name]
+        pattern [:folder_entry, RDF::ORE.proxyFor, :target]
+        pattern [:target, RDF.type, RDF::RO.Resource]
+        # The pattern below is treated as mandatory - Bug in RDF library! :( Maybe not needed?
+        # pattern [:target, RDF::ORE.isDescribedBy, :target_resource_map], :optional => true
+      end
+
+      # Create instances for each item.
+      graph.query(query).each do |result|
+        if result.respond_to? :target_resource_map
+          contents << ROSRS::Folder.new(@research_object, result.name.to_s, result.target.to_s, :eager_load => @eager_load)
+        else
+          contents << ROSRS::FolderEntry.new(self, result.name.to_s, result.target.to_s, result.entry_uri.to_s)
+        end
+      end
+    end
+
+  end
+end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder_entry.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder_entry.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/folder_entry.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,32 @@
+module ROSRS
+
+  # An item within a folder.
+
+  class FolderEntry < Resource
+
+    attr_reader :parent_folder, :name, :uri, :resource_uri
+
+    ##
+    # +parent_folder+:: The ROSRS::Folder object in which this entry resides..
+    # +name+::          The display name of the ROSRS::FolderEntry.
+    # +uri+::           The URI of this ROSRS::FolderEntry
+    # +resource_uri+::  The URI for the resource referred to by this ROSRS::FolderEntry.
+    # +folder+::        (Optional) The ROSRS::Folder that this entry points to, if applicable.
+    def initialize(parent_folder, name, uri, resource_uri, folder = nil)
+      super(folder.research_object, uri, resource_uri)
+      @name = name
+      @folder = folder
+      @is_folder = !options[:folder].nil?
+      @resource = options[:folder]
+      @session = @folder.research_object.session
+    end
+
+    ##
+    # Returns boolean stating whether or not this entry points to a folder
+    def folder?
+      @is_folder
+    end
+
+  end
+
+end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/namespaces.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/namespaces.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/namespaces.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,50 @@
+#:nodoc: all
+
+module RDF
+
+  class AO < Vocabulary("http://purl.org/ao/")
+    # Declaring these might not be necessary
+    property :Annotation
+    property :body
+    property :annotatesResource
+  end
+
+  class ORE < Vocabulary("http://www.openarchives.org/ore/terms/")
+    property :Aggregation
+    property :AggregatedResource
+    property :Proxy
+    property :aggregates
+    property :proxyFor
+    property :proxyIn
+    property :isDescribedBy
+  end
+
+  class RO < Vocabulary("http://purl.org/wf4ever/ro#")
+    property :ResearchObject
+    property :AggregatedAnnotation
+    property :annotatesAggregatedResource
+    property :FolderEntry
+    property :Folder
+    property :Resource
+    property :entryName
+  end
+
+  class ROEVO < Vocabulary("http://purl.org/wf4ever/roevo#")
+    property :LiveRO
+  end
+
+  class ROTERMS < Vocabulary("http://ro.example.org/ro/terms/")
+    property :note
+    property :resource
+    property :defaultBase
+  end
+
+  class DON < Vocabulary("http://example.com/2012/11/workflow#")
+    property :hasExampleDataSet
+    property :dataSet
+    property :hasInput
+    property :input
+    property :value
+  end
+
+end

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/rdf_graph.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/rdf_graph.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/rdf_graph.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,74 @@
+# Shim class for RDF graph parsing, serialization, access
+module ROSRS
+  class RDFGraph
+
+    attr_accessor :graph
+
+    def initialize(options={})
+      # options: :uri =>    (URI to load),
+      #          :data =""   (string to load)
+      #          :format => (format of data)
+      @format = :rdfxml
+      @graph  = RDF::Graph.new
+      if options[:uri]
+        load_resource(options[:uri], options[:format])
+      end
+      if options[:data]
+        load_data(options[:data], options[:format])
+      end
+    end
+
+    def load_data(data, format=nil)
+      @graph << RDF::Reader.for(map_format(format)).new(data)
+    end
+
+    def load_resource(uri, format=nil)
+      raise NotImplementedError.new("Attempt to initialize RDFGraph from web resource: #{uri}")
+    end
+
+    def serialize(format=nil)
+      return RDF::Writer.for(map_format(format)).buffer { |w| w << @graph }
+    end
+
+    # other methods here
+
+    def has_statement?(stmt)
+      return @graph.has_statement?(stmt)
+    end
+
+    def each_statement(&block)
+      @graph.each_statement(&block)
+    end
+
+    def query(pattern, &block)
+      @graph.query(pattern, &block)
+    end
+
+    def match?(pattern)
+      pattern_found = false
+      @graph.query(pattern) { |s| pattern_found = true }
+      return pattern_found
+    end
+
+    # Private helpers
+
+    private
+
+    def map_format(format=nil)
+      rdf_format = :rdfxml  # default
+      if format
+        if format == :xml
+          rdf_format = :rdfxml
+        elsif format == :ntriples
+          rdf_format = :ntriples
+        elsif format == :turtle
+          rdf_format = :turtle
+        else
+          raise ArgumentError.new("Unrecognized RDF format: #{format}")
+        end
+      end
+      return rdf_format
+    end
+
+  end
+end

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/research_object.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/research_object.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/research_object.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,115 @@
+module ROSRS
+
+  class ResearchObject
+
+    attr_reader :uri, :session
+
+    def initialize(rosrs_session, uri)
+      @session = rosrs_session
+      @uri = uri
+      @loaded = false
+    end
+
+    def loaded?
+      @loaded
+    end
+
+    def load!
+      manifest_uri, @manifest = @session.get_manifest(uri)
+      @annotations = extract_annotations
+      @root_folder = extract_root_folder
+      @loaded = true
+    end
+
+    def manifest
+      load! unless loaded?
+      @manifest
+    end
+
+    def annotations(resource_uri = nil)
+      load! unless loaded?
+      if resource_uri.nil?
+        @annotations
+      else
+        @annotations.select {|a| a.resource_uri == resource_uri}
+      end
+    end
+
+    def root_folder
+      load! unless loaded?
+      @root_folder
+    end
+
+    def delete!
+      @session.delete_research_object(uri)
+      true
+    end
+
+    ##
+    # Create an annotation for a given resource_uri, using the supplied annotation body.
+    def create_annotation(resource_uri, annotation_body)
+      annotation = ROSRS::Annotation.create(self, resource_uri, annotation_body)
+      annotations << annotation
+      annotation
+    end
+
+    ##
+    # Create an annotation for a given resource_uri, using a remote body pointed to by body_uri.
+    def create_remote_annotation(resource_uri, body_uri)
+      annotation = ROSRS::Annotation.create_remote(self, resource_uri, body_uri)
+      annotations << annotation
+      annotation
+    end
+
+    ##
+    # Create a root folder in the research object if one doesn't already exist.
+    def create_folder(name)
+      @session.create_folder(@uri, name)
+    end
+
+    private
+
+    def extract_annotations
+      annotations = []
+      queries = [RDF::RO.annotatesAggregatedResource, RDF::AO.annotatesResource].collect do |predicate|
+        RDF::Query.new do
+          pattern [:annotation_uri, RDF.type, RDF::RO.AggregatedAnnotation]
+          pattern [:annotation_uri, predicate, :resource_uri]
+          pattern [:annotation_uri, RDF::AO.body, :body_uri]
+          pattern [:annotation_uri, RDF::DC.creator, :created_by]
+          pattern [:annotation_uri, RDF::DC.created, :created_at]
+        end
+      end
+
+      queries.each do |query|
+        @manifest.query(query) do |result|
+            annotations << ROSRS::Annotation.new(self,
+                                                   result.annotation_uri.to_s,
+                                                   result.body_uri.to_s,
+                                                   result.resource_uri.to_s,
+                                                   result.created_at.to_s,
+                                                   result.created_by.to_s)
+        end
+      end
+
+      annotations
+    end
+
+    def extract_root_folder
+      query = RDF::Query.new do
+        pattern [:research_object, RDF::RO.rootFolder,  :folder]
+        pattern [:folder, RDF::ORE.isDescribedBy, :folder_resource_map]
+      end
+
+      result = @manifest.query(query).first
+      if result
+        folder_uri = result.folder.to_s
+        folder_name = folder_uri.to_s.split('/').last
+        ROSRS::Folder.new(self, folder_name, folder_uri)
+      else
+        nil
+      end
+    end
+
+  end
+end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/resource.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/resource.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/resource.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,34 @@
+module ROSRS
+
+  class Resource
+    attr_reader :uri, :proxy_uri
+
+    def initialize(research_object, uri, proxy_uri, external = false)
+      @research_object = research_object
+      @uri = uri
+      @proxy_uri = proxy_uri
+      @session = @research_object.session
+      @external = external
+    end
+
+    ##
+    # Removes this resource from the Research Object.
+    def delete!
+      if internal?
+        @session.remove_resource(@uri)
+      elsif external?
+        @session.remove_resource(@proxy_uri)
+      end
+      true
+    end
+
+    def internal?
+      !external
+    end
+
+    def external?
+      external
+    end
+
+  end
+end
\ No newline at end of file

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/session.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/session.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs/session.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,756 @@
+# ROSRS session class
+module ROSRS
+  class Session
+
+    ANNOTATION_CONTENT_TYPES =
+      { "application/rdf+xml" => :xml,
+        "text/turtle"         => :turtle,
+        #"text/n3"             => :n3,
+        "text/nt"             => :ntriples,
+        #"application/json"    => :jsonld,
+        #"application/xhtml"   => :rdfa,
+      }
+
+    # -------------
+    # General setup
+    # -------------
+
+    def initialize(uri, accesskey=nil)
+      @uri = URI(uri.to_s) # Force string or URI to be a URI - tried coerce, didn't work
+      @key = accesskey
+      @http = Net::HTTP.new(@uri.host, @uri.port)
+    end
+
+    def close
+      if @http and @http.started?
+        @http.finish
+        @http = nil
+      end
+    end
+
+    def error(msg, value=nil)
+      # Raise exception with supplied message and optional value
+      if value
+        msg += " (#{value})"
+      end
+      raise ROSRS::Exception.new("Session::Exception on address@hidden #{msg}")
+    end
+
+    # -------
+    # Helpers
+    # -------
+
+    private
+
+    ##
+    # Parse links from headers; returns a hash indexed by link relation
+    # Headerlist is a hash indexed by header field name (see HTTP:Response)
+    def parse_links(headers)
+      links = {}
+      link_header = headers["link"] || headers["Link"]
+      link_header.split(",").each do |link|
+        matches = link.strip.match(/<([^>]*)>\s*;.*rel\s*=\s*"?([^;"]*)"?/)
+        if matches
+          links[matches[2]] ||= []
+          links[matches[2]] << URI(matches[1])
+        end
+      end
+      links
+    end
+
+    ##
+    # Extract path (incl query) for HTTP request
+    # Should accept URI, RDF::URI or string values
+    # Must be same host and port as session URI
+    # Relative values are based on session URI
+    def get_request_path(uripath)
+      uripath = URI(uripath.to_s)
+      if uripath.scheme && (uripath.scheme != @uri.scheme)
+        error("Request URI scheme does not match session: #{uripath}")
+      end
+      if (uripath.host && uripath.host != @uri.host) ||
+         (uripath.port && uripath.port != @uri.port)
+        error("Request URI host or port does not match session: #{uripath}")
+      end
+      requri = URI.join(@uri.to_s, uripath.path).path
+      if uripath.query
+        requri += "?"+uripath.query
+      end
+      requri
+    end
+
+    def get_request_headers(options = {})
+      if options[:headers]
+        # Convert symbol keys to strings
+        reqheaders = options[:headers].inject({}) do |headers, (header, value)|
+          headers[header.to_s] = value
+          headers
+        end
+      else
+        reqheaders = {}
+      end
+      if @key
+        reqheaders["authorization"] = "Bearer "address@hidden
+      end
+      if options[:ctype]
+        reqheaders["content-type"] = options[:ctype]
+      end
+      if options[:accept]
+        reqheaders['accept'] = options[:accept]
+      end
+      if options[:link]
+        reqheaders['Link'] = options[:link]
+      end
+      reqheaders
+    end
+
+    public
+
+    ##
+    # Perform HTTP request
+    #
+    # +method+::        HTTP method name
+    # +uripath+::       is reference or URI of resource (see get_request_path)
+    # options:
+    # [:body]    body to accompany request
+    # [:ctype]   content type of supplied body
+    # [:accept]  accept content types for response
+    # [:headers] additional headers for request
+    # Return [code, reason(text), response headers, response body]
+    #
+    def do_request(method, uripath, options = {})
+
+      req = nil
+
+      case method
+      when 'GET'
+        req = Net::HTTP::Get.new(get_request_path(uripath))
+      when 'PUT'
+        req = Net::HTTP::Put.new(get_request_path(uripath))
+      when 'POST'
+        req = Net::HTTP::Post.new(get_request_path(uripath))
+      when 'DELETE'
+        req = Net::HTTP::Delete.new(get_request_path(uripath))
+      else
+        error("Unrecognized HTTP method #{method}")
+      end
+
+      if options[:body]
+        req.body = options[:body]
+      end
+
+      get_request_headers(options).each { |h,v| req.add_field(h, v) }
+      resp = @http.request(req)
+      [Integer(resp.code), resp.message, resp, resp.body]
+    end
+
+    ##
+    # Perform HTTP request, following 302, 303 307 redirects
+    # Return [code, reason(text), response headers, final uri, response body]
+    def do_request_follow_redirect(method, uripath, options = {})
+      code, reason, headers, data = "" uripath, options)
+      if [302,303,307].include?(code)
+        uripath = headers["location"]
+        code, reason, headers, data = "" uripath, options)
+      end
+      if [302,307].include?(code)
+        # Allow second temporary redirect
+        uripath = headers["location"]
+        code, reason, headers, data = "" uripath, options)
+      end
+      [code, reason, headers, uripath, data]
+    end
+
+    ##
+    # Perform HTTP request expecting an RDF/XML response
+    # Return [code, reason(text), response headers, manifest graph]
+    # Returns the manifest as a graph if the request is successful
+    # otherwise returns the raw response data.
+    def do_request_rdf(method, uripath, options = {})
+      options[:accept] ||= "application/rdf+xml"
+      code, reason, headers, uripath, data = "" uripath, options)
+      if code >= 200 and code < 300
+        if headers["content-type"].downcase == options[:accept]
+          begin
+            data = "" => data, :format => :xml)
+          rescue Exception => e
+            code = 902
+            reason = "RDF parse failure (#{e.message})"
+          end
+        else
+          code = 901
+          reason = "Non-RDF content-type returned (#{headers["content-type"]})"
+        end
+      end
+      [code, reason, headers, uripath, data]
+    end
+
+    # ---------------
+    # RO manipulation
+    # ---------------
+
+    ##
+    # Returns [copde, reason, uri, manifest]
+    def create_research_object(name, title, creator, date)
+      reqheaders   = {
+          "slug"    => name
+          }
+      roinfo = {
+          "id"      => name,
+          "title"   => title,
+          "creator" => creator,
+          "date"    => date
+          }
+      roinfotext = roinfo.to_json
+      code, reason, headers, uripath, data = "" "",
+          :body       => roinfotext,
+          :headers    => reqheaders)
+      if code == 201
+        [code, reason, headers["location"], data]
+      elsif code == 409
+        [code, reason, nil, data]
+      else
+        error("Error creating RO: #{code} #{reason}")
+      end
+    end
+
+    def delete_research_object(ro_uri)
+      #  code, reason = delete_research_object(ro_uri)
+      code, reason = do_request("DELETE", ro_uri,
+          :accept => "application/rdf+xml")
+      if [204, 404].include?(code)
+        [code, reason]
+      else
+        error("Error deleting RO #{ro_uri}: #{code} #{reason}")
+      end
+    end
+
+    # ---------------------
+    # Resource manipulation
+    # ---------------------
+
+    ##
+    # Aggregate internal resource
+    #
+    # options:
+    # [:body]    body to accompany request
+    # [:ctype]   content type of supplied body
+    # [:accept]  accept content types for response
+    # [:headers] additional headers for request
+    #
+    # Returns: [code, reason, proxyuri, resource_uri], where code is 200 or 201
+
+    def aggregate_internal_resource(ro_uri, respath=nil, options={})
+        # POST (empty) proxy value to RO ...
+      reqheaders = options[:headers] || {}
+      if respath
+        reqheaders['slug'] = respath
+      end
+      proxydata = %q(
+        <rdf:RDF
+          xmlns:ore="http://www.openarchives.org/ore/terms/"
+          xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
+          <ore:Proxy>
+          </ore:Proxy>
+        </rdf:RDF>
+        )
+      code, reason, headers = do_request("POST", ro_uri,
+        :ctype    => "application/vnd.wf4ever.proxy",
+        :headers  => reqheaders,
+        :body     => proxydata)
+      if code != 201
+        error("Error creating aggregation proxy",
+              "#{code} #{reason} #{respath}")
+      end
+      proxyuri = URI(headers["location"])
+      links    = parse_links(headers)
+      resource_uri = links[RDF::ORE.proxyFor.to_s].first
+      unless resource_uri
+        error("No ore:proxyFor link in create proxy response",
+              "Proxy URI #{proxyuri}")
+      end
+      # PUT resource content to indicated URI
+      code, reason = do_request("PUT", resource_uri, options)
+      unless [200,201].include?(code)
+          error("Error creating aggregated resource content",
+                "#{code}, #{reason}, #{respath}")
+      end
+      [code, reason, proxyuri, resource_uri]
+    end
+
+    # -----------------------
+    # Resource access
+    # -----------------------
+
+    ##
+    # Retrieve resource from RO
+    #
+    # resuriref    is relative reference or URI of resource
+    # ro_uri       is URI of RO, used as base for relative reference
+    # options:
+    # [:accept]    content type
+    # [:headers]   additional headers for request
+    # Returns:
+    # [code, reason, headers, data], where code is 200 or 404
+    def get_resource(resuriref, ro_uri=nil, options={})
+      if ro_uri
+        resuriref = URI.join(ro_uri.to_s, resuriref.to_s)
+      end
+      code, reason, headers, uri, data = "" resuriref, options)
+      unless [200,404].include?(code)
+        error("Error retrieving RO resource: #{code}, #{reason}, #{resuriref}")
+      end
+      [code, reason, headers, uri, data]
+    end
+
+    ##
+    # Retrieve RDF resource from RO
+    #
+    # resource_uri    is relative reference or URI of resource
+    # ro_uri     is URI of RO, used as base for relative reference
+    # options:
+    # [:headers]   additional headers for request
+    #
+    # Returns:
+    # [code, reason, headers, uri, data], where code is 200 or 404
+    #
+    # If code isreturned as 200, data is returned as an RDFGraph value
+    def get_resource_rdf(resource_uri, ro_uri=nil, options={})
+      if ro_uri
+        resource_uri = URI.join(ro_uri.to_s, resource_uri.to_s)
+      end
+      code, reason, headers, uri, data = "" resource_uri, options)
+      unless [200,404].include?(code)
+        error("Error retrieving RO resource: #{code}, #{reason}, #{resource_uri}")
+      end
+      [code, reason, headers, uri, data]
+    end
+
+    ##
+    # Retrieve an RO manifest
+    #
+    # Returns [manifesturi, manifest]
+    def get_manifest(ro_uri)
+      code, reason, headers, uri, data = "" ro_uri)
+      if code != 200
+        error("Error retrieving RO manifest: #{code} #{reason}")
+      end
+      [uri, data]
+    end
+
+    # -----------------------
+    # Annotation manipulation
+    # -----------------------
+
+    ##
+    # Create an annotation body from a supplied annnotation graph.
+    #
+    # Returns: [code, reason, body_uri]
+    def create_annotation_body(ro_uri, annotation_graph)
+      code, reason, bodyproxyuri, body_uri = aggregate_internal_resource(ro_uri, nil,
+        :ctype => "application/rdf+xml",
+        :body  => annotation_graph.serialize(format=:xml))
+      if code != 201
+        error("Error creating annotation body resource",
+              "#{code}, #{reason}, #{ro_uri}")
+      end
+      [code, reason, body_uri]
+    end
+
+    ##
+    # Create entity body for annotation stub
+    def create_annotation_stub_rdf(ro_uri, resource_uri, body_uri)
+      v = { :xmlbase => ro_uri.to_s,
+            :resource_uri  => resource_uri.to_s,
+            :body_uri => body_uri.to_s
+          }
+      annotation_stub = %Q(<?xml version="1.0" encoding="UTF-8"?>
+          <rdf:RDF
+            xmlns:ro="http://purl.org/wf4ever/ro#"
+            xmlns:ao="http://purl.org/ao/"
+            xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+            xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+            xml:base="#{v[:xmlbase]}"
+          >
+            <ro:AggregatedAnnotation>
+              <ao:annotatesResource rdf:resource="#{v[:resource_uri]}" />
+              <ao:body rdf:resource="#{v[:body_uri]}" />
+            </ro:AggregatedAnnotation>
+          </rdf:RDF>
+          )
+      annotation_stub
+    end
+
+    ##
+    # Create an annotation stub for supplied resource using indicated body
+    #
+    # Returns: [code, reason, stuburi]
+    def create_annotation_stub(ro_uri, resource_uri, body_uri)
+      annotation = create_annotation_stub_rdf(ro_uri, resource_uri, body_uri)
+      code, reason, headers, data = "" ro_uri,
+          :ctype => "application/vnd.wf4ever.annotation",
+          :body  => annotation)
+      if code != 201
+          error("Error creating annotation #{code}, #{reason}, #{resource_uri}")
+      end
+      [code, reason, URI(headers["location"])]
+    end
+
+    ##
+    # Create internal annotation
+    #
+    # Returns: [code, reason, annotation_uri, body_uri]
+    def create_internal_annotation(ro_uri, resource_uri, annotation_graph)
+      code, reason, headers, data = "" ro_uri,
+          :ctype => "application/rdf+xml",
+          :body  => annotation_graph.serialize(format=:xml),
+          :link => "<#{resource_uri}>; rel=\"#{RDF::AO.annotatesResource}\"")
+      if code != 201
+        error("Error creating annotation #{code}, #{reason}, #{resource_uri}")
+      end
+      puts parse_links(headers).inspect
+puts "      parse_links(headers) = #{      parse_links(headers).inspect}"
+      [code, reason, URI(headers["location"]), parse_links(headers)[RDF::AO.body.to_s].first]
+    end
+
+    ##
+    # Create a resource annotation using an existing (possibly external) annotation body
+    #
+    # Returns: (code, reason, annotation_uri)
+    def create_external_annotation(ro_uri, resource_uri, body_uri)
+      create_annotation_stub(ro_uri, resource_uri, body_uri)
+    end
+
+    ##
+    # Update an indicated annotation for supplied resource using indicated body
+    #
+    # Returns: [code, reason]
+    def update_annotation_stub(ro_uri, stuburi, resource_uri, body_uri)
+      annotation = create_annotation_stub_rdf(ro_uri, resource_uri, body_uri)
+      code, reason, headers, data = "" stuburi,
+          :ctype => "application/vnd.wf4ever.annotation",
+          :body  => annotation)
+      if code != 200
+          error("Error updating annotation #{code}, #{reason}, #{resource_uri}")
+      end
+      [code, reason]
+    end
+
+    ##
+    # Update an annotation with a new internal annotation body
+    #
+    # returns: [code, reason, body_uri]
+    def update_internal_annotation(ro_uri, stuburi, resource_uri, annotation_graph)
+      code, reason, body_uri = create_annotation_body(ro_uri, annotation_graph)
+      if code != 201
+          error("Error creating annotation #{code}, #{reason}, #{resource_uri}")
+      end
+      code, reason = update_annotation_stub(ro_uri, stuburi, resource_uri, body_uri)
+      [code, reason, body_uri]
+    end
+
+    ##
+    # Update an annotation with an existing (possibly external) annotation body
+    #
+    # returns: (code, reason)
+    def update_external_annotation(ro_uri, annotation_uri, resource_uri, body_uri)
+      update_annotation_stub(ro_uri, annotation_uri, resource_uri, body_uri)
+    end
+
+    ##
+    # Enumerate annnotation URIs associated with a resource
+    # (or all annotations for an RO)
+    #
+    # Returns an array of annotation statements
+    def get_annotation_statements(ro_uri, resource_uri=nil)
+      manifesturi, manifest = get_manifest(ro_uri)
+      statements = []
+
+      resource_uri = RDF::URI.parse(ro_uri).join(RDF::URI.parse(resource_uri)) if ro_uri
+
+      manifest.query(:object => resource_uri) do |stmt|
+        if [RDF::AO.annotatesResource,RDF::RO.annotatesAggregatedResource].include?(stmt.predicate)
+          statements << stmt
+        end
+      end
+      statements
+    end
+
+    ##
+    # Enumerate annnotation URIs associated with a resource
+    # (or all annotations for an RO)
+    #
+    # Returns an array of annotation URIs
+    def get_annotation_stub_uris(ro_uri, resource_uri=nil)
+      get_annotation_statements(ro_uri, resource_uri).map do |statement|
+        statement.subject
+      end
+    end
+
+    ##
+    # Enumerate annnotation body URIs associated with a resource
+    # (or all annotations for an RO)
+    #
+    # Returns an array of annotation body URIs
+    def get_annotation_body_uris(ro_uri, resource_uri=nil)
+      manifesturi, manifest = get_manifest(ro_uri)
+      body_uris = []
+
+      query1 = RDF::Query.new do
+        pattern [:annotation_uri, RDF::AO.annotatesResource, RDF::URI(resource_uri)]
+        pattern [:annotation_uri, RDF::AO.body, :body_uri]
+      end
+
+      query2 = RDF::Query.new do
+        pattern [:annotation_uri, RDF::RO.annotatesAggregatedResource, RDF::URI(resource_uri)]
+        pattern [:annotation_uri, RDF::AO.body, :body_uri]
+      end
+
+      manifest.query(query1) do |result|
+        body_uris << result.body_uri.to_s
+      end
+
+      manifest.query(query2) do |result|
+        body_uris << result.body_uri.to_s
+      end
+
+      body_uris.uniq
+    end
+
+    ##
+    # Retrieve RDF graphs of all annnotations associated with a resource
+    # (or all annotations for an RO)
+    #
+    # Returns graph of merged annotations
+    def get_annotation_graphs(ro_uri, resource_uri=nil)
+      annotation_graphs = []
+      get_annotation_statements(ro_uri, resource_uri).each do |annotation_statement|
+      puts "processing statement: #{annotation_statement.inspect}"
+        auri   = annotation_statement.subject
+        resuri = annotation_statement.object
+        code, reason, headers, buri, bodytext = do_request_follow_redirect("GET", auri, {})
+        if code == 200
+          content_type = headers['content-type'].split(';', 2)[0].strip.downcase
+          if ANNOTATION_CONTENT_TYPES.include?(content_type)
+            bodyformat = ANNOTATION_CONTENT_TYPES[content_type]
+            annotation_graphs << {
+              :stub         => auri,
+              :resource_uri => resuri,
+              :body_uri     => buri,
+              :body         => ROSRS::RDFGraph.new.load_data(bodytext, bodyformat)
+            }
+          else
+            warn("Warning: #{buri} has unrecognized content-type: #{content_type}")
+          end
+        else
+          error("Failed to GET #{buri}: #{code} #{reason}")
+        end
+      end
+      annotation_graphs
+    end
+  
+    ##
+    # Build RDF graph of all annnotations associated with a resource
+    # (or all annotations for an RO)
+    #
+    # Returns graph of merged annotations
+    def get_annotation_graph(ro_uri, resource_uri=nil)
+      annotation_graph = ROSRS::RDFGraph.new
+      get_annotation_body_uris(ro_uri, resource_uri).each do |auri|
+        code, reason, headers, buri, bodytext = do_request_follow_redirect("GET", auri, {})
+        if code == 200
+          content_type = headers['content-type'].split(';', 2)[0].strip.downcase
+          if ANNOTATION_CONTENT_TYPES.include?(content_type)
+            bodyformat = ANNOTATION_CONTENT_TYPES[content_type]
+            annotation_graph.load_data(bodytext, bodyformat)
+          else
+            warn("Warning: #{buri} has unrecognized content-type: #{content_type}")
+          end
+        else
+          error("Failed to GET #{buri}: #{code} #{reason}")
+        end
+      end
+      annotation_graph
+    end
+
+    ##
+    # Retrieve annotation for given annotation URI
+    #
+    # Returns: annotation_graph
+    def get_annotation(annotation_uri)
+      code, reason, headers, uri, annotation_graph = get_resource_rdf(annotation_uri)
+      annotation_graph
+    end
+
+    ##
+    # Remove annotation at given annotation URI
+    #
+    # Returns: (code, reason)
+    def remove_annotation(annotation_uri)
+      code, reason = do_request("DELETE", annotation_uri)
+      if code == 204
+        [code, reason]
+      else
+        error("Failed to DELETE annotation #{annotation_uri}: #{code} #{reason}")
+      end
+    end
+
+    # -----------------------
+    # Folder manipulation
+    # -----------------------
+
+    ##
+    # Returns an array of the given research object's root folders, as Folder objects.
+    def get_root_folder(ro_uri, options = {})
+      uri, data = ""
+      query = RDF::Query.new do
+        pattern [:research_object, RDF::RO.rootFolder,  :folder]
+        pattern [:folder, RDF::ORE.isDescribedBy, :folder_resource_map]
+      end
+
+      result = data.query(query).first
+
+      get_folder(result.folder_resource_map.to_s, options.merge({:name => result.folder.to_s}))
+    end
+
+    ##
+    # Returns an RO::Folder object from the given resource map URI.
+    def get_folder(folder_uri, options = {})
+      folder_name = options[:name] || folder_uri.to_s.split('/').last
+      ROSRS::Folder.new(self, folder_name, folder_uri, :eager_load => options[:eager_load])
+    end
+
+    ##
+    # Returns an array of the given research object's root folders, as RO::Folder objects.
+    # These folders have their contents pre-loaded
+    # and the full hierarchy can be traversed without making further requests
+    def get_folder_hierarchy(ro_uri, options = {})
+      options[:eager_load] = true
+      get_root_folder(ro_uri, options)
+    end
+
+    ##
+    # Takes a folder URI and returns a it's description in RDF
+    def get_folder_description(folder_uri)
+      code, reason, headers, uripath, graph = do_request_rdf("GET", folder_uri,
+                                                             :accept => 'application/vnd.wf4ever.folder')
+      if code == 201
+        parse_folder_description(graph)
+      else
+        error("Error getting folder description: #{code} #{reason}")
+      end
+    end
+
+    ##
+    # +contents+ is an Array containing Hash elements, which must consist of a :uri and an optional :name.
+    # Example:
+    #   folder_contents = [{:name => 'test_data.txt', :uri => 'http://www.example.com/ro/file1.txt'},
+    #                      {:uri => 'http://www.myexperiment.org/workflows/7'}]
+    #   create_folder('ros/new_ro/', 'example_data', folder_contents)
+    #
+    # Returns the created folder as an RO::Folder object
+    def create_folder(ro_uri, name, contents = [])
+      code, reason, headers, uripath, folder_description = do_request_rdf("POST", ro_uri,
+          :body       => create_folder_description(contents),
+          :headers    => {"Slug" => name,
+                          "Content-Type" => 'application/vnd.wf4ever.folder',},
+          :accept     => 'application/vnd.wf4ever.folder')
+
+      if code == 201
+        uri = parse_links(headers)[RDF::ORE.proxyFor.to_s].first
+        folder = ROSRS::Folder.new(self, uri.to_s.split('/').last, uri)
+
+        # Parse folder contents from response
+        query = RDF::Query.new do
+          pattern [:folder_entry, RDF.type, RDF.Description]
+          pattern [:folder_entry, RDF::RO.entryName, :name]
+          pattern [:folder_entry, RDF::ORE.proxyFor, :target]
+          #pattern [:folder_entry, SOMETHING, :entry_uri]
+        end
+
+        folder_contents = folder_description.query(query).collect do |e|
+          ROSRS::FolderEntry.new(self, e.name.to_s, e.target.to_s, e.entry_uri.to_s, folder)
+        end
+
+        folder.set_contents!(folder_contents)
+        folder
+      else
+        error("Error creating folder: #{code} #{reason}")
+      end
+    end
+
+    def delete_folder(folder_uri)
+      code, reason = do_request("DELETE", folder_uri)
+      error("Error deleting folder #{folder_uri}: #{code} #{reason}") unless [204, 404].include?(code)
+      [code, reason]
+    end
+
+    def add_folder_entry(folder_uri, resource_uri, resource_name = nil, options = {})
+      code, reason, headers, body= do_request("POST", folder_uri,
+          :body       => create_folder_entry_description(resource_uri, resource_name),
+          :headers    => {"Content-Type" => 'application/vnd.wf4ever.proxy',})
+      if code == 201
+        ROSRS::FolderEntry.new(self, resource_name, parse_links(headers)[RDF::ORE.proxyFor.to_s].first,
+                            headers["Location"], options[:folder])
+      else
+        error("Error adding resource to folder: #{code} #{reason}")
+      end
+    end
+
+    def delete_resource(resource_uri)
+      code, reason = do_request("DELETE", resource_uri)
+      error("Error deleting resource #{resource_uri}: #{code} #{reason}") unless code == 204
+      [code, reason]
+    end
+
+    private
+
+    ##
+    # Takes +contents+, an Array containing Hash elements, which must consist of a :uri and an optional :name,
+    # and returns an RDF description of the folder contents.
+    def create_folder_description(contents)
+      body = %(
+        <rdf:RDF
+          xmlns:ore="#{RDF::ORE.to_uri.to_s}"
+          xmlns:rdf="#{RDF.to_uri.to_s}"
+          xmlns:ro="#{RDF::RO.to_uri.to_s}" >
+          <ro:Folder>
+            #{contents.collect {|r| "<ore:aggregates rdf:resource=\"#{r[:uri]}\" />" }.join("\n")}
+          </ro:Folder>
+      )
+      contents.each do |r|
+        if r[:name]
+          body << create_folder_entry_body(r[:uri], r[:name])
+        end
+      end
+      body << %(
+        </rdf:RDF>
+      )
+
+      body
+    end
+
+    def create_folder_entry_description(uri, name = nil)
+     %(
+        <rdf:RDF
+          xmlns:ore="#{RDF::ORE.to_uri.to_s}"
+          xmlns:rdf="#{RDF.to_uri.to_s}"
+          xmlns:ro="#{RDF::RO.to_uri.to_s}" >
+          #{create_folder_entry_body(uri, name)}
+        </rdf:RDF>
+      )
+    end
+
+    def create_folder_entry_body(uri, name = nil)
+      body = %(
+        <ro:FolderEntry>
+      )
+      body << "<ro:entryName>#{name}</ro:entryName>" if name
+      body << %(<ore:proxyFor rdf:resource="#{uri}" />
+        </ro:FolderEntry>
+      )
+      body
+    end
+
+  end
+end

Added: branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs_client.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs_client.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/lib/wf4ever/rosrs_client.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,19 @@
+require 'net/http'
+require 'logger'
+
+require 'rubygems'
+require 'json'
+require 'rdf'
+require 'rdf/raptor'
+
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'namespaces'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'rdf_graph'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'session'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'exceptions'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'research_object'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'annotation'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs',  'resource'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'folder'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'rosrs', 'folder_entry'))
+
+

Added: branches/wf4ever/vendor/plugins/rosrs/test/helper.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/test/helper.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/test/helper.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,17 @@
+require 'rubygems'
+require 'bundler'
+begin
+  Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+  $stderr.puts e.message
+  $stderr.puts "Run `bundle install` to install missing gems"
+  exit e.status_code
+end
+require 'test/unit'
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'wf4ever/rosrs_client'
+
+class Test::Unit::TestCase
+end

Added: branches/wf4ever/vendor/plugins/rosrs/test/test_rosrs_session.rb (0 => 3193)


--- branches/wf4ever/vendor/plugins/rosrs/test/test_rosrs_session.rb	                        (rev 0)
+++ branches/wf4ever/vendor/plugins/rosrs/test/test_rosrs_session.rb	2012-11-23 11:21:15 UTC (rev 3193)
@@ -0,0 +1,405 @@
+# Test suite for ROSRS_Session
+require File.dirname(__FILE__) + '/helper'
+
+
+class TestROSRSSession < Test::Unit::TestCase
+
+  # Test configuration values - may be imported later
+  #
+  # @@TODO: create separate module for test configuration (RODL, etc)
+  #
+  class Config
+    def self.rosrs_api_uri; "http://sandbox.wf4ever-project.org/rodl/ROs/"; end
+    def self.authorization; "b1b286f1-24cf-4a86-97b1-208513d403ee"; end
+    def self.test_ro_name;  "TestSessionRO_ruby"; end
+    def self.test_ro_path; test_ro_name+"/"; end
+    def self.test_ro_uri;   rosrs_api_uri+test_ro_path; end
+    def self.test_res1_rel; "subdir/res1.txt"; end
+    def self.test_res2_rel; "subdir/res2.rdf"; end
+    def self.test_res1_uri; test_ro_uri+test_res1_rel; end
+    def self.test_res2_uri; test_ro_uri+test_res2_rel; end
+  end
+
+  def setup
+    @rouri = nil
+    @rosrs = ROSRS::Session.new(Config.rosrs_api_uri, Config.authorization)
+
+    StringIO.class_eval do
+      def readpartial(*args)
+        result = read(*args)
+        if result.nil?
+          raise EOFError
+        else
+          result
+        end
+      end
+    end
+  end
+
+  def teardown
+    if @rosrs
+      @rosrs.close
+    end
+  end
+
+  def uri(str)
+    RDF::URI(str)
+  end
+
+  def lit(str)
+    RDF::Literal(str)
+  end
+
+  def stmt(triple)
+    s,p,o = triple
+    RDF::Statement(:subject=>s, :predicate=>p, :object=>o)
+  end
+
+  def assert_contains(triple, graph)
+    assert(graph.match?(stmt(triple)), "Expected triple #{triple}")
+  end
+
+  def assert_not_contains(triple, graph)
+    assert(!graph.match?(stmt(triple)), "Unexpected triple #{triple}")
+  end
+
+  def assert_includes(item, list)
+    assert(list.include?(item), "Expected item #{item} in list: #{list.inspect}")
+  end
+
+  def assert_not_includes(item, list)
+    assert(!list.include?(item), "Unexpected item #{item} in list: #{list.inspect}")
+  end
+
+  def create_test_research_object
+    c, r = @rosrs.delete_research_object(Config.test_ro_uri)
+    c,r,u,m = @rosrs.create_research_object(Config.test_ro_name,
+        "Test RO for Session", "TestROSRS_Session.py", "2012-09-28")
+    assert_equal(c, 201)
+    @rouri = u
+    [c,r,u,m]
+  end
+
+  def populate_test_research_object
+    # Add plain text resource
+    res1_body = %q(#{test_res1_uri}
+        resource body line 2
+        resource body line 3
+        end
+        )
+    options = { :body => res1_body, :ctype => "text/plain" }
+    c, r, puri, ruri = @rosrs.aggregate_internal_resource(
+        @rouri, Config.test_res1_rel, options)
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    assert_equal(Config.test_res1_uri, ruri.to_s)
+    @res_txt = ruri
+    # Add RDF resource
+    res2_body = %q(
+        <rdf:RDF
+          xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+          xmlns:ex="http://example.org/" >
+          <ex:Resource rdf:about="http:/example.com/res/1">
+            <ex:foo rdf:resource="http://example.com/res/1" />
+            <ex:bar>Literal property</ex:bar>
+          </ex:Resource>
+        </rdf:RDF>
+        )
+    options = { :body => res2_body, :ctype => "application/rdf+xml" }
+    c, r, puri, ruri = @rosrs.aggregate_internal_resource(
+        @rouri, Config.test_res2_rel, options)
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    assert_equal(Config.test_res2_uri, ruri.to_s)
+    @res_rdf = ruri
+    # @@TODO Add external resource
+  end
+
+  def delete_test_research_object
+    c, r = @rosrs.delete_research_object(@rouri)
+    [c, r]
+  end
+
+  # ----------
+  # Test cases
+  # ----------
+
+  def test_namespaces
+    assert_equal(RDF::URI("http://www.openarchives.org/ore/terms/Aggregation"), RDF::ORE.Aggregation)
+    assert_equal(RDF::URI("http://purl.org/wf4ever/ro#ResearchObject"), RDF::RO.ResearchObject)
+    assert_equal(RDF::URI("http://www.w3.org/2000/01/rdf-schema#seeAlso"), RDF::RDFS.seeAlso)
+  end
+
+  def test_create_serialize_graph
+    b = %q(
+        <rdf:RDF
+          xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+          xmlns:ex="http://example.org/" >
+          <ex:Resource rdf:about="http:/example.com/res/1">
+            <ex:foo rdf:resource="http://example.com/res/1" />
+            <ex:bar>Literal property</ex:bar>
+          </ex:Resource>
+        </rdf:RDF>
+        )
+    g  = ROSRS::RDFGraph.new(:data ="" b)
+    b1 = g.serialize(format=:ntriples)
+    r1 = %r{<http:/example\.com/res/1> <http://example\.org/foo> <http://example\.com/res/1> \.}
+    r2 = %r{<http:/example\.com/res/1> <http://example\.org/bar> "Literal property" \.}
+    [r1,r2].each do |r|
+      assert(b1 =~ r, "Not matched: #{r}")
+    end
+  end
+
+  def test_query_graph
+    b = %q(
+        <rdf:RDF
+          xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+          xmlns:ex="http://example.org/" >
+          <ex:Resource rdf:about="http:/example.com/res/1">
+            <ex:foo rdf:resource="http://example.com/res/1" />
+            <ex:bar>Literal property</ex:bar>
+          </ex:Resource>
+        </rdf:RDF>
+        )
+    g  = ROSRS::RDFGraph.new(:data ="" b)
+    stmts = []
+    g.query([nil, nil, nil]) { |s| stmts << s }
+    s1 = stmt([uri("http:/example.com/res/1"),uri("http://example.org/foo"),uri("http://example.com/res/1")])
+    s2 = stmt([uri("http:/example.com/res/1"),uri("http://example.org/bar"),lit("Literal property")])
+    assert_includes(s1, stmts)
+    assert_includes(s2, stmts)
+    stmts = []
+    g.query(:object => uri("http://example.com/res/1")) { |s| stmts << s }
+    assert_includes(s1, stmts)
+    assert_not_includes(s2, stmts)
+  end
+
+  def test_http_simple_get
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    c,r,h,b = @rosrs.do_request("GET", @rouri,
+      {:accept => "application/rdf+xml"})
+    assert_equal(303, c)
+    assert_equal("See Other", r)
+    assert_equal("application/rdf+xml", h["content-type"])
+    assert_equal("", b)
+    c,r = delete_test_research_object
+  end
+
+  def test_http_redirected_get
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    c,r,h,u,b = @rosrs.do_request_follow_redirect("GET", @rouri,
+        {:accept => "application/rdf+xml"})
+    assert_equal(200, c)
+    assert_equal("OK", r)
+    assert_equal("application/rdf+xml", h["content-type"])
+    assert_equal(Config.test_ro_uri+".ro/manifest.rdf", u.to_s)
+    #assert_match(???, b)
+    c,r = delete_test_research_object
+  end
+
+  def test_create_research_object
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    assert_equal(Config.test_ro_uri, u)
+    s = stmt([uri(Config.test_ro_uri), RDF.type, RDF::RO.ResearchObject])
+    assert_contains(s, m)
+    c,r = delete_test_research_object
+    assert_equal(204, c)
+    assert_equal("No Content", r)
+  end
+
+  def test_get_manifest
+    # [manifesturi, manifest] = get_ro_manifest(rouri)
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    # Get manifest
+    manifesturi, manifest = @rosrs.get_manifest(u)
+    assert_equal(@rouri.to_s+".ro/manifest.rdf", manifesturi.to_s)
+    # Check manifest RDF graph
+    assert_contains([uri(@rouri), RDF.type, RDF::RO.ResearchObject], manifest)
+    assert_contains([uri(@rouri), RDF::DC.creator, nil], manifest)
+    assert_contains([uri(@rouri), RDF::DC.created, nil], manifest)
+    assert_contains([uri(@rouri), RDF::ORE.isDescribedBy, uri(manifesturi)], manifest)
+  end
+
+  def test_aggregate_internal_resource
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    body    = "test_aggregate_internal_resource resource body\n"
+    options = { :body => body, :ctype => "text/plain" }
+    c, r, puri, ruri = @rosrs.aggregate_internal_resource(
+        @rouri, "test_aggregate_internal_resource", options)
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    puri_exp = Config.test_ro_uri+".ro/proxies/"
+    puri_act = puri.to_s.slice(0...puri_exp.length)
+    assert_equal(puri_exp, puri_act)
+    assert_equal(Config.test_ro_uri+"test_aggregate_internal_resource", ruri.to_s)
+    c,r = delete_test_research_object
+  end
+
+  def test_create_annotation_body
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    b = %q(
+        <rdf:RDF
+          xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+          xmlns:ex="http://example.org" >
+          <ex:Resource rdf:about="http:/example.com/res/1">
+            <ex:foo rdf:resource="http://example..com/res/1" />
+            <ex:bar>Literal property</ex:bar>
+          </ex:Resource>
+        </rdf:RDF>
+        )
+    g = ROSRS::RDFGraph.new(:data ="" b)
+    # Create an annotation body from a supplied annnotation graph.
+    # Params:  (rouri, anngr)
+    # Returns: (status, reason, bodyuri)
+    c,r,u = @rosrs.create_annotation_body(@rouri, g)
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    assert_match(%r(http://sandbox.wf4ever-project.org/rodl/ROs/TestSessionRO_ruby/), u.to_s)
+    #assert_equal(nil, u)
+    c,r = delete_test_research_object
+  end
+
+  def test_create_annotation_stub
+    # [code, reason, stuburi] = create_annotation_stub(rouri, resuri, bodyuri)
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    c,r,u = @rosrs.create_annotation_stub(@rouri,
+        "http://example.org/resource", "http://example.org/body")
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    assert_match(%r(http://sandbox.wf4ever-project.org/rodl/ROs/TestSessionRO_ruby/\.ro/), u.to_s)
+    c,r = delete_test_research_object
+  end
+
+  def test_create_internal_annotation
+    # [code, reason, annuri, bodyuri] = create_internal_annotation(rouri, resuri, anngr)
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    populate_test_research_object
+    # Create internal annotation on @res_txt
+    annbody1 = %Q(<?xml version="1.0" encoding="UTF-8"?>
+      <rdf:RDF
+         xmlns:dct="http://purl.org/dc/terms/"
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+         xml:base="address@hidden"
+      >
+        <rdf:Description rdf:about="address@hidden">
+        <dct:title>Title 1</dct:title>
+        <rdfs:seeAlso rdf:resource="http://example.org/test1" />
+        </rdf:Description>
+      </rdf:RDF>
+      )
+    agraph1 = ROSRS::RDFGraph.new(:data ="" annbody1, :format => :xml)
+    c,r,annuri,bodyuri1 = @rosrs.create_internal_annotation(
+      @rouri, @res_txt, agraph1)
+    assert_equal(201, c)
+    assert_equal("Created", r)
+    # Retrieve annotation URIs
+    auris1 = @rosrs.get_annotation_stub_uris(@rouri, @res_txt)
+    assert_includes(uri(annuri), auris1)
+    buris1 = @rosrs.get_annotation_body_uris(@rouri, @res_txt)
+    assert_includes(uri(bodyuri1), buris1)
+    # Retrieve annotation
+    c,r,auri1,agr1a = @rosrs.get_annotation_body(annuri)
+    assert_equal(200, c)
+    assert_equal("OK", r)
+    # The following test fails, due to a temp[orary redirect from the annotation
+    # body URI in the stub to the actual URI used to retrieve the body:
+    # assert_includes(auri1, buris1)
+    s1a = [uri(@res_txt), RDF::DC.title, lit("Title 1")]
+    s1b = [uri(@res_txt), RDF::RDFS.seeAlso,  uri("http://example.org/test1")]
+    assert_contains(s1a,agr1a)
+    assert_contains(s1b,agr1a)
+    # Retrieve merged annotations
+    agr1b = @rosrs.get_annotation_graph(@rouri, @res_txt)
+    assert_contains(s1a,agr1b)
+    assert_contains(s1b,agr1b)
+    # Update internal annotation
+    annbody2 = %Q(<?xml version="1.0" encoding="UTF-8"?>
+      <rdf:RDF
+        xmlns:dct="http://purl.org/dc/terms/"
+        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+        xml:base="address@hidden"
+      >
+        <rdf:Description rdf:about="address@hidden">
+        <dct:title>Title 2</dct:title>
+        <rdfs:seeAlso rdf:resource="http://example.org/test2" />
+        </rdf:Description>
+      </rdf:RDF>
+      )
+    agraph2 = ROSRS::RDFGraph.new(:data ="" annbody2, :format => :xml)
+    c,r,bodyuri2 = @rosrs.update_internal_annotation(
+      @rouri, annuri, @res_txt, agraph2)
+    assert_equal(c, 200)
+    assert_equal(r, "OK")
+    # Retrieve annotation URIs
+    auris2 = @rosrs.get_annotation_stub_uris(@rouri, @res_txt)
+    assert_includes(uri(annuri), auris2)
+    buris2 = @rosrs.get_annotation_body_uris(@rouri, @res_txt)
+    assert_includes(uri(bodyuri2), buris2)
+    # Retrieve annotation
+    c,r,auri2,agr2a = @rosrs.get_annotation_body(annuri)
+    assert_equal(c, 200)
+    assert_equal(r, "OK")
+    s2a = [uri(@res_txt), RDF::DC.title, lit("Title 2")]
+    s2b = [uri(@res_txt), RDF::RDFS.seeAlso,  uri("http://example.org/test2")]
+    assert_not_contains(s1a,agr2a)
+    assert_not_contains(s1b,agr2a)
+    assert_contains(s2a,agr2a)
+    assert_contains(s2b,agr2a)
+    # Retrieve merged annotations
+    agr2b = @rosrs.get_annotation_graph(@rouri, @res_txt)
+    assert_not_contains(s1a,agr2b)
+    assert_not_contains(s1b,agr2b)
+    assert_contains(s2a,agr2b)
+    assert_contains(s2b,agr2b)
+    # Clean up
+    c,r = delete_test_research_object
+  end
+
+  def test_create_external_annotation
+    c,r,u,m = create_test_research_object
+    assert_equal(201, c)
+    populate_test_research_object
+
+    # Create external annotation on @res_txt
+    c,r,annuri,bodyuri1 = @rosrs.create_external_annotation(@rouri, @res_txt, "http://www.example.com/something")
+    assert_equal(201, c)
+    assert_equal("Created", r)
+
+    # Retrieve annotation URIs
+    auris1 = @rosrs.get_annotation_stub_uris(@rouri, @res_txt)
+    assert_includes(uri(annuri), auris1)
+    buris1 = @rosrs.get_annotation_body_uris(@rouri, @res_txt)
+    assert_includes(uri(bodyuri1), buris1)
+
+    # Update external annotation
+    c,r,bodyuri2 = @rosrs.update_external_annotation(@rouri, annuri, @res_txt, "http://www.example.com/other")
+    assert_equal(c, 200)
+    assert_equal(r, "OK")
+
+    # Retrieve annotation URIs
+    auris2 = @rosrs.get_annotation_stub_uris(@rouri, @res_txt)
+    assert_includes(uri(annuri), auris2)
+    buris2 = @rosrs.get_annotation_body_uris(@rouri, @res_txt)
+    assert_includes(uri(bodyuri2), buris2)
+
+    # Remove annotation
+    code, reason = @rosrs.remove_annotation(annuri)
+    assert_equal(code, 204)
+
+    # Clean up
+    c,r = delete_test_research_object
+  end
+
+
+ end

reply via email to

[Prev in Thread] Current Thread [Next in Thread]