rgeoserver 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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