rgeoserver 0.5.6 → 0.5.7

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.
@@ -2,8 +2,8 @@
2
2
  module RGeoServer
3
3
  # A feature type is a vector based spatial resource or data set that originates from a data store. In some cases, like Shapefile, a feature type has a one-to-one relationship with its data store. In other cases, like PostGIS, the relationship of feature type to data store is many-to-one, with each feature type corresponding to a table in the database.
4
4
  class FeatureType < ResourceInfo
5
- OBJ_ATTRIBUTES = {:catalog => "catalog", :name => "name", :workspace => "workspace", :enabled => "enabled" }
6
- OBJ_DEFAULT_ATTRIBUTES = {:catalog => nil, :workspace => nil, :coverage_store => nil, :name => nil, :enabled => "false" }
5
+ OBJ_ATTRIBUTES = {:catalog => "catalog", :name => "name", :workspace => "workspace", :enabled => "enabled", :metadata_links => "metadataLinks", :title => "title", :abstract => "abstract" }
6
+ OBJ_DEFAULT_ATTRIBUTES = {:catalog => nil, :workspace => nil, :coverage_store => nil, :name => nil, :enabled => "false", :metadata_links => [], :title => nil, :abtract => nil }
7
7
 
8
8
  define_attribute_methods OBJ_ATTRIBUTES.keys
9
9
  update_attribute_accessors OBJ_ATTRIBUTES
@@ -35,7 +35,24 @@ module RGeoServer
35
35
  def message
36
36
  builder = Nokogiri::XML::Builder.new do |xml|
37
37
  xml.featureType {
38
- xml.name @name
38
+ xml.name @name if new?
39
+ xml.enabled @enabled if (enabled_changed? || new?)
40
+ unless new?
41
+ xml.title @title
42
+ xml.abstract @abtract if abstract_changed?
43
+ xml.store(:class => 'featureType') {
44
+ xml.name @data_store.name
45
+ }
46
+ xml.metadataLinks {
47
+ @metadata_links.each{ |m|
48
+ xml.metadataLink {
49
+ xml.type_ m['type']
50
+ xml.metadataType m['metadataType']
51
+ xml.content m['content']
52
+ }
53
+ }
54
+ } if metadata_links_changed?
55
+ end
39
56
  }
40
57
  end
41
58
  @message = builder.doc.to_xml
@@ -75,8 +92,41 @@ module RGeoServer
75
92
  doc = profile_xml_to_ng profile_xml
76
93
  h = {
77
94
  "name" => doc.at_xpath('//name').text.strip,
95
+ "title" => doc.at_xpath('//title/text()').to_s,
96
+ "abstract" => doc.at_xpath('//abstract/text()').to_s,
78
97
  "workspace" => @workspace.name,
79
- "nativeName" => doc.at_xpath('//nativeName').to_s
98
+ "nativeName" => doc.at_xpath('//nativeName/text()').to_s,
99
+ "srs" => doc.at_xpath('//srs/text()').to_s,
100
+ "nativeBoundingBox" => {
101
+ 'minx' => doc.at_xpath('//nativeBoundingBox/minx/text()').to_s,
102
+ 'miny' => doc.at_xpath('//nativeBoundingBox/miny/text()').to_s,
103
+ 'maxx' => doc.at_xpath('//nativeBoundingBox/maxx/text()').to_s,
104
+ 'maxy' => doc.at_xpath('//nativeBoundingBox/maxy/text()').to_s,
105
+ 'crs' => doc.at_xpath('//nativeBoundingBox/crs/text()').to_s
106
+ },
107
+ "latLonBoundingBox" => {
108
+ 'minx' => doc.at_xpath('//latLonBoundingBox/minx/text()').to_s,
109
+ 'miny' => doc.at_xpath('//latLonBoundingBox/miny/text()').to_s,
110
+ 'maxx' => doc.at_xpath('//latLonBoundingBox/maxx/text()').to_s,
111
+ 'maxy' => doc.at_xpath('//latLonBoundingBox/maxy/text()').to_s,
112
+ 'crs' => doc.at_xpath('//latLonBoundingBox/crs/text()').to_s
113
+ },
114
+ "metadataLinks" => doc.xpath('//metadataLinks/metadataLink').collect{ |m|
115
+ {
116
+ 'type' => m.at_xpath('//type/text()').to_s,
117
+ 'metadataType' => m.at_xpath('//metadataType/text()').to_s,
118
+ 'content' => m.at_xpath('//content/text()').to_s
119
+ }
120
+ },
121
+ "attributes" => doc.xpath('//attributes/attribute').collect{ |a|
122
+ {
123
+ 'name' => a.at_xpath('//name/text()').to_s,
124
+ 'minOccurs' => a.at_xpath('//minOccurs/text()').to_s,
125
+ 'maxOccurs' => a.at_xpath('//maxOccurs/text()').to_s,
126
+ 'nillable' => a.at_xpath('//nillable/text()').to_s,
127
+ 'binding' => a.at_xpath('//binding/text()').to_s
128
+ }
129
+ }
80
130
  }.freeze
81
131
  h
82
132
  end
@@ -3,8 +3,29 @@ module RGeoServer
3
3
  # A layer is a published resource (feature type or coverage).
4
4
  class Layer < ResourceInfo
5
5
 
6
- OBJ_ATTRIBUTES = {:enabled => 'enabled', :catalog => 'catalog', :name => 'name', :default_style => 'default_style', :alternate_styles => 'alternate_styles', :metadata => 'metadata', :attribution => 'attribution', :layer_type => 'type' }
7
- OBJ_DEFAULT_ATTRIBUTES = {:enabled => 'true', :catalog => nil, :name => nil, :default_style => nil, :alternate_styles => [], :metadata => {}, :attribution => {:logo_height => '0', :logo_width => '0', 'title' => ''}, :layer_type => nil }
6
+ OBJ_ATTRIBUTES = {:enabled => 'enabled', :queryable => 'queryable', :path => 'path', :catalog => 'catalog', :name => 'name', :default_style => 'default_style', :alternate_styles => 'alternate_styles', :metadata => 'metadata', :attribution => 'attribution', :layer_type => 'type' }
7
+ OBJ_DEFAULT_ATTRIBUTES = {
8
+ :enabled => 'true',
9
+ :queryable => 'true',
10
+ :path => '/',
11
+ :catalog => nil,
12
+ :name => nil,
13
+ :default_style => nil,
14
+ :alternate_styles => [],
15
+ :metadata => {
16
+ 'GWC.autoCacheStyles' => 'true',
17
+ 'GWC.gutter' => '0',
18
+ 'GWC.enabled' => 'true',
19
+ 'GWC.cacheFormats' => 'image/jpeg,image/png',
20
+ 'GWC.gridSets' => 'EPSG:4326,EPSG:900913'
21
+ },
22
+ :attribution => {
23
+ 'logo_height' => '0',
24
+ 'logo_width' => '0',
25
+ 'title' => ''
26
+ },
27
+ :layer_type => nil
28
+ }
8
29
 
9
30
  define_attribute_methods OBJ_ATTRIBUTES.keys
10
31
  update_attribute_accessors OBJ_ATTRIBUTES
@@ -33,12 +54,18 @@ module RGeoServer
33
54
  nil
34
55
  end
35
56
 
57
+ def update_params name_route = @name
58
+ { :layer => name_route }
59
+ end
60
+
36
61
  def message
37
62
  builder = Nokogiri::XML::Builder.new do |xml|
38
63
  xml.layer {
39
- #xml.name @name
40
- xml.type_ layer_type
41
- xml.enabled enabled
64
+ xml.name @name
65
+ xml.path path
66
+ xml.type_ layer_type
67
+ xml.enabled @enabled
68
+ xml.queryable @queryable
42
69
  xml.defaultStyle {
43
70
  xml.name default_style
44
71
  }
@@ -52,6 +79,13 @@ module RGeoServer
52
79
  xml.resource(:class => resource.class.resource_name){
53
80
  xml.name resource.name
54
81
  } unless resource.nil?
82
+ xml.metadata {
83
+ metadata.each_pair { |k,v|
84
+ xml.entry(:key => k) {
85
+ xml.text v
86
+ }
87
+ }
88
+ }
55
89
  xml.attribution {
56
90
  xml.title attribution['title'] unless attribution['title'].empty?
57
91
  xml.logoWidth attribution['logo_width']
@@ -130,8 +164,10 @@ module RGeoServer
130
164
  "path" => doc.at_xpath('//path/text()').to_s,
131
165
  "default_style" => doc.at_xpath('//defaultStyle/name/text()').to_s,
132
166
  "alternate_styles" => doc.xpath('//styles/style/name/text()').collect{ |s| s.to_s},
167
+ # Types can be: VECTOR, RASTER, REMOTE, WMS
133
168
  "type" => doc.at_xpath('//type/text()').to_s,
134
169
  "enabled" => doc.at_xpath('//enabled/text()').to_s,
170
+ "queryable" => doc.at_xpath('//queryable/text()').to_s,
135
171
  "attribution" => {
136
172
  "title" => doc.at_xpath('//attribution/title/text()').to_s,
137
173
  "logo_width" => doc.at_xpath('//attribution/logoWidth/text()').to_s,
@@ -148,5 +184,79 @@ module RGeoServer
148
184
  h
149
185
  end
150
186
 
187
+ def workspace
188
+ resource.workspace
189
+ end
190
+
191
+ #= GeoWebCache Operations for this layer
192
+ # See http://geowebcache.org/docs/current/rest/seed.html
193
+ # See RGeoServer::Catalog.seed_terminate for stopping pending and/or running tasks for any layer
194
+ #
195
+ # Example:
196
+ # > lyr = RGeoServer::Layer.new catalog, :name => 'Arc_Sample'
197
+ # > options = {
198
+ # :srs => {:number => 4326 },
199
+ # :zoomStart => 1,
200
+ # :zoomStop => 12,
201
+ # :format => 'image/png',
202
+ # :threadCount => 1
203
+ # }
204
+ # > lyr.seed :issue, options
205
+
206
+ # @param[String] operation
207
+ # @option operation[Symbol] :issue seed
208
+ # @option operation[Symbol] :truncate seed
209
+ # @option operation[Symbol] :status of the seeding thread
210
+ # @param[Hash] options for seed message. Read the documentation
211
+ def seed operation, options
212
+ op = operation.to_sym
213
+ sub_path = "seed/#{prefixed_name}.xml"
214
+ case op
215
+ when :issue
216
+ @catalog.do_url sub_path, :post, build_seed_request(:seed, options), {}, @catalog.gwc_client
217
+ when :truncate
218
+ @catalog.do_url sub_path, :post, build_seed_request(:truncate, options), {}, @catalog.gwc_client
219
+ when :status
220
+ raise NotImplementedError
221
+ end
222
+ end
223
+
224
+ # @param[Hash] options for seed message
225
+ def build_seed_request operation, options
226
+ builder = Nokogiri::XML::Builder.new do |xml|
227
+ xml.seedRequest {
228
+ xml.name prefixed_name
229
+
230
+ xml.srs {
231
+ xml.number options[:srs][:number]
232
+ } unless options[:srs].nil? #&& options[:srs].is_a?(Hash)
233
+
234
+ xml.bounds {
235
+ xml.coords {
236
+ options[:bounds][:coords].each { |dbl|
237
+ xml.double dbl
238
+ }
239
+ }
240
+ } unless options[:bounds].nil?
241
+
242
+ xml.type_ operation
243
+
244
+ [:gridSetId, :zoomStart, :zoomStop, :format, :threadCount].each { |p|
245
+ eval "xml.#{p.to_s} options[p]" unless options[p].nil?
246
+ }
247
+
248
+ xml.parameters {
249
+ options[:parameters].each_pair { |k,v|
250
+ xml.entry {
251
+ xml.string k.upcase
252
+ xml.string v
253
+ }
254
+ }
255
+ } if options[:parameters].is_a?(Hash)
256
+ }
257
+ end
258
+ return builder.doc.to_xml
259
+ end
151
260
  end
261
+
152
262
  end
@@ -116,7 +116,7 @@ module RGeoServer
116
116
 
117
117
  def profile_xml_to_hash profile_xml
118
118
  doc = profile_xml_to_ng profile_xml
119
- name = doc.at_xpath('//name/text()').text.strip
119
+ name = doc.at_xpath('//name/text()').to_s
120
120
 
121
121
  h = {
122
122
  "name" => name,
@@ -0,0 +1,63 @@
1
+
2
+ module RGeoServer
3
+ # A namespace is a uniquely identifiable grouping of feature types. A namespaces is identified by a prefix and a uri.
4
+ class Namespace < ResourceInfo
5
+
6
+ OBJ_ATTRIBUTES = {:enabled => 'enabled', :catalog => 'catalog', :name => 'prefix', :uri => 'uri' }
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
+ @@route = "namespaces"
13
+ @@resource_name = "namespace"
14
+
15
+ def self.resource_name
16
+ @@resource_name
17
+ end
18
+
19
+ def self.root_xpath
20
+ "//#{@@route}/#{@@resource_name}"
21
+ end
22
+
23
+ def self.member_xpath
24
+ "//#{resource_name}"
25
+ end
26
+
27
+ def route
28
+ @@route
29
+ end
30
+
31
+ def message
32
+ builder = Nokogiri::XML::Builder.new do |xml|
33
+ xml.namespace {
34
+ xml.prefix @name
35
+ xml.uri @uri
36
+ }
37
+ end
38
+ return builder.doc.to_xml
39
+ end
40
+
41
+ # @param [RGeoServer::Catalog] catalog
42
+ # @param [Hash] options
43
+ def initialize catalog, options
44
+ super({})
45
+ _run_initialize_callbacks do
46
+ @catalog = catalog
47
+ @name = options[:name].strip
48
+ @uri = options[:uri] if options[:uri]
49
+ end
50
+ @route = route
51
+ end
52
+
53
+ def profile_xml_to_hash profile_xml
54
+ doc = profile_xml_to_ng profile_xml
55
+ h = {
56
+ 'name' => doc.at_xpath('//namespace/prefix/text()').to_s,
57
+ 'uri' => doc.at_xpath('//namespace/uri/text()').to_s
58
+ }.freeze
59
+ h
60
+ end
61
+
62
+ end
63
+ end
@@ -55,6 +55,12 @@ module RGeoServer
55
55
  def to_s
56
56
  "#{self.class.name}: #{name}"
57
57
  end
58
+
59
+ # Return full name of resource with namespace prefix
60
+ def prefixed_name
61
+ return "#{workspace.name}:#{name}" if self.respond_to?(:workspace)
62
+ raise "Workspace is not defined for this resource"
63
+ end
58
64
 
59
65
  def create_method
60
66
  :post
@@ -63,6 +69,12 @@ module RGeoServer
63
69
  def update_method
64
70
  :put
65
71
  end
72
+
73
+ # We pass the old name "name_route" in case the name of the resource is being edited
74
+ # Child classes should implement this
75
+ def update_params name_route = name
76
+ { self.class.resource_name.downcase.to_sym => name_route }
77
+ end
66
78
 
67
79
  # Modify or save the resource
68
80
  # @param [Hash] options / query parameters
@@ -71,7 +83,15 @@ module RGeoServer
71
83
  @previously_changed = changes
72
84
  @changed_attributes.clear
73
85
  run_callbacks :save do
74
- if new?
86
+ unless @previously_changed[:name].nil?
87
+ old_name, new_name = @previously_changed[:name]
88
+ name_route = old_name if old_name != new_name
89
+ update = true
90
+ else
91
+ name_route = name
92
+ update = false
93
+ end
94
+ if !update && new?
75
95
  if self.respond_to?(:create_route)
76
96
  raise "Resource cannot be created directly" if create_route.nil?
77
97
  route = create_route
@@ -83,8 +103,8 @@ module RGeoServer
83
103
  @catalog.add(route, message, create_method, options)
84
104
  clear
85
105
  else
86
- options = update_options.merge(options) if self.respond_to?(:update_options)
87
- route = self.respond_to?(:update_route)? update_route : {@route => @name}
106
+ options = update_params(name_route).merge(options)
107
+ route = {@route => name_route}
88
108
  @catalog.modify(route, message, update_method, options) #unless changes.empty?
89
109
  end
90
110
 
@@ -10,11 +10,24 @@ module RGeoServer
10
10
  include RGeoServer::GeoServerUrlHelpers
11
11
  include ActiveSupport::Benchmarkable
12
12
 
13
+ # Instantiates a rest client with passed configuration
14
+ # @param [Hash] c configuration
15
+ # return <RestClient::Resource>
16
+ def rest_client c
17
+ RestClient::Resource.new(c[:url], :user => c[:user], :password => c[:password], :headers => c[:headers])
18
+ end
19
+
13
20
  def client config = {}
21
+ @client ||= rest_client(self.config.merge(config))
22
+ end
23
+
24
+ def gwc_client config = {}
14
25
  c = self.config.merge(config)
15
- @client ||= RestClient::Resource.new(c[:url], :user => c[:user], :password => c[:password], :headers => c[:headers])
26
+ c[:url] = c[:geowebcache_url]
27
+ @gwc_client ||= rest_client(c)
16
28
  end
17
29
 
30
+
18
31
  def headers format
19
32
  sym = :xml || format.to_sym
20
33
  {:accept => sym, :content_type=> sym}
@@ -36,23 +49,25 @@ module RGeoServer
36
49
  end
37
50
  end
38
51
 
39
- # Do an action on an arbitrary URL within the catalog passing no data
40
- # Default method is GET
41
- # @param [String] url
42
- # @param [String] method
43
- def do_url url, method = :get
44
- url.slice! client.url
45
- fetcher = client[url]
46
- fetcher.options[:headers] ||= headers(:xml)
47
- begin
48
- return fetcher.get if method == :get
49
- fetcher.send method, nil
50
- rescue RestClient::InternalServerError => e
51
- $logger.error e.response
52
- $logger.flush if $logger.respond_to? :flush
53
- raise GeoServerInvalidRequest, "Error fetching URL: #{url}. See $logger for details"
54
- end
55
- end
52
+ # Do an action on an arbitrary URL path within the catalog
53
+ # Default method is GET
54
+ # @param [String] sub_url
55
+ # @param [String] method
56
+ # @param [String] data payload
57
+ # @param [Hash] options for request
58
+ def do_url sub_url, method = :get, data = nil, options = {}, client = client
59
+ sub_url.slice! client.url
60
+ fetcher = client[sub_url]
61
+ fetcher.options.merge(options)
62
+ begin
63
+ return fetcher.get if method == :get
64
+ fetcher.send method, data
65
+ rescue RestClient::InternalServerError => e
66
+ $logger.error e.response
67
+ $logger.flush if $logger.respond_to? :flush
68
+ raise GeoServerInvalidRequest, "Error fetching URL: #{sub_url}. See $logger for details"
69
+ end
70
+ end
56
71
 
57
72
  # Add resource to the catalog
58
73
  # @param [String] what
data/rgeoserver.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = "http://github.com/rnz0/rgeoserver"
11
11
 
12
12
  s.files = `git ls-files`.split("\n")
13
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ s.test_files = `git ls-files -- {examples,spec,features}/*`.split("\n")
14
14
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
15
  s.require_paths = ["lib"]
16
16
 
Binary file
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe RGeoServer::ResourceInfo do
4
+ subject { RGeoServer::ResourceInfo.new }
5
+ let(:options) {
6
+ { 'new' => 'true' }
7
+ }
8
+ describe "#list" do
9
+
10
+ end
11
+
12
+ end
13
+