rgeoserver 0.5.9 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/Gemfile +1 -7
- data/Gemfile.lock +147 -0
- data/README.rdoc +69 -78
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/batch_load.rb +138 -0
- data/config/defaults.yml +17 -0
- data/examples/batch_demo.rb +170 -0
- data/examples/catalog_migration.rb +2 -2
- data/examples/cluster_demo.rb +1 -1
- data/examples/coverage_stores.rb +42 -0
- data/examples/demo_druid_workspace.rb +6 -0
- data/examples/deploy_dor_layer.rb +19 -0
- data/examples/sql_layer_demo.rb +1 -1
- data/lib/rgeoserver/catalog.rb +83 -86
- data/lib/rgeoserver/config.rb +11 -1
- data/lib/rgeoserver/coverage.rb +43 -15
- data/lib/rgeoserver/coveragestore.rb +46 -11
- data/lib/rgeoserver/datastore.rb +73 -62
- data/lib/rgeoserver/featuretype.rb +134 -71
- data/lib/rgeoserver/geoserver_url_helpers.rb +140 -10
- data/lib/rgeoserver/layer.rb +52 -16
- data/lib/rgeoserver/layergroup.rb +1 -2
- data/lib/rgeoserver/namespace.rb +1 -2
- data/lib/rgeoserver/resource.rb +37 -34
- data/lib/rgeoserver/rest_api_client.rb +33 -14
- data/lib/rgeoserver/style.rb +1 -2
- data/lib/rgeoserver/utils/boundingbox.rb +59 -16
- data/lib/rgeoserver/utils/metadata.rb +21 -0
- data/lib/rgeoserver/version.rb +1 -1
- data/lib/rgeoserver/wmsstore.rb +1 -6
- data/lib/rgeoserver/workspace.rb +23 -8
- data/lib/rgeoserver.rb +31 -38
- data/rgeoserver.gemspec +28 -20
- data/spec/fixtures/load_ex1.yml +45 -0
- data/spec/fixtures/load_ex2.yml +14 -0
- data/spec/functional/catalog_spec.rb +71 -0
- data/spec/functional/rest_api_client_spec.rb +215 -0
- data/spec/integration/geoserver_spec.rb +2 -2
- metadata +120 -66
- data/config/config_defaults.yml +0 -10
- data/examples/batch_example.rb +0 -105
@@ -1,21 +1,41 @@
|
|
1
1
|
|
2
2
|
module RGeoServer
|
3
|
-
# A feature type is a vector based spatial resource or data set that originates from a data store.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
# A feature type is a vector based spatial resource or data set that originates from a data store.
|
4
|
+
# In some cases, like Shapefile, a feature type has a one-to-one relationship with its data store.
|
5
|
+
# In other cases, like PostGIS, the relationship of feature type to data store is many-to-one, with
|
6
|
+
# each feature type corresponding to a table in the database.
|
7
|
+
class FeatureType < ResourceInfo
|
8
|
+
OBJ_ATTRIBUTES = {
|
9
|
+
:catalog => "catalog",
|
10
|
+
:name => "name",
|
11
|
+
:native_name => "nativeName",
|
12
|
+
:workspace => "workspace",
|
13
|
+
:data_store => "data_store",
|
14
|
+
:enabled => "enabled",
|
15
|
+
:metadata => "metadata",
|
16
|
+
:metadata_links => "metadataLinks",
|
17
|
+
:title => "title",
|
18
|
+
:abstract => "abstract",
|
19
|
+
:keywords => 'keywords',
|
20
|
+
:native_bounds => 'native_bounds',
|
21
|
+
:latlon_bounds => "latlon_bounds",
|
22
|
+
:projection_policy => 'projection_policy'
|
23
|
+
}
|
24
|
+
OBJ_DEFAULT_ATTRIBUTES = {
|
8
25
|
:catalog => nil,
|
9
26
|
:workspace => nil,
|
10
27
|
:data_store => nil,
|
11
28
|
:name => nil,
|
29
|
+
:native_name => nil,
|
12
30
|
:enabled => "false",
|
13
|
-
:
|
31
|
+
:metadata => {},
|
32
|
+
:metadata_links => {},
|
14
33
|
:title => nil,
|
15
34
|
:abstract => nil,
|
35
|
+
:keywords => [],
|
16
36
|
:native_bounds => {'minx'=>nil, 'miny' =>nil, 'maxx'=>nil, 'maxy'=>nil, 'crs' =>nil},
|
17
37
|
:latlon_bounds => {'minx'=>nil, 'miny' =>nil, 'maxx'=>nil, 'maxy'=>nil, 'crs' =>nil},
|
18
|
-
:projection_policy => :
|
38
|
+
:projection_policy => :keep
|
19
39
|
}
|
20
40
|
|
21
41
|
define_attribute_methods OBJ_ATTRIBUTES.keys
|
@@ -25,6 +45,19 @@ module RGeoServer
|
|
25
45
|
@@root = "featureTypes"
|
26
46
|
@@resource_name = "featureType"
|
27
47
|
|
48
|
+
# see http://inspire.ec.europa.eu/schemas/common/1.0/common.xsd
|
49
|
+
METADATA_TYPES = {
|
50
|
+
'ISO19139' => 'text/xml',
|
51
|
+
'TC211' => 'text/xml'
|
52
|
+
}
|
53
|
+
|
54
|
+
# see https://github.com/geoserver/geoserver/blob/master/src/main/src/main/java/org/geoserver/catalog/ProjectionPolicy.java
|
55
|
+
PROJECTION_POLICIES = {
|
56
|
+
:force => 'FORCE_DECLARED',
|
57
|
+
:reproject => 'REPROJECT_TO_DECLARED',
|
58
|
+
:keep => 'NONE'
|
59
|
+
}
|
60
|
+
|
28
61
|
def self.root
|
29
62
|
@@root
|
30
63
|
end
|
@@ -42,20 +75,45 @@ module RGeoServer
|
|
42
75
|
end
|
43
76
|
|
44
77
|
def route
|
78
|
+
raise GeoServerArgumentError, "workspace not defined" unless @workspace
|
79
|
+
raise GeoServerArgumentError, "data_store not defined" unless @data_store
|
45
80
|
@@route % [@workspace.name , @data_store.name]
|
46
81
|
end
|
82
|
+
|
83
|
+
def to_mimetype(type, default = 'text/xml')
|
84
|
+
k = type.to_s.strip.upcase
|
85
|
+
return METADATA_TYPES[k] if METADATA_TYPES.include? k
|
86
|
+
default
|
87
|
+
end
|
47
88
|
|
48
89
|
def message
|
49
90
|
builder = Nokogiri::XML::Builder.new do |xml|
|
50
91
|
xml.featureType {
|
51
|
-
xml.
|
52
|
-
xml.
|
53
|
-
xml.
|
54
|
-
xml.
|
92
|
+
xml.nativeName @native_name.nil?? @name : @native_name if new? # on new only
|
93
|
+
xml.name @name
|
94
|
+
xml.enabled @enabled
|
95
|
+
xml.title @title
|
96
|
+
xml.abstract @abstract
|
97
|
+
xml.keywords {
|
98
|
+
@keywords.compact.uniq.each do |k|
|
99
|
+
xml.string RGeoServer::Metadata::to_keyword(k)
|
100
|
+
end
|
101
|
+
} unless @keywords.empty?
|
55
102
|
|
103
|
+
xml.metadataLinks {
|
104
|
+
@metadata_links.each do |m|
|
105
|
+
raise ArgumentError, "Malformed metadata_links" unless m.is_a? Hash
|
106
|
+
xml.metadataLink {
|
107
|
+
xml.type_ to_mimetype(m['metadataType'])
|
108
|
+
xml.metadataType m['metadataType']
|
109
|
+
xml.content m['content']
|
110
|
+
}
|
111
|
+
end
|
112
|
+
} unless @metadata_links.empty?
|
113
|
+
|
56
114
|
xml.store(:class => 'dataStore') {
|
57
115
|
xml.name @data_store.name
|
58
|
-
} if new?
|
116
|
+
} if new? or data_store_changed?
|
59
117
|
|
60
118
|
xml.nativeBoundingBox {
|
61
119
|
xml.minx native_bounds['minx'] if native_bounds['minx']
|
@@ -63,7 +121,7 @@ module RGeoServer
|
|
63
121
|
xml.maxx native_bounds['maxx'] if native_bounds['maxx']
|
64
122
|
xml.maxy native_bounds['maxy'] if native_bounds['maxy']
|
65
123
|
xml.crs native_bounds['crs'] if native_bounds['crs']
|
66
|
-
} if valid_native_bounds?
|
124
|
+
} if valid_native_bounds? and (new? or native_bounds_changed?)
|
67
125
|
|
68
126
|
xml.latLonBoundingBox {
|
69
127
|
xml.minx latlon_bounds['minx'] if latlon_bounds['minx']
|
@@ -71,11 +129,11 @@ module RGeoServer
|
|
71
129
|
xml.maxx latlon_bounds['maxx'] if latlon_bounds['maxx']
|
72
130
|
xml.maxy latlon_bounds['maxy'] if latlon_bounds['maxy']
|
73
131
|
xml.crs latlon_bounds['crs'] if latlon_bounds['crs']
|
74
|
-
} if valid_latlon_bounds?
|
132
|
+
} if valid_latlon_bounds? and (new? or latlon_bounds_changed?)
|
75
133
|
|
76
|
-
xml.projectionPolicy get_projection_policy_message(projection_policy) if projection_policy
|
134
|
+
xml.projectionPolicy get_projection_policy_message(projection_policy) if projection_policy and new? or projection_policy_changed?
|
77
135
|
|
78
|
-
if new?
|
136
|
+
if new? # XXX: hard coded attributes
|
79
137
|
xml.attributes {
|
80
138
|
xml.attribute {
|
81
139
|
xml.name 'the_geom'
|
@@ -85,44 +143,38 @@ module RGeoServer
|
|
85
143
|
xml.binding 'com.vividsolutions.jts.geom.Point'
|
86
144
|
}
|
87
145
|
}
|
88
|
-
else
|
89
|
-
xml.metadataLinks {
|
90
|
-
@metadata_links.each{ |m|
|
91
|
-
xml.metadataLink {
|
92
|
-
xml.type_ m['type']
|
93
|
-
xml.metadataType m['metadataType']
|
94
|
-
xml.content m['content']
|
95
|
-
}
|
96
|
-
}
|
97
|
-
} if metadata_links_changed?
|
98
146
|
end
|
99
147
|
}
|
100
148
|
end
|
101
149
|
@message = builder.doc.to_xml
|
150
|
+
ap({:message => @message}) if $DEBUG
|
151
|
+
@message
|
102
152
|
end
|
103
153
|
|
104
154
|
|
105
155
|
# @param [RGeoServer::Catalog] catalog
|
106
156
|
# @param [Hash] options
|
107
157
|
def initialize catalog, options
|
108
|
-
|
158
|
+
raise GeoServerArgumentError, "FeatureType.new requires :data_store option" unless options.include?(:data_store)
|
159
|
+
raise GeoServerArgumentError, "FeatureType.new requires :name option" unless options.include?(:name)
|
160
|
+
super(catalog)
|
109
161
|
_run_initialize_callbacks do
|
110
|
-
@catalog = catalog
|
111
162
|
workspace = options[:workspace] || 'default'
|
112
163
|
if workspace.instance_of? String
|
113
164
|
@workspace = @catalog.get_workspace(workspace)
|
114
165
|
elsif workspace.instance_of? Workspace
|
115
166
|
@workspace = workspace
|
116
167
|
else
|
117
|
-
raise "Not a valid workspace"
|
168
|
+
raise GeoServerArgumentError, "Not a valid workspace: #{workspace}"
|
118
169
|
end
|
170
|
+
|
119
171
|
data_store = options[:data_store]
|
120
172
|
if data_store.instance_of? String
|
121
|
-
@data_store =
|
173
|
+
@data_store = @catalog.get_data_store(@workspace.name, data_store)
|
122
174
|
elsif data_store.instance_of? DataStore
|
123
175
|
@data_store = data_store
|
124
176
|
else
|
125
|
-
raise "Not a valid
|
177
|
+
raise GeoServerArgumentError, "Not a valid datastore: #{data_store}"
|
126
178
|
end
|
127
179
|
|
128
180
|
@name = options[:name].strip
|
@@ -132,77 +184,88 @@ module RGeoServer
|
|
132
184
|
|
133
185
|
def profile_xml_to_hash profile_xml
|
134
186
|
doc = profile_xml_to_ng profile_xml
|
187
|
+
ft = doc.at_xpath('//' + FeatureType::resource_name)
|
188
|
+
ap({:doc => doc, :ft => ft}) if $DEBUG
|
135
189
|
h = {
|
136
|
-
"name" =>
|
137
|
-
"
|
138
|
-
"
|
190
|
+
"name" => ft.at_xpath('name').text,
|
191
|
+
"native_name" => ft.at_xpath('nativeName').text,
|
192
|
+
"title" => ft.at_xpath('title').text,
|
193
|
+
"abstract" => ft.at_xpath('abstract/text()'), # optional
|
194
|
+
"keywords" => ft.xpath('keywords/string').collect { |k| k.at_xpath('.').text},
|
139
195
|
"workspace" => @workspace.name,
|
140
196
|
"data_store" => @data_store.name,
|
141
|
-
"
|
142
|
-
"srs" => doc.at_xpath('//srs/text()').to_s,
|
197
|
+
"srs" => ft.at_xpath('srs').text,
|
143
198
|
"native_bounds" => {
|
144
|
-
'minx' =>
|
145
|
-
'miny' =>
|
146
|
-
'maxx' =>
|
147
|
-
'maxy' =>
|
148
|
-
'crs' =>
|
199
|
+
'minx' => ft.at_xpath('nativeBoundingBox/minx').text.to_f,
|
200
|
+
'miny' => ft.at_xpath('nativeBoundingBox/miny').text.to_f,
|
201
|
+
'maxx' => ft.at_xpath('nativeBoundingBox/maxx').text.to_f,
|
202
|
+
'maxy' => ft.at_xpath('nativeBoundingBox/maxy').text.to_f,
|
203
|
+
'crs' => ft.at_xpath('srs').text
|
149
204
|
},
|
150
205
|
"latlon_bounds" => {
|
151
|
-
'minx' =>
|
152
|
-
'miny' =>
|
153
|
-
'maxx' =>
|
154
|
-
'maxy' =>
|
155
|
-
'crs' =>
|
206
|
+
'minx' => ft.at_xpath('latLonBoundingBox/minx').text.to_f,
|
207
|
+
'miny' => ft.at_xpath('latLonBoundingBox/miny').text.to_f,
|
208
|
+
'maxx' => ft.at_xpath('latLonBoundingBox/maxx').text.to_f,
|
209
|
+
'maxy' => ft.at_xpath('latLonBoundingBox/maxy').text.to_f,
|
210
|
+
'crs' => ft.at_xpath('latLonBoundingBox/crs').text
|
156
211
|
},
|
157
|
-
"projection_policy" => get_projection_policy_sym(
|
158
|
-
"
|
212
|
+
"projection_policy" => get_projection_policy_sym(ft.at_xpath('projectionPolicy').text),
|
213
|
+
"metadata_links" => ft.xpath('metadataLinks/metadataLink').collect{ |m|
|
159
214
|
{
|
160
|
-
'type' => m.at_xpath('
|
161
|
-
'metadataType' => m.at_xpath('
|
162
|
-
'content' => m.at_xpath('
|
215
|
+
'type' => m.at_xpath('type').text,
|
216
|
+
'metadataType' => m.at_xpath('metadataType').text,
|
217
|
+
'content' => m.at_xpath('content').text
|
163
218
|
}
|
164
219
|
},
|
165
|
-
"attributes" =>
|
220
|
+
"attributes" => ft.xpath('attributes/attribute').collect{ |a|
|
166
221
|
{
|
167
|
-
'name' => a.at_xpath('
|
168
|
-
'minOccurs' => a.at_xpath('
|
169
|
-
'maxOccurs' => a.at_xpath('
|
170
|
-
'nillable' => a.at_xpath('
|
171
|
-
'binding' => a.at_xpath('
|
222
|
+
'name' => a.at_xpath('name').text,
|
223
|
+
'minOccurs' => a.at_xpath('minOccurs').text,
|
224
|
+
'maxOccurs' => a.at_xpath('maxOccurs').text,
|
225
|
+
'nillable' => a.at_xpath('nillable').text,
|
226
|
+
'binding' => a.at_xpath('binding').text
|
172
227
|
}
|
173
228
|
}
|
174
229
|
}.freeze
|
230
|
+
ap({:h => h}) if $DEBUG
|
175
231
|
h
|
176
232
|
end
|
177
233
|
|
178
234
|
def valid_native_bounds?
|
179
|
-
native_bounds
|
180
|
-
|
235
|
+
bbox = RGeoServer::BoundingBox.new(native_bounds)
|
236
|
+
ap bbox if $DEBUG
|
237
|
+
not bbox.nil? and bbox.valid? and not native_bounds['crs'].empty?
|
181
238
|
end
|
182
239
|
|
183
240
|
def valid_latlon_bounds?
|
184
|
-
latlon_bounds
|
185
|
-
|
241
|
+
bbox = RGeoServer::BoundingBox.new(latlon_bounds)
|
242
|
+
ap bbox if $DEBUG
|
243
|
+
not bbox.nil? and bbox.valid? and not latlon_bounds['crs'].empty?
|
244
|
+
end
|
245
|
+
|
246
|
+
def update_params name_route = name
|
247
|
+
super(name_route)
|
248
|
+
# recalculate='nativebbox,latlonbbox'
|
186
249
|
end
|
187
250
|
|
188
251
|
private
|
252
|
+
|
189
253
|
def get_projection_policy_sym value
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
when 'NONE' then :keep
|
254
|
+
v = value.strip.upcase
|
255
|
+
if PROJECTION_POLICIES.has_value? v
|
256
|
+
PROJECTION_POLICIES.invert[v]
|
194
257
|
else
|
195
|
-
raise
|
258
|
+
raise GeoServerArgumentError, "Invalid PROJECTION_POLICY: #{v}"
|
196
259
|
end
|
197
260
|
end
|
198
261
|
|
199
262
|
def get_projection_policy_message value
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
263
|
+
k = value
|
264
|
+
k = value.strip.to_sym if not value.is_a? Symbol
|
265
|
+
if PROJECTION_POLICIES.has_key? k
|
266
|
+
PROJECTION_POLICIES[k]
|
204
267
|
else
|
205
|
-
raise
|
268
|
+
raise GeoServerArgumentError, "Invalid PROJECTION_POLICY: #{k}"
|
206
269
|
end
|
207
270
|
end
|
208
271
|
end
|
@@ -1,17 +1,147 @@
|
|
1
1
|
|
2
2
|
module RGeoServer
|
3
3
|
module GeoServerUrlHelpers
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
|
5
|
+
# Valid URI sequences for REST API
|
6
|
+
# See http://docs.geoserver.org/stable/en/user/rest/index.html
|
7
|
+
URI_SEQUENCES = [
|
8
|
+
%w{settings},
|
9
|
+
%w{settings contact},
|
10
|
+
%w{workspaces},
|
11
|
+
%w{workspaces settings},
|
12
|
+
%w{namespaces},
|
13
|
+
%w{workspaces datastores},
|
14
|
+
%w{workspaces datastores file},
|
15
|
+
%w{workspaces datastores external},
|
16
|
+
%w{workspaces datastores url},
|
17
|
+
%w{workspaces datastores featuretypes},
|
18
|
+
%w{workspaces coveragestores},
|
19
|
+
%w{workspaces coveragestores file},
|
20
|
+
%w{workspaces coveragestores coverages},
|
21
|
+
%w{styles},
|
22
|
+
%w{workspaces styles},
|
23
|
+
%w{layers},
|
24
|
+
%w{layers styles},
|
25
|
+
%w{layergroups},
|
26
|
+
%w{workspaces layergroups},
|
27
|
+
%w{fonts},
|
28
|
+
%w{templates},
|
29
|
+
%w{services wcs settings},
|
30
|
+
%w{services wfs settings},
|
31
|
+
%w{services wms settings},
|
32
|
+
%w{reload},
|
33
|
+
%w{reset},
|
34
|
+
%w{about}
|
35
|
+
].map {|x| x.map(&:to_sym)}
|
36
|
+
|
37
|
+
# Regexp processing for #URI_SEQUENCES
|
38
|
+
URI_REGEX = URI_SEQUENCES.map do |a|
|
39
|
+
Regexp.new('^' + a.map {|x| x.to_s}.join('/\w+/') + '[/\w]*$')
|
14
40
|
end
|
41
|
+
|
42
|
+
# Valid formats for REST API
|
43
|
+
# See http://docs.geoserver.org/stable/en/user/rest/api/details.html
|
44
|
+
URI_FORMATS = %w{xml json html sld zip}.map(&:to_sym)
|
45
|
+
|
46
|
+
# See http://docs.geoserver.org/latest/en/user/rest/api/
|
47
|
+
# @param [Hash] base, examples:
|
48
|
+
# - { :workspaces => nil }
|
49
|
+
#
|
50
|
+
# @param [Hash] options
|
51
|
+
# @return [String] baseURL for REST API, e.g.,:
|
52
|
+
# - settings.xml
|
53
|
+
# - layers/_name_.xml
|
54
|
+
# - styles/_name_.xml
|
55
|
+
# - workspaces/_name_.xml
|
56
|
+
# - workspaces/_name_/settings.xml
|
57
|
+
# - namespaces/_name_.xml
|
58
|
+
# - workspaces/_name_/datastores/_name_.xml
|
59
|
+
# - workspaces/_name_/datastores/_name_/featuretype/_name_.xml
|
60
|
+
def url_for base, options = {}
|
61
|
+
raise GeoServerArgumentError, "options must be Hash" unless options.is_a? Hash
|
62
|
+
if base.is_a? String
|
63
|
+
$stderr.puts "WARNING: deprecated usage -- base should be Hash"
|
64
|
+
base = { base.to_sym => nil } if base.is_a? String
|
65
|
+
end
|
15
66
|
|
67
|
+
base = Hash[base.map {|k,v| [k.to_sym, v]}] unless base.keys.select {|k| not k.is_a? Symbol}.size == 0
|
68
|
+
|
69
|
+
format = (options.delete(:format) if options.include?(:format)) || :xml
|
70
|
+
raise GeoServerArgumentError, "Unknown REST API format: '#{format}'" unless URI_FORMATS.include?(format)
|
71
|
+
|
72
|
+
new_base = base.collect {|k,v| v.nil?? "#{k}" : "#{k}/#{v}"}.join('/').to_s
|
73
|
+
new_base = new_base.gsub(%r{/$}, '')
|
74
|
+
|
75
|
+
raise GeoServerArgumentError, "Invalid REST URI syntax: #{new_base} from #{base}" unless URI_REGEX.each.select {|r| r.match(new_base)}.size > 0
|
76
|
+
|
77
|
+
new_base += ".#{format}"
|
78
|
+
if not options.empty?
|
79
|
+
new_base += "?" + options.collect {|k,v| [CGI::escape(k.to_s), CGI::escape(v.to_s)].join('=')}.join('&')
|
80
|
+
end
|
81
|
+
ap "url_for: #{base} #{options} => #{new_base}" if $DEBUG
|
82
|
+
new_base
|
83
|
+
end
|
84
|
+
|
85
|
+
# See http://docs.geoserver.org/latest/en/user/rest/api/
|
86
|
+
# @param [Hash] sequence with values. Note that the sequence can end in a nil, but none of the preceding elements may be nil
|
87
|
+
# - 'workspaces'
|
88
|
+
# - { :workspaces => nil }
|
89
|
+
# - { :workspaces => 'default', :datastores => nil }
|
90
|
+
# - { :about => 'version' }
|
91
|
+
#
|
92
|
+
# @param [Hash] options :format. See `URI_FORMATS`
|
93
|
+
#
|
94
|
+
# @return [String] baseURL for REST API, e.g.,:
|
95
|
+
# - workspaces.xml
|
96
|
+
# - workspaces/_name_.json
|
97
|
+
# - workspaces/_name_/datastores.xml
|
98
|
+
# - workspaces/_name_/datastores/_name_/featuretype/_name_.xml
|
99
|
+
#
|
100
|
+
# @raise [GeoServerArgumentError] if sequence is invalid
|
101
|
+
# def url_for_NOT_READY sequence, options = { }
|
102
|
+
# if sequence.is_a? Hash
|
103
|
+
# # ap "url_for(String): #{sequence}"
|
104
|
+
# new_base = sequence
|
105
|
+
# else
|
106
|
+
# # ap "url_for(Hash): #{sequence}"
|
107
|
+
# raise GeoServerArgumentError, "sequence must be Hash" unless sequence.is_a? Hash
|
108
|
+
# if sequence.keys.select {|k| k.is_a? Symbol}.empty?
|
109
|
+
# raise GeoServerArgumentError, "Sequence must use symbol keys: #{sequence}"
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# raise GeoServerArgumentError, "Invalid sequence: #{sequence}" unless URI_SEQUENCES.include?(sequence.keys.to_a)
|
113
|
+
#
|
114
|
+
# # sequence can end in a nil, but none of the preceding elements may
|
115
|
+
# if sequence.size > 1
|
116
|
+
# sequence.keys.slice(0..-2).reverse_each do |k|
|
117
|
+
# raise GeoServerArgumentError, "Missing required sequence value for #{k}: #{sequence}" if sequence[k] == nil
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# # `about` sequence can only be :version or :manifest
|
122
|
+
# if sequence.include?(:about) and not [:manifest, :version].include?(sequence[:about])
|
123
|
+
# raise GeoServerArgumentError, "Missing required sequence symbol for about [:manifest, :version]: #{sequence}"
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# if sequence.keys == [:layers, :styles]
|
127
|
+
# raise GeoServerArgumentError, "Cannot retrieve specific layer style: #{sequence}" if sequence[:styles] != nil
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# raise GeoServerArgumentError, "options must be Hash: #{options}" unless options.is_a? Hash
|
131
|
+
# format = options.delete(:format) || :xml
|
132
|
+
# raise GeoServerArgumentError, "Unknown REST API format: '#{format}'" unless URI_FORMATS.include?(format)
|
133
|
+
#
|
134
|
+
# new_base = sequence.collect {|k,v| v.nil?? "#{k}" : "#{k}/#{v}"}.join('/')
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# raise TypeError if new_base.is_a? String if $DEBUG
|
138
|
+
#
|
139
|
+
# new_base = new_base.gsub(/\/$/,'')
|
140
|
+
# new_base += ".#{format}"
|
141
|
+
# if not options.empty?
|
142
|
+
# new_base += "?" + CGI::escape(options.collect {|k,v| "#{k}=#{v}"}.join('&'))
|
143
|
+
# end
|
144
|
+
# new_base
|
145
|
+
# end
|
16
146
|
end
|
17
147
|
end
|
data/lib/rgeoserver/layer.rb
CHANGED
@@ -98,14 +98,22 @@ module RGeoServer
|
|
98
98
|
|
99
99
|
# @param [RGeoServer::Catalog] catalog
|
100
100
|
# @param [Hash] options
|
101
|
-
# @option options [String] :name
|
101
|
+
# @option options [String] :name required
|
102
102
|
# @option options [String] :default_style
|
103
103
|
# @option options [Array<String>] :alternate_styles
|
104
104
|
def initialize catalog, options
|
105
|
-
super(
|
105
|
+
super(catalog)
|
106
106
|
_run_initialize_callbacks do
|
107
|
-
|
108
|
-
|
107
|
+
if options[:name].instance_of? Layer
|
108
|
+
options[:name] = options[:name].name.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
raise GeoServerArgumentError, "Layer requires :name option" unless options.include? :name and options[:name].is_a? String
|
112
|
+
@name = options[:name].to_s.strip
|
113
|
+
ap({:init_name => @name}) if $DEBUG
|
114
|
+
|
115
|
+
raise NotImplementedError, ":default_style" if options.include? :default_style
|
116
|
+
raise NotImplementedError, ":alternate_styles" if options.include? :alternate_styles
|
109
117
|
#@default_style = options[:default_style] || ''
|
110
118
|
#@alternate_styles = options[:alternate_styles] || []
|
111
119
|
end
|
@@ -116,7 +124,7 @@ module RGeoServer
|
|
116
124
|
if r.is_a?(RGeoServer::Coverage) || r.is_a?(RGeoServer::FeatureType)
|
117
125
|
@resource = r
|
118
126
|
else
|
119
|
-
raise 'Unknown resource type'
|
127
|
+
raise GeoServerArgumentError, 'Unknown resource type: #{r.class}'
|
120
128
|
end
|
121
129
|
end
|
122
130
|
|
@@ -132,9 +140,17 @@ module RGeoServer
|
|
132
140
|
when 'coverage'
|
133
141
|
return RGeoServer::Coverage.new @catalog, :workspace => workspace, :coverage_store => store, :name => name
|
134
142
|
when 'featureType'
|
135
|
-
|
143
|
+
ap({:catalog => @catalog, :workspace => workspace, :data_store => store, :name => name}) if $DEBUG
|
144
|
+
begin
|
145
|
+
ft = RGeoServer::FeatureType.new @catalog, :workspace => workspace, :data_store => store, :name => name
|
146
|
+
ap({:featureType => ft, :route => ft.route}) if $DEBUG
|
147
|
+
rescue Exception => e
|
148
|
+
ap({:errormsg => "#{e}", :error => e, :trace => e.backtrace}) if $DEBUG
|
149
|
+
end
|
150
|
+
|
151
|
+
return ft
|
136
152
|
else
|
137
|
-
raise 'Unknown resource type'
|
153
|
+
raise GeoServerArgumentError, 'Unknown resource type: #{data_type}'
|
138
154
|
end
|
139
155
|
else
|
140
156
|
nil
|
@@ -146,11 +162,11 @@ module RGeoServer
|
|
146
162
|
|
147
163
|
# TODO: Simplify if necessary with "/layers/<l>/styles[.<format>]", as specified in the API
|
148
164
|
def get_default_style &block
|
149
|
-
self.class.list Style, @catalog, @default_style, {:layer => self},
|
165
|
+
self.class.list Style, @catalog, @default_style, {:layer => self}, false, &block
|
150
166
|
end
|
151
167
|
|
152
168
|
def get_alternate_styles &block
|
153
|
-
self.class.list Style, @catalog, @alternate_styles, {:layer => self},
|
169
|
+
self.class.list Style, @catalog, @alternate_styles, {:layer => self}, false, &block
|
154
170
|
end
|
155
171
|
|
156
172
|
def profile_xml_to_hash profile_xml
|
@@ -179,7 +195,7 @@ module RGeoServer
|
|
179
195
|
"store" => store,
|
180
196
|
"workspace" => workspace
|
181
197
|
},
|
182
|
-
"metadata" => doc.xpath('//metadata/entry').inject({}){ |
|
198
|
+
"metadata" => doc.xpath('//metadata/entry').inject({}){ |h2, e| h2.merge(e['key']=> e.text.to_s) }
|
183
199
|
}.freeze
|
184
200
|
h
|
185
201
|
end
|
@@ -188,6 +204,12 @@ module RGeoServer
|
|
188
204
|
resource.workspace
|
189
205
|
end
|
190
206
|
|
207
|
+
# Return full name of resource with namespace prefix
|
208
|
+
def prefixed_name
|
209
|
+
return "#{workspace.name}:#{name}" if self.respond_to?(:workspace)
|
210
|
+
raise "Workspace is not defined for this resource"
|
211
|
+
end
|
212
|
+
|
191
213
|
#= GeoWebCache Operations for this layer
|
192
214
|
# See http://geowebcache.org/docs/current/rest/seed.html
|
193
215
|
# See RGeoServer::Catalog.seed_terminate for stopping pending and/or running tasks for any layer
|
@@ -202,6 +224,8 @@ module RGeoServer
|
|
202
224
|
# :threadCount => 1
|
203
225
|
# }
|
204
226
|
# > lyr.seed :issue, options
|
227
|
+
#
|
228
|
+
# @see http://geowebcache.org/docs/current/rest/
|
205
229
|
|
206
230
|
# @param[String] operation
|
207
231
|
# @option operation[Symbol] :issue seed
|
@@ -213,16 +237,25 @@ module RGeoServer
|
|
213
237
|
sub_path = "seed/#{prefixed_name}.xml"
|
214
238
|
case op
|
215
239
|
when :issue
|
216
|
-
@catalog.do_url sub_path, :post,
|
240
|
+
@catalog.do_url sub_path, :post, _build_seed_request(:seed, options), {}, @catalog.gwc_client
|
217
241
|
when :truncate
|
218
|
-
@catalog.do_url sub_path, :post,
|
242
|
+
@catalog.do_url sub_path, :post, _build_seed_request(:truncate, options), {}, @catalog.gwc_client
|
219
243
|
when :status
|
220
|
-
raise NotImplementedError
|
244
|
+
raise NotImplementedError, "#{op}"
|
221
245
|
end
|
222
246
|
end
|
223
247
|
|
224
|
-
|
225
|
-
|
248
|
+
private
|
249
|
+
# @param[Hash] options for seed message, requiring
|
250
|
+
# options[:srs][:number]
|
251
|
+
# options[:bounds][:coords]
|
252
|
+
# options[:gridSetId]
|
253
|
+
# options[:zoomStart]
|
254
|
+
# options[:zoomStop]
|
255
|
+
# options[:gridSetId]
|
256
|
+
# options[:gridSetId]
|
257
|
+
#
|
258
|
+
def _build_seed_request operation, options
|
226
259
|
builder = Nokogiri::XML::Builder.new do |xml|
|
227
260
|
xml.seedRequest {
|
228
261
|
xml.name prefixed_name
|
@@ -241,9 +274,11 @@ module RGeoServer
|
|
241
274
|
|
242
275
|
xml.type_ operation
|
243
276
|
|
244
|
-
[:gridSetId, :zoomStart, :zoomStop, :
|
277
|
+
[:gridSetId, :zoomStart, :zoomStop, :threadCount].each { |p|
|
245
278
|
eval "xml.#{p.to_s} options[p]" unless options[p].nil?
|
246
279
|
}
|
280
|
+
|
281
|
+
xml.format_ options[:tileFormat] unless options[:tileFormat].nil?
|
247
282
|
|
248
283
|
xml.parameters {
|
249
284
|
options[:parameters].each_pair { |k,v|
|
@@ -255,6 +290,7 @@ module RGeoServer
|
|
255
290
|
} if options[:parameters].is_a?(Hash)
|
256
291
|
}
|
257
292
|
end
|
293
|
+
ap({:build_seed_request => builder.doc}) if $DEBUG
|
258
294
|
return builder.doc.to_xml
|
259
295
|
end
|
260
296
|
end
|
@@ -68,9 +68,8 @@ module RGeoServer
|
|
68
68
|
# @param [Hash] options
|
69
69
|
# @option options [String] :name
|
70
70
|
def initialize catalog, options
|
71
|
-
super(
|
71
|
+
super(catalog)
|
72
72
|
_run_initialize_callbacks do
|
73
|
-
@catalog = catalog
|
74
73
|
@name = options[:name].strip
|
75
74
|
@workspace = options[:workspace]
|
76
75
|
end
|
data/lib/rgeoserver/namespace.rb
CHANGED
@@ -41,9 +41,8 @@ module RGeoServer
|
|
41
41
|
# @param [RGeoServer::Catalog] catalog
|
42
42
|
# @param [Hash] options
|
43
43
|
def initialize catalog, options
|
44
|
-
super(
|
44
|
+
super(catalog)
|
45
45
|
_run_initialize_callbacks do
|
46
|
-
@catalog = catalog
|
47
46
|
@name = options[:name].strip
|
48
47
|
@uri = options[:uri] if options[:uri]
|
49
48
|
end
|