root/Explorator/trunk/vendor/plugins/activerdf_sparql-1.3.6/lib/activerdf_sparql/sparql.rb @ 450

Revision 450, 6.2 KB (checked in by samuraraujo, 9 years ago)
Line 
1require 'active_rdf'
2require 'queryengine/query2sparql'
3require 'open-uri'
4require 'cgi'
5require 'rexml/document'
6require "#{File.dirname(__FILE__)}/sparql_result_parser"
7
8# SPARQL adapter
9class SparqlAdapter < ActiveRdfAdapter
10  $activerdflog.info "loading SPARQL adapter"
11  ConnectionPool.register_adapter(:sparql, self) 
12  attr_reader :engine
13  attr_reader :caching , :url 
14  def reset_cache()     
15    @sparql_cache = {}
16  end
17  #  def SparqlAdapter.get_cache
18  #    return @sparql_cache
19  #  end
20 
21  # Instantiate the connection with the SPARQL Endpoint.
22  # available parameters:
23  # * :url => url: endpoint location e.g. "http://m3pe.org:8080/repositories/test-people"
24  # * :results => one of :xml, :json, :sparql_xml
25  # * :request_method => :get (default) or :post
26  # * :timeout => timeout in seconds to wait for endpoint response
27  # * :auth => [user, pass]
28  def initialize(params = {})   
29    super() 
30    @sparql_cache = {}
31    @reads = true
32    @writes = false
33    @title =params[:title] 
34    @url = params[:url] || ''
35    @caching = params[:caching] || false
36    @timeout = params[:timeout] || 100
37    @auth = params[:auth] || nil
38   
39    @result_format = params[:results] || :json
40    raise ActiveRdfError, "Result format unsupported" unless [:xml, :json, :sparql_xml].include? @result_format
41   
42   
43    @engine = params[:engine]
44    if @engine == nil
45      response = Net::HTTP.get_response(URI.parse(@url))   
46      if  response['server'].to_s.downcase.index('virtuoso') != nil 
47        @engine = :virtuoso 
48      else
49        @engine = :sesame2 
50      end
51    end 
52    raise ActiveRdfError, "SPARQL engine unsupported" unless [:yars2, :sesame2, :joseki, :virtuoso].include? @engine
53   
54    @request_method = params[:request_method] || :get
55    raise ActiveRdfError, "Request method unsupported" unless [:get,:post].include? @request_method
56  end
57 
58  def size
59    query(Query.new.select(:s,:p,:o).where(:s,:p,:o)).size
60  end
61 
62  # query datastore with query string (SPARQL), returns array with query results
63  # may be called with a block
64  def query(query, &block)   
65    qs = Query2SPARQL.translate(query,@engine)
66   
67    if @caching 
68      if is_into_cache(qs) 
69        $activerdflog.debug "cache hit for query #{qs}"
70        return  query_cache(qs)
71      end
72    end   
73   
74    result = execute_sparql_query(qs, header(query), &block)
75    add_to_cache(qs, result) if @caching
76    result = [] if result == "timeout"
77 
78    return result
79  end
80 
81  # do the real work of executing the sparql query
82  def execute_sparql_query(qs, header=nil, &block)
83    header = header(nil) if header.nil?
84   
85    # querying sparql endpoint
86    require 'timeout'
87    response = ''
88    url =''
89    begin 
90      case @request_method
91        when :get
92        # encoding query string in URL
93        if @url.index('?') == nil
94          url = "#@url?query=#{CGI.escape(qs)}"       
95        else
96          url = "#@url&query=#{CGI.escape(qs)}"         
97        end
98        #puts url
99        $activerdflog.debug "GET #{url}"       
100        timeout(@timeout) do         
101          # puts url
102          open(url, header) do |f|           
103            response = f.read   
104            #              puts response
105          end
106        end
107        when :post
108        $activerdflog.debug "POST #@url with #{qs}"
109        response = Net::HTTP.post_form(URI.parse(@url),{'query'=>qs}).body       
110      end
111      #puts response
112    rescue Timeout::Error
113      raise ActiveRdfError, "timeout on SPARQL endpoint. <br><br><b>URI accessed:</b> " + url
114      return "timeout"
115    rescue OpenURI::HTTPError => e
116      raise ActiveRdfError, "could not query SPARQL endpoint, server said: #{e} . <br><br><b>URI accessed:</b> " + url
117      return []
118    rescue Errno::ECONNREFUSED
119      raise ActiveRdfError, "connection refused on SPARQL endpoint #@url"
120      return []
121    end
122   
123    # we parse content depending on the result format
124   
125    results = case @result_format
126      when :json 
127      parse_json(response)
128      when :xml, :sparql_xml
129      parse_xml(response)
130    end
131   
132    if block_given?
133      results.each do |*clauses|
134        yield(*clauses)
135      end
136    else     
137      results
138    end
139  end   
140  def close
141    ConnectionPool.remove_data_source(self)
142  end   
143  protected
144  def add_to_cache(query_string, result)
145    if result.nil? or result.empty?
146      @sparql_cache.store(query_string, [])
147    else
148      if result == "timeout"
149        @sparql_cache.store(query_string, [])
150      else 
151        $activerdflog.debug "adding to sparql cache - query: #{query_string}"
152        @sparql_cache.store(query_string, result) 
153      end
154    end
155  end 
156  def is_into_cache(query_string)
157    @sparql_cache.include?(query_string)     
158  end
159  def query_cache(query_string)         
160    return @sparql_cache.fetch(query_string)   
161  end
162 
163  # constructs correct HTTP header for selected query-result format
164  def header(query)
165    header = case @result_format
166      when :json
167      { 'accept' => 'application/sparql-results+json' }
168      when :xml
169      { 'accept' => 'application/rdf+xml' }
170      when :sparql_xml
171      { 'accept' => 'application/sparql-results+xml' }
172    end
173    if @auth
174      header.merge( :http_basic_authentication => @auth )
175    else
176      header
177    end
178  end
179 
180  # parse json query results into array
181  def parse_json(s)
182    # this will try to first load json with the native c extensions,
183    # and if this fails json_pure will be loaded
184    require 'json'
185   
186    parsed_object = JSON.parse(s)
187    return [] if parsed_object.nil?
188   
189    results = []   
190    vars = parsed_object['head']['vars']
191    objects = parsed_object['results']['bindings']
192   
193    objects.each do |obj|
194      result = []
195      vars.each do |v|
196        result << create_node( obj[v]['type'], obj[v]['value'])
197      end
198      results << result
199    end
200   
201    results
202  end
203 
204  # parse xml stream result into array
205  def parse_xml(s)   
206    parser = SparqlResultParser.new
207    REXML::Document.parse_stream(s, parser) 
208    parser.result
209  end 
210  # create ruby objects for each RDF node
211  def create_node(type, value)
212    case type
213      when 'uri'
214      RDFS::Resource.new(value)
215      when 'bnode'
216      BNode.new(value)
217      when 'literal','typed-literal'
218      value.to_s
219    end
220  end   
221end
Note: See TracBrowser for help on using the browser.