Module: ActiveRubic
- Defined in:
- lib/active_rubic.rb,
lib/active_rubic.rb,
lib/active_rubic/base.rb,
lib/active_rubic/cacher.rb
Overview
ActiveRubic emulates ActiveRecord and provides connections to several data stores with the objective to abstract the semantic data from various engines.
The engines are also attempted to be drop-in replaceable by offering an abstraction method find(). see ActiveRubic::Base for the API reference.
-
some of it is still undocumented!!
The supported backends currently include:
-
ActiveRecord
-
ActiveRubinstein
This module abstracts the query methods (SPARQL, graph handling, SQL, Lucene index) to parameters so that different storages can be “hot-replaced” without the need to make changes to the request.
ActiveRubinstein::Base is the API which translates queries to the servers which are supported by the Rubinstein backend, which replies to queries over the DRb bridge. This also makes possible to use Java-based repositories with JRuby without running the whole Rails stack on JRuby.
- Authors
-
Mikael Lammentausta, Lauri Miettinen
- Copyright
-
Copyright © 2007-2008 Savonia University of Applied Sciences
- License
-
MIT
Examples
In this example we’ll inspect the instance of the Museum of natural history of Kuopio, Finland. Launch up the Rails console:
$ ./script/console
Loading development environment.
RUBIC log/irb: * Initializing ActiveRubic, version 0.76
RUBIC log/irb: => loading ActiveRubinstein
RUBIC log/irb: => loading ActiveRubic
RUBIC log/irb: * Rails environment already initialized
DEBUG log/irb: => including ActiveRubinstein to ActiveRubic::Base
RUBIC log/irb: * loading ActiveRDF extensions
DEEP log/irb: Formulating new RDFS::Resource http://www.w3.org/2000/01/rdf-schema#Resource from String
DEEP log/irb: Formulating new RDFS::Resource http://openlab/media#image from String
DEEP log/irb: Formulating new RDFS::Resource http://www.w3.org/2002/07/owl#Class from String
DEEP log/irb: Formulating new RDFS::Resource http://www.w3.org/2002/07/owl#Thing from String
DEEP log/irb: Formulating new RDFS::Resource http://www.w3.org/2002/07/owl#ObjectProperty from String
RUBINSTEIN log/irb: * initializing JenaEndpoint: druby://192.168.0.11:2002
DEBUG log/irb: #<DRb::DRbObject:0xb6e0ed0c @ref=nil, @uri="druby://192.168.0.11:2002">
DEBUG log/irb: => reply from server: Greetings -- this is jRubinstein#JenaLuc/Picard 0.84 on 192.168.0.11:2002, PID 20471808
RUBINSTEIN log/irb: => added #<ActiveRubinstein::JenaEndpoint:0xb6e0edfc @uri="druby://192.168.0.11:2002"> to pool
INFO log/irb: @@jena = #<ActiveRubinstein::JenaEndpoint:0xb6e0edfc @uri="druby://192.168.0.11:2002">
INFO log/irb: @@lucene = #<ActiveRubinstein::JenaEndpoint:0xb6e0edfc @uri="druby://192.168.0.11:2002">
If everything is fine, fire up a simple query for label:
resource = KUOPIO::kuopion_museo
=> #<RDFS::Resource:0xb6ef1fa8 @uri="http://openlab/kuopio#kuopion_museo">
resource.label
=> ["Kuopion museo"]
How does this data get from Jena to Rails’ console? Let’s inspect the entire data passage.
First of all, the label method looks like this:
class class RDFS::Resource
def label
if @label.nil?
@label = my( RDFS::label )
end
return @label
end
end
It calls the private ‘my’ method within the model:
private
### helper
def my( predicate )
if predicate.is_a? String then
predicate = RDFS::Resource.new( predicate )
end
begin
@@log.debug " => find #{self.uri} #{predicate} ?"
ActiveRubic::Base.find( predicate, :subject => self.uri,
:from => RUBIC_DATASTORES,
:lang => @language
) || Array.new
rescue
@@log.error $!
return Array.new
end
end
Which calls the ActiveRubic::Base find() method with the subject, required predicate, and options for used data stores as well as the desired language. The find() method and the following data flow, many lines are removed to simplify the logic behind the module:
module ActiveRubic #:nodoc:
class Base
class << self # Class methods
def find(*args)
# options:
# :data_stores = Array
# :suffice_to = Array of data_stores that are trusted to return sufficient results. By default all data stores are untrusted to be complete, and the results of each are combined. The results of servers given in the array
# :combine = Array of data stores that are queried and the results combined. If the trusted server returns results, trust that the contents is sufficient.
options = extract_options_from_args!(args)
serial_query_handler( args.first, options )
end
private
# runs a query on data stores sequentially
def serial_query_handler(query, options)
begin
data_stores.each do |storage|
my_results = run_query( storage, query, options )
end
end
# merge and return results
end
# constructs the actual queries and receives the result
def run_query( storage, query, options )
case storage
when :jena
ActiveRubinstein::JenaQuery.execute( query, options )
end
end
end
end
end
end
The ActiveRubinstein::JenaQuery class, and ActiveRubic in general, accepts three types of ‘query’ objects:
-
Symbol for actions, eg. :parents, :children, :nearby, :properties etc.
-
RDFS::Resource (predicate) with the option :subject => uri, to fetch the object, as in the RDFS::label example
-
Query, an ActiveRDF object, as a block without the .execute call
Let’s examine the JenaQuery class:
module ActiveRubinstein #:nodoc:
class JenaQuery < ActiveRubinstein::Base
class << self
public
def execute( query, options )
if query.is_a? Symbol or query.is_a? RDFS::Resource
case query
# ... process some symbols
else # construct common SPARQL
sparql = ActiveRubinstein::Base.construct_sparql( query, options )
self.query( sparql, options ) if sparql
end
end
end
private
# pretty much the most important method of all :)
# this method sends the request to Rubinstein's DRb server.
def method_missing(method, *args, &block)
@@log.rubinstein "sending the request to DRb server, method #{method}"
@@jena.send( method, *args, &block )
end
end
end
end
@@jena variable is instantiated in ActiveRubinstein::Base:
module ActiveRubinstein #:nodoc:
class Base
def shuffle # Initialization of servers
$serverPool = {} unless defined? $serverPool
RUBIC_DATASTORES.each do |adapter|
case adapter
when :jena
server = JenaEndpoint.new
if server.ping
$serverPool.update :jena => [ server ]
@@log.rubinstein " => added #{server.inspect} to pool"
end
end
end
end
end
# create the server pool, start the DRb service, and
# init the required submodules, so that the correct service is
# accessible as a class variable
def initialize
self.shuffle unless defined? $serverPool
DRb.start_service
RUBIC_DATASTORES.each do |adapter|
case adapter
##############################
when :jena
# instantiate the server for the JenaQuery class
ActiveRubinstein::JenaQuery.new
end
end
end
end
end
end
module ActiveRubinstein #:nodoc:
class JenaQuery < ActiveRubinstein::Base
def initialize
server = $serverPool[ :jena ].first
unless server.ping
@@log.error $!.message
else
@@jena = server
@@log.info "@@jena = #{server.inspect}"
end
end
end
end
Finally, here is the log of the query:
DEEP log/irb: Formulating new RDFS::Resource http://www.w3.org/2000/01/rdf-schema#label from String
DEBUG log/irb: => find http://openlab/kuopio#kuopion_museo <http://www.w3.org/2000/01/rdf-schema#label> ?
RUBIC log/irb: * Find: <http://www.w3.org/2000/01/rdf-schema#label>, fromjenalucenesubject<http://openlab/kuopio#kuopion_museo>lang
DEEP log/irb: => Querying data stores: jena, lucene
DEEP log/irb: - Will suffice to data from lucene
RUBIC log/irb: => query: <http://www.w3.org/2000/01/rdf-schema#label> (RDFS::Resource)
RUBINSTEIN log/irb: Constructing SPARQL, options: data_storesjenalucenefromjenalucenesubject<http://openlab/kuopio#kuopion_museo>lang
DEBUG log/irb: => constructing Query to find <http://www.w3.org/2000/01/rdf-schema#label>
DEEP log/irb: Constructing SPARQL <http://openlab/kuopio#kuopion_museo> <http://www.w3.org/2000/01/rdf-schema#label> ?
RUBINSTEIN log/irb: sending the request to DRb server, method query
RUBIC log/irb: => Got 1 results from jena in 0.00976 sec
RUBIC log/irb: => query: <http://www.w3.org/2000/01/rdf-schema#label> (RDFS::Resource)
RUBIC log/irb: => No results from lucene in 0.00015 sec
DEEP log/irb: => 1 altogether
RUBIC log/irb: => TOTAL: 1 unique results
DEEP log/irb: => Returning all 1, no limit
=> ["Kuopion museo"]
Defined Under Namespace
Classes: ActiveRubicError, AdapterNotFoundError, AdapterNotSpecifiedError, Base, Cacher, ConnectionFailedError, ConnectionNotEstablishedError, RubicNotFoundError
Constant Summary collapse
- VERSION =
'0.8.2'