rgeoserver 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+
2
+ module RGeoServer
3
+ module GeoServerUrlHelpers
4
+ API_DOCUMENTATION = "http://docs.geoserver.org/latest/en/user/restconfig/rest-config-api.html"
5
+
6
+ def url_for base, options = nil
7
+ return base unless options.is_a? Hash
8
+ format = options.delete(:format) || 'xml'
9
+ new_base = base.map{ |key,value| value.nil?? key.to_s : [key.to_s, CGI::escape(value.to_s)].join("/") }.join("/")
10
+ new_base = new_base.gsub(/\/$/,'')
11
+ new_base += ".#{format}"
12
+ "#{new_base}" + (("?#{options.map { |key, value| "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"}.join("&") }" if options and not options.empty?) || '')
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,140 @@
1
+
2
+ module RGeoServer
3
+
4
+ class ResourceInfo
5
+
6
+ include ActiveModel::Dirty
7
+ extend ActiveModel::Callbacks
8
+
9
+ define_model_callbacks :save, :destroy
10
+ define_model_callbacks :initialize, :only => :after
11
+
12
+ # mapping object parameters to profile elements
13
+ OBJ_ATTRIBUTES = {:enabled => 'enabled'}
14
+ OBJ_DEFAULT_ATTRIBUTES = {:enabled => true}
15
+
16
+ define_attribute_methods OBJ_ATTRIBUTES.keys
17
+
18
+ def self.update_attribute_accessors attributes
19
+ attributes.each do |attribute, profile_name|
20
+ class_eval <<-RUBY
21
+ def #{attribute.to_s}
22
+ @#{attribute} || profile['#{profile_name.to_s}'] || OBJ_DEFAULT_ATTRIBUTES[:#{attribute}]
23
+ end
24
+
25
+ def #{attribute.to_s}= val
26
+ #{attribute.to_s}_will_change! unless val == #{attribute.to_s}
27
+ @#{attribute.to_s} = val
28
+ end
29
+ RUBY
30
+ end
31
+ end
32
+
33
+ def initialize options
34
+ @new = true
35
+ end
36
+
37
+ def to_s
38
+ "#{self.class.name}: #{name}"
39
+ end
40
+
41
+ # Add resource to Geoserver catalog
42
+ def self.create options, catalog = nil
43
+ raise GeoServerInvalidRequest, "Can't create a #{self.class.resource_name} resource with empty name" if options[:name].nil?
44
+ catalog ||= RGeoServer.catalog
45
+ catalog.add @route, xml(options)
46
+ self.class.new catalog, options
47
+ end
48
+
49
+ # Modify or save the resource
50
+ # @param options [Hash]
51
+ # @return [RGeoServer::ResourceInfo]
52
+ def save options = {}
53
+ @previously_changed = changes
54
+ @changed_attributes.clear
55
+ run_callbacks :save do
56
+ if new?
57
+ @catalog.add(@route, message)
58
+ clear
59
+ else
60
+ @catalog.modify({@route => @name}, message) #unless changes.empty?
61
+ end
62
+
63
+ self
64
+ end
65
+ end
66
+
67
+ # Purge resource from Geoserver Catalog
68
+ # @param options [Hash]
69
+ # @return [RGeoServer::ResourceInfo] `self`
70
+ def delete options = {}
71
+ run_callbacks :destroy do
72
+ @catalog.purge({@route => @name}, options) unless new?
73
+ clear
74
+ self
75
+ end
76
+ end
77
+
78
+ # Check if this resource already exists
79
+ # @return [Boolean]
80
+ def new?
81
+ profile
82
+ @new
83
+ end
84
+
85
+ def clear
86
+ @profile = nil
87
+ @changed_attributes = {}
88
+ end
89
+
90
+ # Retrieve the resource profile as a hash and cache it
91
+ # @return [Hash]
92
+ def profile
93
+ if @profile
94
+ return @profile
95
+ end
96
+
97
+ @profile ||= begin
98
+ h = profile_xml_to_hash(@catalog.search @route => @name )
99
+ @new = false
100
+ h
101
+ rescue RestClient::ResourceNotFound
102
+ # The resource is new
103
+ @new = true
104
+ {}
105
+ end.freeze
106
+ end
107
+
108
+ def profile= profile_xml
109
+ @profile = profile_xml_to_hash(profile_xml)
110
+ end
111
+
112
+ def profile_xml_to_ng profile_xml
113
+ Nokogiri::XML(profile_xml).xpath(self.class.member_xpath)
114
+ end
115
+
116
+ def profile_xml_to_hash profile_xml
117
+ doc = profile_xml_to_ng profile_xml
118
+ h = {'name' => doc.at_xpath('//name').text.strip, 'enabled' => @enabled }
119
+ doc.xpath('//atom:link/@href', "xmlns:atom"=>"http://www.w3.org/2005/Atom" ).each{ |l|
120
+ target = l.text.match(/([a-zA-Z]+)\.xml$/)[1]
121
+ if !target.nil? && target != l.parent.parent.name.to_s.downcase
122
+ begin
123
+ h[l.parent.parent.name.to_s] << target
124
+ rescue
125
+ h[l.parent.parent.name.to_s] = []
126
+ end
127
+ else
128
+ h[l.parent.parent.name.to_s] = begin
129
+ response = @catalog.fetch_url l.text
130
+ Nokogiri::XML(response).xpath('//name/text()').collect{ |a| a.text }
131
+ rescue RestClient::ResourceNotFound
132
+ []
133
+ end.freeze
134
+ end
135
+ }
136
+ h
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,103 @@
1
+
2
+ require 'logger'
3
+ $logger = Logger.new(STDOUT)
4
+ $logger.level = Logger::WARN
5
+
6
+
7
+ module RGeoServer
8
+ module RestApiClient
9
+
10
+ include RGeoServer::GeoServerUrlHelpers
11
+ include ActiveSupport::Benchmarkable
12
+
13
+ def client config = {}
14
+ c = self.config.merge(config)
15
+ @client ||= RestClient::Resource.new(c[:url], :user => c[:user], :password => c[:password], :headers => c[:headers])
16
+ end
17
+
18
+ def headers format
19
+ sym = :xml || format.to_sym
20
+ {:accept => sym, :content_type=> sym}
21
+ end
22
+
23
+ # Search a resource in the catalog
24
+ # @param [OrderedHash] what
25
+ # @param [Hash] options
26
+ def search what, options = {}
27
+ resources = client[url_for(what, options)]
28
+ resources.options[:headers] ||= headers(:xml)
29
+ begin
30
+ return resources.get
31
+ rescue RestClient::InternalServerError => e
32
+ $logger.error e.response
33
+ $logger.flush if $logger.respond_to? :flush
34
+ raise GeoServerInvalidRequest, "Error listing #{what.inspect}. See $logger for details"
35
+ end
36
+ end
37
+
38
+ # Fetch an arbitrary URL within the catalog
39
+ # @param [String] url
40
+ def fetch_url url
41
+ url.slice! client.url
42
+ fetcher = client[url]
43
+ fetcher.options[:headers] ||= headers(:xml)
44
+ begin
45
+ return fetcher.get
46
+ rescue RestClient::InternalServerError => e
47
+ $logger.error e.response
48
+ $logger.flush if $logger.respond_to? :flush
49
+ raise GeoServerInvalidRequest, "Error fetching URL: #{url}. See $logger for details"
50
+ end
51
+
52
+ end
53
+
54
+ # Add resource to the catalog
55
+ # @param [String] what
56
+ # @param [String] message
57
+ # @param [Symbol] method
58
+ def add what, message, method = :post
59
+ request = client[url_for(what)]
60
+ request.options[:headers] ||= headers(:xml)
61
+ begin
62
+ return request.send method, message
63
+ rescue RestClient::InternalServerError => e
64
+ $logger.error e.response
65
+ $logger.flush if $logger.respond_to? :flush
66
+ raise GeoServerInvalidRequest, "Error adding #{what.inspect}. See logger for details"
67
+ end
68
+
69
+ end
70
+
71
+ # Modify resource in the catalog
72
+ # @param [String] what
73
+ # @param [String] message
74
+ def modify what, message
75
+ request = client[url_for(what, {})]
76
+ request.options[:headers] ||= headers(:xml)
77
+ $logger.debug "Modifying: \n #{message}"
78
+ begin
79
+ return request.put message
80
+ rescue RestClient::InternalServerError => e
81
+ $logger.error e.response
82
+ $logger.flush if $logger.respond_to? :flush
83
+ raise GeoServerInvalidRequest, "Error modifying #{what.inspect}. See $logger for details"
84
+ end
85
+
86
+ end
87
+
88
+ # Purge resource from the catalog. Options can include recurse=true or false
89
+ # @param [OrderedHash] what
90
+ # @param [Hash] options
91
+ def purge what, options
92
+ request = client[url_for(what, options)]
93
+ begin
94
+ return request.delete
95
+ rescue RestClient::InternalServerError => e
96
+ $logger.error e.response
97
+ $logger.flush if $logger.respond_to? :flush
98
+ raise GeoServerInvalidRequest, "Error deleting #{what.inspect}. See $logger for details"
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,9 @@
1
+ module RGeoServer
2
+ unless RGeoServer.const_defined? :VERSION
3
+ def self.version
4
+ @version ||= File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION')).chomp
5
+ end
6
+
7
+ VERSION = self.version
8
+ end
9
+ end
@@ -0,0 +1,100 @@
1
+
2
+ module RGeoServer
3
+
4
+ class WmsStore < ResourceInfo
5
+
6
+ define_attribute_methods [:catalog, :workspace, :name]
7
+
8
+ @@r = Confstruct::Configuration.new(
9
+ :route => "workspaces/%s/wmsstores",
10
+ :root => "wmsStores",
11
+ :resource_name => "wmsStore"
12
+ )
13
+
14
+ def self.root
15
+ @@r.root
16
+ end
17
+
18
+ def self.method
19
+ :put
20
+ end
21
+
22
+ def self.resource_name
23
+ @@r.resource_name
24
+ end
25
+
26
+ def self.root_xpath
27
+ "//#{root}/#{resource_name}"
28
+ end
29
+
30
+ def self.member_xpath
31
+ "//#{resource_name}"
32
+ end
33
+
34
+ def route
35
+ @@r.route % @workspace.name
36
+ end
37
+
38
+ def xml options = nil
39
+ <<-cs
40
+ <wmsStore>
41
+ <enabled>true</enabled>
42
+ <name>#{name}</name>
43
+ <workspace><name>#{workspace_name}</name></workspace>
44
+ </wmsStore>
45
+ cs
46
+ end
47
+
48
+ def name
49
+ @name
50
+ end
51
+
52
+ def workspace
53
+ @workspace
54
+ end
55
+
56
+ def catalog
57
+ @catalog
58
+ end
59
+
60
+ def workspace_name
61
+ @workspace.name
62
+ end
63
+
64
+ # @param [RGeoServer::Catalog] catalog
65
+ # @param [RGeoServer::Workspace|String] workspace
66
+ # @param [String] name
67
+ def initialize catalog, options
68
+ super({})
69
+ _run_initialize_callbacks do
70
+ @catalog = catalog
71
+ workspace = options[:workspace] || 'default'
72
+ if workspace.instance_of? String
73
+ @workspace = @catalog.get_workspace(workspace)
74
+ elsif workspace.instance_of? Workspace
75
+ @workspace = workspace
76
+ else
77
+ raise "Not a valid workspace"
78
+ end
79
+ @name = options[:name].strip
80
+ @route = route
81
+ end
82
+ end
83
+
84
+ def name= val
85
+ name_will_change! unless val == @name
86
+ @name = val
87
+ end
88
+
89
+ def workspace= val
90
+ workspace_will_change! unless val == @workspace
91
+ @workspace = val
92
+ end
93
+
94
+ def catalog= val
95
+ catalog_will_change! unless val == @catalog
96
+ @catalog = val
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,74 @@
1
+
2
+ module RGeoServer
3
+
4
+ class Workspace < ResourceInfo
5
+
6
+ OBJ_ATTRIBUTES = {:enabled => 'enabled', :catalog => 'catalog', :name => 'name' }
7
+ OBJ_DEFAULT_ATTRIBUTES = {:enabled => true, :catalog => nil, :name => nil }
8
+
9
+ define_attribute_methods OBJ_ATTRIBUTES.keys
10
+ update_attribute_accessors OBJ_ATTRIBUTES
11
+
12
+ @@r = Confstruct::Configuration.new(:route => 'workspaces', :resource_name => 'workspace')
13
+
14
+ def self.resource_name
15
+ @@r.resource_name
16
+ end
17
+
18
+ def self.method
19
+ :post
20
+ end
21
+
22
+ def self.root_xpath
23
+ "//#{@@r.route}/#{@@r.resource_name}"
24
+ end
25
+
26
+ def self.member_xpath
27
+ "//#{resource_name}"
28
+ end
29
+
30
+ def route
31
+ @@r.route
32
+ end
33
+
34
+ def message
35
+ builder = Nokogiri::XML::Builder.new do |xml|
36
+ xml.workspace {
37
+ xml.enabled @enabled if enabled_changed?
38
+ xml.name @name
39
+ }
40
+ end
41
+ return builder.doc.to_xml
42
+ end
43
+
44
+ # @param [RGeoServer::Catalog] catalog
45
+ # @param [Hash] options
46
+ def initialize catalog, options
47
+ super({})
48
+ _run_initialize_callbacks do
49
+ @catalog = catalog
50
+ @name = options[:name].strip
51
+ end
52
+ @route = route
53
+ end
54
+
55
+ def data_stores
56
+ profile['dataStores'].collect{ |name|
57
+ DataStore.new @catalog, :workspace => self, :name => name if name
58
+ }
59
+ end
60
+
61
+ def coverage_stores
62
+ profile['coverageStores'].collect{ |name|
63
+ CoverageStore.new @catalog, :workspace => self, :name => name if name
64
+ }
65
+ end
66
+
67
+ def wms_stores
68
+ profile['wmsStores'].collect{ |name|
69
+ WmsStore.new @catalog, :workspace => self, :name => name if name
70
+ }
71
+ end
72
+
73
+ end
74
+ end