rgeoserver 0.5.5 → 0.5.6
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 +6 -3
- data/VERSION +1 -1
- data/lib/rgeoserver/catalog.rb +34 -8
- data/lib/rgeoserver/coverage.rb +71 -72
- data/lib/rgeoserver/coveragestore.rb +72 -82
- data/lib/rgeoserver/datastore.rb +84 -94
- data/lib/rgeoserver/featuretype.rb +71 -77
- data/lib/rgeoserver/layer.rb +128 -135
- data/lib/rgeoserver/layergroup.rb +138 -0
- data/lib/rgeoserver/resource.rb +2 -3
- data/lib/rgeoserver/rest_api_client.rb +7 -5
- data/lib/rgeoserver/style.rb +83 -88
- data/lib/rgeoserver/wmsstore.rb +6 -16
- data/lib/rgeoserver/workspace.rb +70 -77
- data/lib/rgeoserver.rb +1 -0
- data/spec/fixtures/datasets/vector/granules.qix +0 -0
- data/spec/lib/integration_test_spec.rb +63 -4
- metadata +31 -28
data/lib/rgeoserver/style.rb
CHANGED
@@ -1,104 +1,99 @@
|
|
1
1
|
|
2
2
|
module RGeoServer
|
3
|
+
# A style describes how a resource (feature type or coverage) should be symbolized or rendered by a Web Map Service. In GeoServer styles are specified with {SLD}[http://docr.geoserver.org/stable/en/user/styling/index.html#styling]
|
4
|
+
class Style < ResourceInfo
|
3
5
|
|
4
|
-
|
6
|
+
OBJ_ATTRIBUTES = {:catalog => 'catalog', :name => 'name', :sld_version => 'sldVersion', :filename => 'filename', :sld_doc => 'sld_doc' }
|
7
|
+
OBJ_DEFAULT_ATTRIBUTES = {:catalog => nil, :name => nil, :sld_version => nil, :filename => '', :sld_doc => nil }
|
5
8
|
|
6
|
-
|
7
|
-
|
9
|
+
define_attribute_methods OBJ_ATTRIBUTES.keys
|
10
|
+
update_attribute_accessors OBJ_ATTRIBUTES
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
@@route = "styles"
|
13
|
+
@@resource_name = "style"
|
14
|
+
@@sld_namespace = "http://www.opengis.net/sld"
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@@r.resource_name
|
16
|
-
end
|
16
|
+
def self.resource_name
|
17
|
+
@@resource_name
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
def self.root_xpath
|
21
|
+
"//#{@@route}/#{@@resource_name}"
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def self.root_xpath
|
27
|
-
"//#{@@r.route}/#{@@r.resource_name}"
|
28
|
-
end
|
24
|
+
def self.member_xpath
|
25
|
+
"//#{resource_name}"
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
def route
|
29
|
+
@@route
|
30
|
+
end
|
31
|
+
|
32
|
+
def sld_namespace
|
33
|
+
@@sld_namespace
|
34
|
+
end
|
33
35
|
|
34
|
-
def route
|
35
|
-
@@r.route
|
36
|
-
end
|
37
|
-
|
38
|
-
def create_options
|
39
|
-
{
|
40
|
-
:headers => {
|
41
|
-
:accept => :xml,
|
42
|
-
:content_type=> "application/vnd.ogc.sld+xml"
|
43
|
-
},
|
44
|
-
:format => :xml,
|
45
|
-
:name => @name
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
def update_options
|
50
|
-
{
|
51
|
-
:headers => {
|
52
|
-
:accept => :xml,
|
53
|
-
:content_type=> "application/vnd.ogc.sld+xml"
|
54
|
-
},
|
55
|
-
:format => :sld
|
56
|
-
}
|
57
|
-
end
|
58
36
|
|
59
|
-
|
60
|
-
|
61
|
-
|
37
|
+
def create_options
|
38
|
+
{
|
39
|
+
:headers => {
|
40
|
+
:accept => :xml,
|
41
|
+
:content_type=> "application/vnd.ogc.sld+xml"
|
42
|
+
},
|
43
|
+
:format => :xml,
|
44
|
+
:name => @name
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_options
|
49
|
+
{
|
50
|
+
:headers => {
|
51
|
+
:accept => :xml,
|
52
|
+
:content_type=> "application/vnd.ogc.sld+xml"
|
53
|
+
},
|
54
|
+
:format => :sld
|
55
|
+
}
|
56
|
+
end
|
62
57
|
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
def message
|
59
|
+
@sld_doc
|
60
|
+
end
|
66
61
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
# Obtain all layers that use this style.
|
79
|
-
# WARNING: This will be slow and inneficient when the list of all layers is too long.
|
80
|
-
def layers &block
|
81
|
-
return to_enum(:layers).to_a unless block_given?
|
82
|
-
@catalog.get_layers do |l|
|
83
|
-
lyrs = [l.profile['default_style']]+l.profile['alternate_styles']
|
84
|
-
yield l if lyrs.include? @name
|
85
|
-
end
|
86
|
-
end
|
62
|
+
# @param [RGeoServer::Catalog] catalog
|
63
|
+
# @param [Hash] options
|
64
|
+
def initialize catalog, options
|
65
|
+
super({})
|
66
|
+
_run_initialize_callbacks do
|
67
|
+
@catalog = catalog
|
68
|
+
@name = options[:name].strip
|
69
|
+
end
|
70
|
+
@route = route
|
71
|
+
end
|
87
72
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
rescue RestClient::ResourceNotFound
|
97
|
-
nil
|
98
|
-
end
|
99
|
-
}.freeze
|
100
|
-
h
|
101
|
-
end
|
102
|
-
|
73
|
+
# Obtain all layers that use this style.
|
74
|
+
# WARNING: This will be slow and inneficient when the list of all layers is too long.
|
75
|
+
def layers &block
|
76
|
+
return to_enum(:layers).to_a unless block_given?
|
77
|
+
@catalog.get_layers do |l|
|
78
|
+
lyrs = [l.profile['default_style']]+l.profile['alternate_styles']
|
79
|
+
yield l if lyrs.include? @name
|
80
|
+
end
|
103
81
|
end
|
82
|
+
|
83
|
+
def profile_xml_to_hash profile_xml
|
84
|
+
doc = profile_xml_to_ng profile_xml
|
85
|
+
h = {
|
86
|
+
'name' => doc.at_xpath('//name').text.strip,
|
87
|
+
'sld_version' => doc.at_xpath('//sldVersion/version/text()').to_s,
|
88
|
+
'filename' => doc.at_xpath('//filename/text()').to_s,
|
89
|
+
'sld_doc' => begin
|
90
|
+
Nokogiri::XML(@catalog.search({:styles => @name}, options={:format => 'sld'})).to_xml
|
91
|
+
rescue RestClient::ResourceNotFound
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
}.freeze
|
95
|
+
h
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
104
99
|
end
|
data/lib/rgeoserver/wmsstore.rb
CHANGED
@@ -5,26 +5,16 @@ module RGeoServer
|
|
5
5
|
|
6
6
|
define_attribute_methods [:catalog, :workspace, :name]
|
7
7
|
|
8
|
-
@@
|
9
|
-
|
10
|
-
|
11
|
-
:resource_name => "wmsStore"
|
12
|
-
)
|
8
|
+
@@route = "workspaces/%s/wmsstores"
|
9
|
+
@@root = "wmsStores"
|
10
|
+
@@resource_name = "wmsStore"
|
13
11
|
|
14
12
|
def self.root
|
15
|
-
@@
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.create_method
|
19
|
-
:put
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.update_method
|
23
|
-
:put
|
13
|
+
@@root
|
24
14
|
end
|
25
15
|
|
26
16
|
def self.resource_name
|
27
|
-
@@
|
17
|
+
@@resource_name
|
28
18
|
end
|
29
19
|
|
30
20
|
def self.root_xpath
|
@@ -36,7 +26,7 @@ module RGeoServer
|
|
36
26
|
end
|
37
27
|
|
38
28
|
def route
|
39
|
-
@@
|
29
|
+
@@route % @workspace.name
|
40
30
|
end
|
41
31
|
|
42
32
|
def xml options = nil
|
data/lib/rgeoserver/workspace.rb
CHANGED
@@ -1,95 +1,88 @@
|
|
1
1
|
|
2
2
|
module RGeoServer
|
3
|
+
# A workspace is a grouping of data stores. More commonly known as a namespace, it is commonly used to group data that is related in some way.
|
4
|
+
class Workspace < ResourceInfo
|
3
5
|
|
4
|
-
|
6
|
+
OBJ_ATTRIBUTES = {:enabled => 'enabled', :catalog => 'catalog', :name => 'name' }
|
7
|
+
OBJ_DEFAULT_ATTRIBUTES = {:enabled => 'true', :catalog => nil, :name => nil }
|
5
8
|
|
6
|
-
|
7
|
-
|
9
|
+
define_attribute_methods OBJ_ATTRIBUTES.keys
|
10
|
+
update_attribute_accessors OBJ_ATTRIBUTES
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
@@route = "workspaces"
|
13
|
+
@@resource_name = "workspace"
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@@r.resource_name
|
16
|
-
end
|
15
|
+
def self.resource_name
|
16
|
+
@@resource_name
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
def self.root_xpath
|
20
|
+
"//#{@@route}/#{@@resource_name}"
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def self.root_xpath
|
27
|
-
"//#{@@r.route}/#{@@r.resource_name}"
|
28
|
-
end
|
23
|
+
def self.member_xpath
|
24
|
+
"//#{resource_name}"
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
def route
|
28
|
+
@@route
|
29
|
+
end
|
33
30
|
|
34
|
-
|
35
|
-
|
31
|
+
def message
|
32
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
33
|
+
xml.workspace {
|
34
|
+
xml.enabled @enabled if enabled_changed?
|
35
|
+
xml.name @name
|
36
|
+
}
|
36
37
|
end
|
38
|
+
return builder.doc.to_xml
|
39
|
+
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
+
end
|
49
|
+
@route = route
|
50
|
+
end
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
@route = route
|
57
|
-
end
|
52
|
+
def data_stores &block
|
53
|
+
self.class.list DataStore, @catalog, profile['dataStores'], {:workspace => self}, check_remote = true, &block
|
54
|
+
end
|
55
|
+
|
56
|
+
def coverage_stores &block
|
57
|
+
self.class.list CoverageStore, @catalog, profile['coverageStores'], {:workspace => self}, check_remote = true, &block
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def coverage_stores &block
|
64
|
-
self.class.list CoverageStore, @catalog, profile['coverageStores'], {:workspace => self}, check_remote = true, &block
|
65
|
-
end
|
60
|
+
def wms_stores &block
|
61
|
+
self.class.list WmsStore, @catalog, profile['wmsStores'], {:workspace => self}, check_remote = true, &block
|
62
|
+
end
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
begin
|
78
|
-
h[l.parent.parent.name.to_s] << target
|
79
|
-
rescue
|
80
|
-
h[l.parent.parent.name.to_s] = []
|
81
|
-
end
|
82
|
-
else
|
83
|
-
h[l.parent.parent.name.to_s] = begin
|
84
|
-
response = @catalog.fetch_url l.text
|
85
|
-
Nokogiri::XML(response).xpath('//name').collect{ |a| a.text.strip }
|
86
|
-
rescue RestClient::ResourceNotFound
|
87
|
-
[]
|
88
|
-
end.freeze
|
64
|
+
def profile_xml_to_hash profile_xml
|
65
|
+
doc = profile_xml_to_ng profile_xml
|
66
|
+
h = {'name' => doc.at_xpath('//name').text.strip, 'enabled' => @enabled }
|
67
|
+
doc.xpath('//atom:link/@href', "xmlns:atom"=>"http://www.w3.org/2005/Atom").each{ |l|
|
68
|
+
target = l.text.match(/([a-zA-Z]+)\.xml$/)[1]
|
69
|
+
if !target.nil? && target != l.parent.parent.name.to_s.downcase
|
70
|
+
begin
|
71
|
+
h[l.parent.parent.name.to_s] << target
|
72
|
+
rescue
|
73
|
+
h[l.parent.parent.name.to_s] = []
|
89
74
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
75
|
+
else
|
76
|
+
h[l.parent.parent.name.to_s] = begin
|
77
|
+
response = @catalog.do_url l.text
|
78
|
+
Nokogiri::XML(response).xpath('//name').collect{ |a| a.text.strip }
|
79
|
+
rescue RestClient::ResourceNotFound
|
80
|
+
[]
|
81
|
+
end.freeze
|
82
|
+
end
|
83
|
+
}
|
84
|
+
h
|
94
85
|
end
|
86
|
+
|
87
|
+
end
|
95
88
|
end
|
data/lib/rgeoserver.rb
CHANGED
Binary file
|
@@ -5,6 +5,7 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
5
5
|
|
6
6
|
before(:all) do
|
7
7
|
@catalog = RGeoServer.catalog
|
8
|
+
@fixtures_dir = File.join(File.dirname(__FILE__), "/../fixtures/")
|
8
9
|
end
|
9
10
|
|
10
11
|
|
@@ -86,7 +87,8 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
86
87
|
lyr.default_style = 'rain'
|
87
88
|
lyr.alternate_styles = ['raster']
|
88
89
|
lyr.enabled = 'true'
|
89
|
-
|
90
|
+
lyr.resource = @catalog.get_coverage 'sf','sfdem', 'sfdem'
|
91
|
+
expect{ lyr.save }.to raise_error
|
90
92
|
end
|
91
93
|
|
92
94
|
it "should list layers" do
|
@@ -96,9 +98,33 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
101
|
+
context "LayerGroups" do
|
102
|
+
it "should instantiate a new group layer" do
|
103
|
+
lyrs = ['a','b','c'].collect{|l| RGeoServer::Layer.new @catalog, :name => l}
|
104
|
+
stys = ['s1','s2','s3','s4'].collect{|s| RGeoServer::Style.new @catalog, :name => s}
|
105
|
+
g = RGeoServer::LayerGroup.new @catalog, :name => 'test_group_layer'
|
106
|
+
g.layers = lyrs
|
107
|
+
g.styles = stys
|
108
|
+
g.new?.should == true
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should create a new group layer from existing layers and styles and delete it right after" do
|
112
|
+
g = RGeoServer::LayerGroup.new @catalog, :name => 'test_group_layer'
|
113
|
+
g.layers = @catalog.get_layers[1,2]
|
114
|
+
g.styles = @catalog.get_styles[1,2]
|
115
|
+
g.new?.should == true
|
116
|
+
g.save
|
117
|
+
# Bounds metadata should come back aggregated from the server
|
118
|
+
g.bounds['maxx'].should_not == ''
|
119
|
+
g.delete
|
120
|
+
g.new?.should == true
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
99
125
|
context "Styles" do
|
100
126
|
before :all do
|
101
|
-
sld_dir = File.join(
|
127
|
+
sld_dir = File.join(@fixtures_dir, 'styles')
|
102
128
|
@test_sld = Nokogiri::XML(File.new(File.join(sld_dir, 'test_style.sld')))
|
103
129
|
@pop_sld = Nokogiri::XML(File.new(File.join(sld_dir, 'poptest.sld')))
|
104
130
|
end
|
@@ -137,6 +163,8 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
137
163
|
before :all do
|
138
164
|
@ws = RGeoServer::Workspace.new @catalog, :name => 'test_workspace_for_stores'
|
139
165
|
@ws.save
|
166
|
+
@shapefile = File.join(@fixtures_dir, 'datasets/vector/granules.shp')
|
167
|
+
@raster = File.join(@fixtures_dir, 'datasets/raster/test.tif')
|
140
168
|
end
|
141
169
|
|
142
170
|
after :all do
|
@@ -164,7 +192,7 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
164
192
|
end
|
165
193
|
|
166
194
|
it "should create a datastore under existing workspace, update and delete it right after" do
|
167
|
-
ds = RGeoServer::DataStore.new @catalog, :workspace => @ws, :name => 'test', :connection_parameters => {"namespace"=>"http://test_workspace_for_stores", "url" => "file
|
195
|
+
ds = RGeoServer::DataStore.new @catalog, :workspace => @ws, :name => 'test', :connection_parameters => {"namespace"=>"http://test_workspace_for_stores", "url" => "file:#{@shapefile}"}
|
168
196
|
ds.new?.should == true
|
169
197
|
ds.save
|
170
198
|
ds.new?.should == false
|
@@ -179,6 +207,15 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
179
207
|
ds.profile['connectionParameters'].should == new_connection_parameters
|
180
208
|
ds.delete
|
181
209
|
end
|
210
|
+
|
211
|
+
it "should create a datastore under existing workspace and add a feature type that will also create a layer" do
|
212
|
+
ds = RGeoServer::DataStore.new @catalog, :workspace => @ws, :name => 'test', :connection_parameters => {"namespace"=>"http://test_workspace_for_stores", "url" => "file:#{@shapefile}"}
|
213
|
+
ds.new?.should == true
|
214
|
+
ds.save
|
215
|
+
ft = RGeoServer::FeatureType.new @catalog, :workspace => @ws, :data_store => ds, :name => 'granules'
|
216
|
+
ft.save
|
217
|
+
|
218
|
+
end
|
182
219
|
end
|
183
220
|
|
184
221
|
context "CoverageStores" do
|
@@ -189,7 +226,7 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
189
226
|
end
|
190
227
|
it "should create a coverage store under existing workspace, update and delete it right after" do
|
191
228
|
cs = RGeoServer::CoverageStore.new @catalog, :workspace => @ws, :name => 'test_coverage_store'
|
192
|
-
cs.url = "file
|
229
|
+
cs.url = "file://#{@raster}"
|
193
230
|
cs.description = 'description'
|
194
231
|
cs.enabled = 'true'
|
195
232
|
cs.data_type = 'GeoTIFF'
|
@@ -202,6 +239,28 @@ describe "Integration test against a GeoServer instance", :integration => true d
|
|
202
239
|
cs.description.should == 'new description'
|
203
240
|
cs.new?.should == false
|
204
241
|
end
|
242
|
+
it "should create a coverage store under existing workspace and add a coverage to it. A layer must be created as a result of this operation" do
|
243
|
+
cs = RGeoServer::CoverageStore.new @catalog, :workspace => @ws, :name => 'raster'
|
244
|
+
cs.url = "file://#{@raster}"
|
245
|
+
cs.description = 'description'
|
246
|
+
cs.enabled = 'true'
|
247
|
+
cs.data_type = 'GeoTIFF'
|
248
|
+
cs.save
|
249
|
+
c = RGeoServer::Coverage.new @catalog, :workspace => @ws, :coverage_store => cs, :name => 'raster'
|
250
|
+
c.title = 'Test Raster Layer'
|
251
|
+
#c.save
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "Catalog operations" do
|
256
|
+
it "should reload the catalog" do
|
257
|
+
@catalog.reload
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should reset the catalog" do
|
261
|
+
@catalog.reset
|
262
|
+
end
|
263
|
+
|
205
264
|
end
|
206
265
|
end
|
207
266
|
end
|