agraph 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+
2
+ module AllegroGraph
3
+
4
+ module Proxy
5
+
6
+ class Query
7
+
8
+ LANGUAGES = [ :sparql, :prolog ].freeze unless defined?(LANGUAGES)
9
+
10
+ attr_reader :server
11
+ attr_reader :resource
12
+ attr_reader :language
13
+
14
+ def initialize(resource)
15
+ @resource = resource
16
+ @language = :sparql
17
+ end
18
+
19
+ def path
20
+ @resource.path
21
+ end
22
+
23
+ def language=(value)
24
+ raise NotImplementedError, "query langauge [#{value}] is not implemented" unless LANGUAGES.include?(value.to_sym)
25
+ @language = value.to_sym
26
+ end
27
+
28
+ def perform(query)
29
+ parameters = { :query => query, :queryLn => @language.to_s }
30
+ @resource.request :get, self.path, :parameters => parameters, :expected_status_code => 200
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,59 @@
1
+
2
+ module AllegroGraph
3
+
4
+ module Proxy
5
+
6
+ class Statements
7
+
8
+ attr_reader :resource
9
+
10
+ def initialize(resource)
11
+ @resource = resource
12
+ end
13
+
14
+ def path
15
+ "#{@resource.path}/statements"
16
+ end
17
+
18
+ def create(subject, predicate, object, context = nil)
19
+ statement = [ subject, predicate, object ]
20
+ statement << context if context
21
+ @resource.request :post, self.path, :body => [ statement ], :expected_status_code => 204
22
+ true
23
+ end
24
+
25
+ def find(options = { })
26
+ parameters = { }
27
+
28
+ { :subject => :subj, :predicate => :pred, :object => :obj, :context => :context }.each do |option_key, parameter_key|
29
+ value = options[option_key]
30
+ parameters.merge! value.is_a?(Array) ?
31
+ { :"#{parameter_key}" => value[0], :"#{parameter_key}End" => value[1] } :
32
+ { parameter_key => value } if value
33
+ end
34
+
35
+ [ :offset, :limit, :infer ].each do |key|
36
+ parameters.merge! key => options[key] if options.has_key?(key)
37
+ end
38
+
39
+ parameters = nil if parameters.empty?
40
+
41
+ @resource.request :get, self.path, :parameters => parameters, :expected_status_code => 200
42
+ end
43
+
44
+ def delete(options = { })
45
+ parameters = { }
46
+
47
+ { :subject => :subj, :predicate => :pred, :object => :obj, :context => :context }.each do |option_key, parameter_key|
48
+ value = options[option_key]
49
+ parameters.merge! parameter_key => value if value
50
+ end
51
+
52
+ @resource.request :delete, self.path, :parameters => parameters, :expected_status_code => 200
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,89 @@
1
+ require File.join(File.dirname(__FILE__), "server")
2
+ require File.join(File.dirname(__FILE__), "session")
3
+ require File.join(File.dirname(__FILE__), "proxy", "statements")
4
+ require File.join(File.dirname(__FILE__), "proxy", "query")
5
+ require File.join(File.dirname(__FILE__), "proxy", "geo")
6
+ require File.join(File.dirname(__FILE__), "proxy", "mapping")
7
+
8
+ module AllegroGraph
9
+
10
+ class Repository
11
+
12
+ attr_reader :server
13
+ attr_reader :catalog
14
+ attr_accessor :name
15
+
16
+ attr_reader :statements
17
+ attr_reader :query
18
+ attr_reader :geo
19
+ attr_reader :mapping
20
+
21
+ def initialize(server_or_catalog, name, options = { })
22
+ @catalog = server_or_catalog.is_a?(AllegroGraph::Server) ? server_or_catalog.root_catalog : server_or_catalog
23
+ @server = @catalog.server
24
+ @name = name
25
+ @statements = Proxy::Statements.new self
26
+ @query = Proxy::Query.new self
27
+ @geo = Proxy::Geo.new self
28
+ @mapping = Proxy::Mapping.new self
29
+ end
30
+
31
+ def ==(other)
32
+ other.is_a?(self.class) && self.catalog == other.catalog && self.name == other.name
33
+ end
34
+
35
+ def path
36
+ "#{@catalog.path}/repositories/#{@name}"
37
+ end
38
+
39
+ def request(http_method, path, options = { })
40
+ @server.request http_method, path, options
41
+ end
42
+
43
+ def exists?
44
+ @catalog.repositories.include? self
45
+ end
46
+
47
+ def create!
48
+ @server.request :put, self.path, :expected_status_code => 204
49
+ true
50
+ rescue ExtendedTransport::UnexpectedStatusCodeError => error
51
+ return false if error.status_code == 400
52
+ raise error
53
+ end
54
+
55
+ def create_if_missing!
56
+ create! unless exists?
57
+ end
58
+
59
+ def delete!
60
+ @server.request :delete, self.path, :expected_status_code => 200
61
+ true
62
+ rescue ExtendedTransport::UnexpectedStatusCodeError => error
63
+ return false if error.status_code == 400
64
+ raise error
65
+ end
66
+
67
+ def delete_if_exists!
68
+ delete! if exists?
69
+ end
70
+
71
+ def size
72
+ response = @server.request :get, self.path + "/size", :type => :text, :expected_status_code => 200
73
+ response.to_i
74
+ end
75
+
76
+ def transaction(&block)
77
+ session = Session.create self
78
+ begin
79
+ session.instance_eval &block
80
+ rescue Object => error
81
+ session.rollback
82
+ raise error
83
+ end
84
+ session.commit
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,68 @@
1
+ require File.join(File.dirname(__FILE__), "transport")
2
+ require File.join(File.dirname(__FILE__), "catalog")
3
+ require File.join(File.dirname(__FILE__), "federation")
4
+
5
+ module AllegroGraph
6
+
7
+ # The Server class provides methods to retrieve informations about a AllegroGraph server.
8
+ class Server
9
+
10
+ attr_reader :host
11
+ attr_reader :port
12
+ attr_reader :username
13
+ attr_reader :password
14
+ attr_reader :root_catalog
15
+
16
+ def initialize(options = { })
17
+ @host = options[:host] || "localhost"
18
+ @port = options[:port] || "10035"
19
+ @username = options[:username]
20
+ @password = options[:password]
21
+
22
+ @root_catalog = Catalog.new self, "root", :root => true
23
+ end
24
+
25
+ def ==(other)
26
+ other.is_a?(self.class) && @host == other.host && @port == other.port
27
+ end
28
+
29
+ def request(http_method, path, options = { })
30
+ ExtendedTransport.request http_method, self.url + path, credentials.merge(options)
31
+ end
32
+
33
+ def version
34
+ {
35
+ :version => self.request(:get, "/version", :expected_status_code => 200),
36
+ :date => self.request(:get, "/version/date", :expected_status_code => 200),
37
+ :revision => self.request(:get, "/version/revision", :expected_status_code => 200)
38
+ }
39
+ end
40
+
41
+ def catalogs
42
+ result = [ @root_catalog ]
43
+ catalogs = self.request :get, "/catalogs", :expected_status_code => 200
44
+ catalogs.each do |catalog|
45
+ id = catalog["id"]
46
+ result << Catalog.new(self, id.sub(/^\//, "")) unless id == "/"
47
+ end
48
+ result
49
+ end
50
+
51
+ def federations
52
+ federations = self.request :get, "/federated", :expected_status_code => 200
53
+ federations.map { |federation| Federation.new self, federation["id"] }
54
+ end
55
+
56
+ def url
57
+ "http://#{@host}:#{@port}"
58
+ end
59
+
60
+ private
61
+
62
+ def credentials
63
+ { :auth_type => :basic, :username => @username, :password => @password }
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,64 @@
1
+ require File.join(File.dirname(__FILE__), "transport")
2
+ require File.join(File.dirname(__FILE__), "proxy", "statements")
3
+ require File.join(File.dirname(__FILE__), "proxy", "query")
4
+ require File.join(File.dirname(__FILE__), "proxy", "geo")
5
+ require File.join(File.dirname(__FILE__), "proxy", "mapping")
6
+
7
+ module AllegroGraph
8
+
9
+ class Session
10
+
11
+ attr_reader :url
12
+ attr_reader :username
13
+ attr_reader :password
14
+
15
+ attr_reader :statements
16
+ attr_reader :query
17
+ attr_reader :geo
18
+ attr_reader :mapping
19
+
20
+ def initialize(options = { })
21
+ @url = options[:url]
22
+ @username = options[:username]
23
+ @password = options[:password]
24
+
25
+ @statements = Proxy::Statements.new self
26
+ @query = Proxy::Query.new self
27
+ @geo = Proxy::Geo.new self
28
+ @mapping = Proxy::Mapping.new self
29
+ end
30
+
31
+ def path
32
+ ""
33
+ end
34
+
35
+ def request(http_method, path, options = { })
36
+ ExtendedTransport.request http_method, self.url + path, credentials.merge(options)
37
+ end
38
+
39
+ def commit
40
+ self.request :post, "/commit", :expected_status_code => 204
41
+ true
42
+ end
43
+
44
+ def rollback
45
+ self.request :post, "/rollback", :expected_status_code => 204
46
+ true
47
+ end
48
+
49
+ def self.create(repository)
50
+ url = repository.request :post, repository.path + "/session", :expected_status_code => 200
51
+ url.sub! /^"/, ""
52
+ url.sub! /"$/, ""
53
+ new :url => url, :username => repository.server.username, :password => repository.server.password
54
+ end
55
+
56
+ private
57
+
58
+ def credentials
59
+ { :auth_type => :basic, :username => @username, :password => @password }
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,169 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/http'
4
+ require 'base64'
5
+ require 'json'
6
+
7
+ module AllegroGraph
8
+
9
+ # Common transport layer for http transfers.
10
+ class Transport
11
+
12
+ attr_reader :http_method
13
+ attr_reader :url
14
+ attr_reader :options
15
+ attr_reader :headers
16
+ attr_reader :parameters
17
+ attr_reader :body
18
+ attr_reader :response
19
+
20
+ def initialize(http_method, url, options = { })
21
+ @http_method = http_method
22
+ @uri = URI.parse url
23
+ @headers = options[:headers] || { }
24
+ @parameters = options[:parameters] || { }
25
+ @body = options[:body]
26
+ end
27
+
28
+ def perform
29
+ initialize_request_class
30
+ initialize_request_path
31
+ initialize_request
32
+ initialize_request_body
33
+ perform_request
34
+ end
35
+
36
+ private
37
+
38
+ def initialize_request_class
39
+ request_class_name = @http_method.capitalize
40
+ raise NotImplementedError, "the request method #{http_method} is not implemented" unless Net::HTTP.const_defined?(request_class_name)
41
+ @request_class = Net::HTTP.const_get request_class_name
42
+ end
43
+
44
+ def initialize_request_path
45
+ serialize_parameters
46
+ @request_path = @uri.path + @serialized_parameters
47
+ end
48
+
49
+ def serialize_parameters
50
+ quote_parameters
51
+ @serialized_parameters = if @parameters.nil? || @parameters.empty?
52
+ ""
53
+ else
54
+ "?" + @quoted_parameters.collect do |key, value|
55
+ value.is_a?(Array) ?
56
+ value.map{ |element| "#{key}=#{element}" }.join("&") :
57
+ "#{key}=#{value}"
58
+ end.join("&")
59
+ end
60
+ end
61
+
62
+ def quote_parameters
63
+ @quoted_parameters = { }
64
+ @parameters.each do |key, value|
65
+ if value.is_a?(Array)
66
+ @quoted_parameters[ CGI.escape("#{key}") ] = value.map{ |element| CGI.escape element }
67
+ else
68
+ @quoted_parameters[ CGI.escape("#{key}") ] = CGI.escape value
69
+ end
70
+ end
71
+ end
72
+
73
+ def initialize_request
74
+ @request = @request_class.new @request_path, @headers
75
+ end
76
+
77
+ def initialize_request_body
78
+ return unless [ :post, :put ].include?(@http_method.to_sym)
79
+ @request.body = @body ? @body : @serialized_parameters.sub(/^\?/, "")
80
+ end
81
+
82
+ def perform_request
83
+ @response = Net::HTTP.start(@uri.host, @uri.port) do |connection|
84
+ connection.request @request
85
+ end
86
+ end
87
+
88
+ def self.request(http_method, url, options = { })
89
+ transport = new http_method, url, options
90
+ transport.perform
91
+ transport.response
92
+ end
93
+
94
+ end
95
+
96
+ class ExtendedTransport < Transport
97
+
98
+ # The UnexpectedStatusCodeError is raised if the :expected_status_code option is given to
99
+ # the :request method and the responded status code is different from the expected one.
100
+ class UnexpectedStatusCodeError < StandardError
101
+
102
+ attr_reader :status_code
103
+ attr_reader :message
104
+
105
+ def initialize(status_code, message)
106
+ @status_code, @message = status_code, message
107
+ end
108
+
109
+ def to_s
110
+ "#{super} received status code #{self.status_code}" + (@message ? " [#{@message}]" : "")
111
+ end
112
+
113
+ end
114
+
115
+ attr_reader :expected_status_code
116
+ attr_reader :auth_type
117
+ attr_reader :username
118
+ attr_reader :password
119
+
120
+ def initialize(http_method, url, options = { })
121
+ super http_method, url, options
122
+ @expected_status_code = options[:expected_status_code]
123
+ @auth_type = options[:auth_type]
124
+ @username = options[:username]
125
+ @password = options[:password]
126
+ end
127
+
128
+ def perform
129
+ initialize_headers
130
+ super
131
+ check_status_code
132
+ parse_response
133
+ end
134
+
135
+ private
136
+
137
+ def initialize_headers
138
+ if @auth_type == :basic
139
+ @headers["Authorization"] = "Basic " + Base64.encode64("#{@username}:#{@password}")
140
+ elsif !@auth_type.nil?
141
+ raise NotImplementedError, "the given auth_type [#{@auth_type}] is not implemented"
142
+ end
143
+ @headers["Accept"] = "application/json"
144
+ end
145
+
146
+ def initialize_request_body
147
+ super
148
+ if @body
149
+ @request.body = @body.to_json
150
+ @request["Content-Type"] = "application/json"
151
+ end
152
+ end
153
+
154
+ def check_status_code
155
+ return unless @expected_status_code
156
+ response_code = @response.code
157
+ response_body = @response.body
158
+ raise UnexpectedStatusCodeError.new(response_code.to_i, response_body) if @expected_status_code.to_s != response_code
159
+ end
160
+
161
+ def parse_response
162
+ @response = @response.body.nil? ? nil : JSON.parse(@response.body)
163
+ rescue JSON::ParserError
164
+ @response = @response.body.to_s
165
+ end
166
+
167
+ end
168
+
169
+ end