rgeoserver 0.5.8.2 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -c
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
+ # general
5
6
  gem 'activemodel'
6
-
7
-
7
+ gem 'rubyzip'
8
+ gem 'rgeo'
9
+ gem 'rgeo-shapefile'
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ It provides primitive Ruby model abstraction.
10
10
  == Documentation
11
11
  The GeoServer REST Configuration API Reference can be found here:
12
12
 
13
- http://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html
13
+ http://docs.geoserver.org/stable/en/user/rest/index.html
14
14
 
15
15
 
16
16
  == Installation
@@ -162,10 +162,14 @@ result as the ResourceInfo#save method.
162
162
  Inspired on the {Rubydora}[https://github.com/cbeer/rubydora] gem. Followed somewhat closely to {gsconfig.py}[https://github.com/dwins/gsconfig.py]
163
163
 
164
164
  == Contributors
165
+ This package is supported and maintained by Stanford University Libraries.
165
166
 
167
+ Bess Sadler <bess@stanford.edu>
166
168
 
167
169
  == License
168
170
 
169
- Copyright (c) 2012 Renzo Sanchez-Silva <renzo@stanford.edu>.
171
+ Copyright (c) 2012 Stanford University
170
172
 
171
- Licensed under the {MIT License}[http://www.opensource.org/licenses/MIT].
173
+ Author: Renzo Sanchez-Silva <renzo.sanchez.silva@gmail.com>.
174
+
175
+ Licensed under the Apache License, Version 2.0
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.8.2
1
+ 0.5.9
data/lib/rgeoserver.rb CHANGED
@@ -19,6 +19,9 @@ module RGeoServer
19
19
  autoload :Layer, "rgeoserver/layer"
20
20
  autoload :LayerGroup, "rgeoserver/layergroup"
21
21
 
22
+ autoload :BoundingBox, "rgeoserver/utils/boundingbox"
23
+ autoload :ShapefileInfo, "rgeoserver/utils/shapefile_info"
24
+
22
25
  require 'restclient'
23
26
  require 'nokogiri'
24
27
  require 'time'
@@ -30,7 +33,7 @@ module RGeoServer
30
33
 
31
34
  def self.catalog
32
35
  @catalog ||= self.connect(self.default_config.geoserver)
33
- end
36
+ end
34
37
 
35
38
  def self.catalog= catalog
36
39
  @catalog = catalog
@@ -1,12 +1,12 @@
1
1
  module RGeoServer
2
2
  # This class represents the main class of the data model.
3
- # Refer to
3
+ # Refer to
4
4
  # - http://geoserver.org/display/GEOS/Catalog+Design
5
5
  # - http://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html#workspaces
6
6
 
7
7
  class Catalog
8
8
  include RGeoServer::RestApiClient
9
-
9
+
10
10
  attr_reader :config
11
11
 
12
12
  # @param [OrderedHash] options
@@ -27,14 +27,14 @@ module RGeoServer
27
27
  end
28
28
 
29
29
  #== Resources
30
-
30
+
31
31
  # Shortcut to ResourceInfo.list to this catalog. See ResourceInfo#list
32
32
  # @param [RGeoServer::ResourceInfo.class] klass
33
33
  # @param [RGeoServer::Catalog] catalog
34
34
  # @param [Array<String>] names
35
35
  # @param [Hash] options
36
36
  # @param [bool] check_remote if already exists in catalog and cache it
37
- # @yield [RGeoServer::ResourceInfo]
37
+ # @yield [RGeoServer::ResourceInfo]
38
38
  def list klass, names, options, check_remote = false, &block
39
39
  ResourceInfo.list klass, self, names, options, check_remote, &block
40
40
  end
@@ -44,12 +44,12 @@ module RGeoServer
44
44
  # List of available workspaces
45
45
  # @return [Array<RGeoServer::Workspace>]
46
46
  def get_workspaces &block
47
- response = self.search :workspaces => nil
47
+ response = self.search :workspaces => nil
48
48
  doc = Nokogiri::XML(response)
49
49
  workspaces = doc.xpath(Workspace.root_xpath).collect{|w| w.text.to_s }
50
50
  list Workspace, workspaces, {}, &block
51
51
  end
52
-
52
+
53
53
  # @param [String] workspace name
54
54
  # @return [RGeoServer::Workspace]
55
55
  def get_workspace workspace
@@ -66,17 +66,17 @@ module RGeoServer
66
66
  name = doc.at_xpath("#{Workspace.member_xpath}/name/text()").to_s
67
67
  return Workspace.new self, :name => name
68
68
  end
69
-
69
+
70
70
  # Assign default workspace
71
71
  # @param [String] workspace name
72
72
  def set_default_workspace workspace
73
- raise TypeError, "Workspace name must be a string" unless workspace.instance_of? String
74
- dws = Workspace.new self, :name => 'default'
75
- dws.name = workspace # This creates a new workspace if name is new
76
- dws.save
77
- dws
73
+ raise TypeError, "Workspace name must be a string" unless workspace.instance_of? String
74
+ dws = Workspace.new self, :name => 'default'
75
+ dws.name = workspace # This creates a new workspace if name is new
76
+ dws.save
77
+ dws
78
78
  end
79
-
79
+
80
80
  # @param [String] store
81
81
  # @param [String] workspace
82
82
  def reassign_workspace store, workspace
@@ -87,13 +87,16 @@ module RGeoServer
87
87
 
88
88
  # List of available layers
89
89
  # @return [Array<RGeoServer::Layer>]
90
- def get_layers &block
91
- response = self.search :layers => nil
90
+ def get_layers options = {}, &block
91
+ response = self.search :layers => nil
92
92
  doc = Nokogiri::XML(response)
93
- layers = doc.xpath(Layer.root_xpath).collect{|l| l.text.to_s }
94
- list Layer, layers, {}, &block
93
+ workspace_name = Workspace === options[:workspace] ? options[:workspace].name : options[:workspace]
94
+ layer_nodes = doc.xpath(Layer.root_xpath).collect{|l| l.text.to_s }
95
+ layers = list(Layer, layer_nodes, {}, &block)
96
+ layers = layers.find_all { |layer| layer.workspace.name == workspace_name } if options[:workspace]
97
+ layers
95
98
  end
96
-
99
+
97
100
  # @param [String] layer name
98
101
  # @return [RGeoServer::Layer]
99
102
  def get_layer layer
@@ -103,17 +106,41 @@ module RGeoServer
103
106
  return Layer.new self, :name => name
104
107
  end
105
108
 
109
+ #= LayerGroups
110
+
111
+ # List of available layer groups
112
+ # @return [Array<RGeoServer::LayerGroup>]
113
+ def get_layergroups options = {}, &block
114
+ response = unless options[:workspace]
115
+ self.search :layergroups => nil
116
+ else
117
+ self.search :workspaces => options[:workspace], :layergroups => nil
118
+ end
119
+ doc = Nokogiri::XML(response)
120
+ layer_groups = doc.xpath(LayerGroup.root_xpath).collect{|l| l.text.to_s }.map(&:strip)
121
+ list LayerGroup, layer_groups, {workspace: options[:workspace]}, &block
122
+ end
123
+
124
+ # @param [String] layer group name
125
+ # @return [RGeoServer::LayerGroup]
126
+ def get_layergroup layergroup
127
+ response = self.search :layergroups => layergroup
128
+ doc = Nokogiri::XML(response)
129
+ name = doc.at_xpath("#{LayerGroup.member_xpath}/name/text()").to_s
130
+ return LayerGroup.new self, :name => name
131
+ end
132
+
106
133
  #= Styles (SLD Style Layer Descriptor)
107
134
 
108
135
  # List of available styles
109
136
  # @return [Array<RGeoServer::Style>]
110
137
  def get_styles &block
111
- response = self.search :styles => nil
138
+ response = self.search :styles => nil
112
139
  doc = Nokogiri::XML(response)
113
140
  styles = doc.xpath(Style.root_xpath).collect{|l| l.text.to_s }
114
141
  list Style, styles, {}, &block
115
142
  end
116
-
143
+
117
144
  # @param [String] style name
118
145
  # @return [RGeoServer::Style]
119
146
  def get_style style
@@ -125,40 +152,40 @@ module RGeoServer
125
152
 
126
153
 
127
154
  #= Namespaces
128
-
155
+
129
156
  # List of available namespaces
130
157
  # @return [Array<RGeoServer::Namespace>]
131
- def get_namespaces
158
+ def get_namespaces
132
159
  raise NotImplementedError
133
- end
160
+ end
134
161
 
135
162
  # @return [RGeoServer::Namespace]
136
- def get_default_namespace
163
+ def get_default_namespace
137
164
  response = self.search :namespaces => 'default'
138
165
  doc = Nokogiri::XML(response)
139
166
  name = doc.at_xpath("#{Namespace.member_xpath}/prefix/text()").to_s
140
167
  uri = doc.at_xpath("#{Namespace.member_xpath}/uri/text()").to_s
141
- return Namespace.new self, :name => name, :uri => uri
142
- end
168
+ return Namespace.new self, :name => name, :uri => uri
169
+ end
143
170
 
144
- def set_default_namespace id, prefix, uri
171
+ def set_default_namespace id, prefix, uri
145
172
  raise NotImplementedError
146
- end
173
+ end
147
174
 
148
175
  #= Data Stores (Vector datasets)
149
176
 
150
177
  # List of vector based spatial data
151
178
  # @param [String] workspace
152
179
  # @return [Array<RGeoServer::DataStore>]
153
- def get_data_stores workspace = nil
154
- ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
180
+ def get_data_stores workspace = nil
181
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
155
182
  ds = []
156
- ws.each{ |w| ds += w.data_stores if w.data_stores }
157
- ds
183
+ ws.each{ |w| ds += w.data_stores if w.data_stores }
184
+ ds
158
185
  end
159
-
186
+
160
187
  # @param [String] workspace
161
- # @param [String] datastore
188
+ # @param [String] datastore
162
189
  # @return [RGeoServer::DataStore]
163
190
  def get_data_store workspace, datastore
164
191
  response = self.search({:workspaces => workspace, :name => datastore})
@@ -166,38 +193,38 @@ module RGeoServer
166
193
  name = doc.at_xpath(DataStore.member_xpath)
167
194
  return DataStore.new self, workspace, name.text if name
168
195
  end
169
-
196
+
170
197
  # List of feature types
171
198
  # @param [String] workspace
172
- # @param [String] datastore
199
+ # @param [String] datastore
173
200
  # @return [Array<RGeoServer::FeatureType>]
174
201
  def get_feature_types workspace, datastore
175
- raise NotImplementedError
202
+ raise NotImplementedError
176
203
  end
177
204
 
178
205
  # @param [String] workspace
179
- # @param [String] datastore
180
- # @param [String] featuretype_id
206
+ # @param [String] datastore
207
+ # @param [String] featuretype_id
181
208
  # @return [RGeoServer::FeatureType]
182
209
  def get_feature_type workspace, datastore, featuretype_id
183
- raise NotImplementedError
184
- end
210
+ raise NotImplementedError
211
+ end
185
212
 
186
213
 
187
- #= Coverages (Raster datasets)
188
-
214
+ #= Coverages (Raster datasets)
215
+
189
216
  # List of coverage stores
190
217
  # @param [String] workspace
191
218
  # @return [Array<RGeoServer::CoverageStore>]
192
219
  def get_coverage_stores workspace = nil
193
- ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
220
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
194
221
  cs = []
195
- ws.each{ |w| cs += w.coverage_stores if w.coverage_stores }
196
- cs
222
+ ws.each{ |w| cs += w.coverage_stores if w.coverage_stores }
223
+ cs
197
224
  end
198
225
 
199
226
  # @param [String] workspace
200
- # @param [String] coveragestore
227
+ # @param [String] coveragestore
201
228
  # @return [RGeoServer::CoverageStore]
202
229
  def get_coverage_store workspace, coveragestore
203
230
  cs = CoverageStore.new self, :workspace => workspace, :name => coveragestore
@@ -206,43 +233,43 @@ module RGeoServer
206
233
 
207
234
  def get_coverage workspace, coverage_store, coverage
208
235
  c = Coverage.new self, :workspace => workspace, :coverage_store => coverage_store, :name => coverage
209
- return c.new?? nil : c
236
+ return c.new?? nil : c
210
237
  end
211
238
 
212
239
  #= WMS Stores (Web Map Services)
213
240
 
214
241
  # List of WMS stores.
215
- # @param [String] workspace
242
+ # @param [String] workspace
216
243
  # @return [Array<RGeoServer::WmsStore>]
217
244
  def get_wms_stores workspace = nil
218
- ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
245
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
219
246
  cs = []
220
- ws.each{ |w| cs += w.wms_stores if w.wms_stores }
221
- cs
247
+ ws.each{ |w| cs += w.wms_stores if w.wms_stores }
248
+ cs
222
249
  end
223
250
 
224
251
  # @param [String] workspace
225
- # @param [String] wmsstore
252
+ # @param [String] wmsstore
226
253
  # @return [RGeoServer::WmsStore]
227
254
  def get_wms_store workspace, wmsstore
228
255
  response = self.search({:workspaces => workspace, :name => wmsstore})
229
256
  doc = Nokogiri::XML(response)
230
257
  name = doc.at_xpath(WmsStore.member_xpath)
231
258
  return WmsStore.new self, workspace, name.text if name
232
- end
259
+ end
233
260
 
234
261
  #= Configuration reloading
235
262
  # Reloads the catalog and configuration from disk. This operation is used to reload GeoServer in cases where an external tool has modified the on disk configuration. This operation will also force GeoServer to drop any internal caches and reconnect to all data stores.
236
263
  def reload
237
- do_url 'reload', :put
264
+ do_url 'reload', :put
238
265
  end
239
266
 
240
267
  #= Resource reset
241
268
  # Resets all store/raster/schema caches and starts fresh. This operation is used to force GeoServer to drop all caches and stores and reconnect fresh to each of them first time they are needed by a request. This is useful in case the stores themselves cache some information about the data structures they manage that changed in the meantime.
242
269
  def reset
243
270
  do_url 'reset', :put
244
- end
245
-
271
+ end
272
+
246
273
  end
247
274
 
248
275
  end
@@ -3,7 +3,27 @@ module RGeoServer
3
3
  # A data store is a source of spatial data that is vector based. It can be a file in the case of a Shapefile, a database in the case of PostGIS, or a server in the case of a remote Web Feature Service.
4
4
  class DataStore < ResourceInfo
5
5
 
6
- OBJ_ATTRIBUTES = {:enabled => "enabled", :catalog => "catalog", :workspace => "workspace", :name => "name", :connection_parameters => "connectionParameters"}
6
+ class DataStoreAlreadyExists < StandardError
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def message
12
+ "The DataStore '#{@name}' already exists and can not be replaced."
13
+ end
14
+ end
15
+
16
+ class DataTypeNotExpected < StandardError
17
+ def initialize(data_type)
18
+ @data_type = data_type
19
+ end
20
+
21
+ def message
22
+ "The DataStore does not not accept the data type '#{@data_type}'."
23
+ end
24
+ end
25
+
26
+ OBJ_ATTRIBUTES = {:enabled => "enabled", :catalog => "catalog", :workspace => "workspace", :name => "name", :connection_parameters => "connection_parameters"}
7
27
  OBJ_DEFAULT_ATTRIBUTES = {:enabled => 'true', :catalog => nil, :workspace => nil, :name => nil, :connection_parameters => {}}
8
28
  define_attribute_methods OBJ_ATTRIBUTES.keys
9
29
  update_attribute_accessors OBJ_ATTRIBUTES
@@ -42,13 +62,13 @@ module RGeoServer
42
62
  builder = Nokogiri::XML::Builder.new do |xml|
43
63
  xml.dataStore {
44
64
  xml.name @name
45
- xml.enabled @enabled
65
+ xml.enabled enabled
46
66
  xml.connectionParameters { # this could be empty
47
- @connection_parameters.each_pair { |k,v|
67
+ connection_parameters.each_pair { |k,v|
48
68
  xml.entry(:key => k) {
49
69
  xml.text v
50
70
  }
51
- } unless @connection_parameters.nil? || @connection_parameters.empty?
71
+ } unless connection_parameters.nil? || connection_parameters.empty?
52
72
  }
53
73
  }
54
74
  end
@@ -58,7 +78,7 @@ module RGeoServer
58
78
  # @param [RGeoServer::Catalog] catalog
59
79
  # @param [RGeoServer::Workspace|String] workspace
60
80
  # @param [String] name
61
- def initialize catalog, options
81
+ def initialize catalog, options
62
82
  super({})
63
83
  _run_initialize_callbacks do
64
84
  @catalog = catalog
@@ -70,32 +90,86 @@ module RGeoServer
70
90
  else
71
91
  raise "Not a valid workspace"
72
92
  end
73
-
93
+
74
94
  @name = options[:name].strip
75
95
  @route = route
76
- end
96
+ end
77
97
  end
78
98
 
79
99
  def featuretypes &block
80
100
  self.class.list FeatureType, @catalog, profile['featureTypes'], {:workspace => @workspace, :data_store => self}, check_remote = true, &block
81
101
  end
82
102
 
103
+ # @param [String] file_path
104
+ # @param [Hash] options { data_type: [:shapefile] }. optional
105
+ def upload_file file_path, options = {}
106
+ raise DataStoreAlreadyExists, @name unless new?
107
+
108
+ options = options.dup
109
+
110
+ data_type = options.delete(:data_type) || :shapefile
111
+ data_type = data_type.to_sym
112
+
113
+ publish = options.delete(:publish) || false
114
+
115
+ upload_url_suffix = case data_type
116
+ when :shapefile then "#{update_route}/file.shp"
117
+ else
118
+ raise DataTypeNotExpected, data_type
119
+ end
120
+
121
+ @catalog.client[upload_url_suffix].put File.read(file_path), :content_type => 'application/zip'
122
+
123
+ clear
124
+ connection_parameters['url'] = connection_parameters['url'].gsub(/.*data/, '').insert(0, 'file:data') #correct to relative path
125
+ save
126
+ clear
127
+
128
+ if publish
129
+ ft = RGeoServer::FeatureType.new @catalog, :workspace => @workspace, :data_store => self, :name => @name
130
+ ft.title = ft.name.capitalize
131
+ ft.abstract = ft.name.capitalize
132
+ ft.enabled = true
133
+
134
+ bounds = case data_type
135
+ when :shapefile
136
+ shpInfo = ShapefileInfo.new file_path
137
+ shpInfo.bounds
138
+ else
139
+ raise DataTypeNotExpected, data_type
140
+ end
141
+
142
+ ft.native_bounds['minx'], ft.native_bounds['miny'], ft.native_bounds['maxx'], ft.native_bounds['maxy'] =
143
+ bounds.to_a
144
+ ft.projection_policy = :force
145
+ ft.save
146
+
147
+ layers = catalog.get_layers workspace: @workspace
148
+ layers.find_all{ |layer| layer.name == ft.name }.each do |layer|
149
+ layer.enabled = true
150
+ layer.save
151
+ end
152
+ end
153
+
154
+ self
155
+ end
156
+
83
157
  def profile_xml_to_hash profile_xml
84
158
  doc = profile_xml_to_ng profile_xml
85
159
  h = {
86
- "name" => doc.at_xpath('//name').text.strip,
160
+ "name" => doc.at_xpath('//name').text.strip,
87
161
  "enabled" => doc.at_xpath('//enabled/text()').to_s,
88
- "connectionParameters" => doc.xpath('//connectionParameters/entry').inject({}){ |h, e| h.merge(e['key']=> e.text.to_s) }
162
+ "connection_parameters" => doc.xpath('//connectionParameters/entry').inject({}){ |h, e| h.merge(e['key']=> e.text.to_s) }
89
163
  }
90
- doc.xpath('//featureTypes/atom:link/@href', "xmlns:atom"=>"http://www.w3.org/2005/Atom" ).each{ |l|
164
+ doc.xpath('//featureTypes/atom:link/@href', "xmlns:atom"=>"http://www.w3.org/2005/Atom" ).each{ |l|
91
165
  h["featureTypes"] = begin
92
- response = @catalog.do_url l.text
93
- Nokogiri::XML(response).xpath('//name/text()').collect{ |a| a.text.strip }
94
- rescue RestClient::ResourceNotFound
95
- []
96
- end.freeze
97
- }
98
- h
166
+ response = @catalog.do_url l.text
167
+ Nokogiri::XML(response).xpath('//name/text()').collect{ |a| a.text.strip }
168
+ rescue RestClient::ResourceNotFound
169
+ []
170
+ end.freeze
171
+ }
172
+ h
99
173
  end
100
174
  end
101
- end
175
+ end