rgeoserver 0.5.6 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+