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.
- data/README.rdoc +27 -8
- data/VERSION +1 -1
- data/config/config_defaults.yml +1 -0
- data/examples/batch_example.rb +105 -0
- data/examples/cluster_demo.rb +30 -0
- data/lib/rgeoserver.rb +1 -0
- data/lib/rgeoserver/catalog.rb +24 -19
- data/lib/rgeoserver/coverage.rb +43 -6
- data/lib/rgeoserver/coveragestore.rb +5 -1
- data/lib/rgeoserver/datastore.rb +3 -3
- data/lib/rgeoserver/featuretype.rb +54 -4
- data/lib/rgeoserver/layer.rb +115 -5
- data/lib/rgeoserver/layergroup.rb +1 -1
- data/lib/rgeoserver/namespace.rb +63 -0
- data/lib/rgeoserver/resource.rb +23 -3
- data/lib/rgeoserver/rest_api_client.rb +33 -18
- data/rgeoserver.gemspec +1 -1
- data/spec/fixtures/datasets/raster/test.tif +0 -0
- data/spec/functional/resource_spec.rb +13 -0
- data/spec/{lib/integration_test_spec.rb → integration/geoserver_spec.rb} +149 -9
- metadata +37 -30
@@ -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
|
data/lib/rgeoserver/layer.rb
CHANGED
@@ -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 = {
|
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
|
-
|
40
|
-
xml.
|
41
|
-
xml.
|
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
|
@@ -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
|
data/lib/rgeoserver/resource.rb
CHANGED
@@ -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
|
-
|
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 =
|
87
|
-
route =
|
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
|
-
|
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
|
40
|
-
# Default method is GET
|
41
|
-
# @param [String]
|
42
|
-
# @param [String] method
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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 -- {
|
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
|