rgeoserver 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ coverage
2
+ coverage.data
3
+ pkg
4
+ rdoc
5
+ doc
6
+ .yardoc
7
+ .bundle
8
+ .rvmrc
9
+ Gemfile.lock
10
+ .DS_Store
11
+ .swp
12
+ .swo
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ #gem 'rake', '0.8.7'
6
+ gem 'activemodel', "~> 3.1.1"
7
+
8
+
data/README.rdoc ADDED
@@ -0,0 +1,80 @@
1
+ == RGeoServer
2
+
3
+ RGeoServer is a Ruby client for the GeoServer RESTful administrative interface.
4
+
5
+ It provides primitive Ruby model abstraction.
6
+
7
+ == Documentation
8
+ The GeoServer REST Configuration API Reference can be found here:
9
+
10
+ http://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html
11
+
12
+
13
+ == Installation
14
+
15
+ $ gem install rgeoserver
16
+
17
+
18
+ == Example:
19
+
20
+ > catalog = RGeoServer::Catalog.new :user=>"admin", :url=>"http://10.0.0.2/geoserver/rest", :password=>"osgeo!"
21
+ => Catalog: http://10.0.0.2/geoserver/rest
22
+ > w = catalog.get_workspace('topp')
23
+ => RGeoServer::Workspace: topp
24
+ > ds = w.data_stores.first
25
+ => RGeoServer::DataStore: states_shapefile
26
+ > ds.profile
27
+ => {"name"=>"states_shapefile", "enabled"=>"true", "connectionParameters"=>{"url"=>"file:data/shapefiles/states.shp", "namespace"=>"http://www.openplans.org/topp"}, "featureTypes"=>["states"]}
28
+ > ft = ds.featuretypes.first
29
+ => RGeoServer::FeatureType: states
30
+ > ft.profile
31
+ => {:name=>"states", :workspace=>"topp", :nativeName=>"states"}
32
+
33
+ == Testing
34
+ We use {jettywrapper}[https://github.com/projecthydra/jettywrapper] to wrap a test instance of GeoServer. In theory, you should be able to point to any other local installation. Suppose that you download the binary stable version 2.1.3 binary from {here}[http://sourceforge.net/project/downloading.php?groupname=geoserver&filename=geoserver-2.1.3-bin.zip&use_mirror=softlayer], then unzip it under say, /tmp/geoserver-2.1.3. The integration tests are executed as follows:
35
+ > rake integration['/tmp/geoserver-2.1.3','8080','-DGEOSERVER_DATA_DIR=data_dir']
36
+
37
+ To generate the documentation run:
38
+ > rake yard
39
+
40
+ To enter into an irb console with all classess loaded:
41
+ > rake console
42
+
43
+ == Related Resources
44
+ * {OSGeo The Open Source Geospatial Foundation}[http://www.osgeo.org]
45
+ * {GeoServer Project page}[http://docs.geoserver.org/stable/en/user/index.html]
46
+ * {GeoServer Catalog design}[http://bit.ly/JrX1J8]
47
+ * {GeoTools}[http://geotools.org/]
48
+ * Implementation in other languages:
49
+ * Python: {gsconfig.py}[https://github.com/dwins/gsconfig.py]
50
+
51
+ == Release History
52
+
53
+ - <b>v0.5.0</b> - Initial alpha release
54
+
55
+ == TODO
56
+ - Complete stores and coverages functionality, handle Layers, styles and data upload.
57
+ - Complete documentaion and test coverage. Add more flexibility for integration tests with embedded Jetty and other containers.
58
+ - Migrate base HTTP client to {Weary}[https://github.com/mwunsch/weary]?
59
+
60
+ == Contributing with Patches and Pull requests checklist
61
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
62
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
63
+ * Fork the project
64
+ * Start a feature/bugfix branch
65
+ * Commit and push until you are happy with your contribution
66
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
67
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
68
+
69
+
70
+ == Acknowledgements
71
+ Inspired on the Rubydora and RSolr gems. Followed somewhat closely to {gsconfig.py}[https://github.com/dwins/gsconfig.py]
72
+
73
+ == Contributors
74
+
75
+
76
+ == License
77
+
78
+ Copyright (c) 2011 Renzo Sanchez-Silva <renzo@stanford.edu>.
79
+
80
+ Licensed under the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'bundler/gem_tasks'
4
+
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+
13
+ # Get your spec rake tasks working in RSpec 2.0
14
+
15
+ require 'rspec/core/rake_task'
16
+
17
+ desc 'Default: run specs.'
18
+ task :default => :spec
19
+
20
+ desc "Run specs"
21
+ RSpec::Core::RakeTask.new do |t|
22
+ # Put spec opts in a file named .rspec in root
23
+ end
24
+
25
+ require 'yard'
26
+ YARD::Rake::YardocTask.new do |t|
27
+ t.options = ["--readme", "README.rdoc"]
28
+ end
29
+
30
+ desc "Open an irb session preloaded with this library"
31
+ task :console do
32
+ sh "irb -rubygems -I lib -r rgeoserver.rb"
33
+ end
34
+
35
+ desc "Execute integration tests"
36
+ task :integration, :jetty_home, :jetty_port, :java_opts do |t, args|
37
+
38
+ require 'jettywrapper'
39
+ jetty_params = {
40
+ :jetty_home => args.jetty_home,
41
+ :java_opts => [args.java_opts],
42
+ :jetty_port => args.jetty_port,
43
+ :quiet => true,
44
+ :startup_wait => 20
45
+ }
46
+
47
+ error = Jettywrapper.wrap(jetty_params) do
48
+ Rake::Task['spec'].invoke
49
+ end
50
+ raise "test failures: #{error}" if error
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
@@ -0,0 +1,9 @@
1
+ geoserver:
2
+ url: "http://localhost:8080/geoserver/rest"
3
+ user: admin
4
+ password: geoserver
5
+ ssl:
6
+ cert_file:
7
+ key_file:
8
+ key_pass: ""
9
+
data/lib/rgeoserver.rb ADDED
@@ -0,0 +1,45 @@
1
+ require 'active_model'
2
+ require 'yaml'
3
+
4
+ module RGeoServer
5
+ autoload :Config, "rgeoserver/config"
6
+ autoload :Catalog, "rgeoserver/catalog"
7
+ autoload :RestApiClient, "rgeoserver/rest_api_client"
8
+ autoload :GeoServerUrlHelpers, "rgeoserver/geoserver_url_helpers"
9
+ autoload :ResourceInfo, "rgeoserver/resource"
10
+ autoload :Workspace, "rgeoserver/workspace"
11
+ autoload :FeatureType, "rgeoserver/featuretype"
12
+ autoload :Coverage, "rgeoserver/coverage"
13
+ autoload :DataStore, "rgeoserver/datastore"
14
+ autoload :CoverageStore, "rgeoserver/coveragestore"
15
+ autoload :WmsStore, "rgeoserver/wmsstore"
16
+
17
+ require 'restclient'
18
+ require 'nokogiri'
19
+ require 'time'
20
+ require 'rgeoserver/version'
21
+
22
+ def self.connect *args
23
+ Catalog.new *args
24
+ end
25
+
26
+ def self.catalog
27
+ @catalog ||= self.connect(self.default_config.geoserver)
28
+ end
29
+
30
+ def self.catalog= catalog
31
+ @catalog = catalog
32
+ end
33
+
34
+ def self.default_config *args, &block
35
+ Config.configure *args, &block
36
+ end
37
+
38
+
39
+ class RGeoServerError < StandardError
40
+ end
41
+
42
+ class GeoServerInvalidRequest < RGeoServerError
43
+ end
44
+
45
+ end
@@ -0,0 +1,169 @@
1
+ module RGeoServer
2
+ # This class represents the main class of the data model.
3
+ # Refer to
4
+ # - http://geoserver.org/display/GEOS/Catalog+Design
5
+ # - http://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html#workspaces
6
+
7
+ class Catalog
8
+ include RGeoServer::RestApiClient
9
+ include ActiveSupport::Benchmarkable
10
+
11
+ attr_reader :config
12
+
13
+ # @param [OrderedHash] options
14
+ # @option options [String] :url
15
+ # @option options [String] :user
16
+ # @option options [String] :password
17
+ def initialize options = {}
18
+ @config = options
19
+ end
20
+
21
+ def to_s
22
+ "Catalog: #{@config[:url]}"
23
+ end
24
+
25
+ def client config = {}
26
+ c = self.config.merge(config)
27
+ @client ||= RestClient::Resource.new(c[:url], :user => c[:user], :password => c[:password], :headers => c[:headers])
28
+ end
29
+
30
+ def headers format
31
+ sym = :xml || format.to_sym
32
+ {:accept => sym, :content_type=> sym}
33
+ end
34
+
35
+ # List of workspaces available
36
+ # @return [Array<RGeoServer::Workspace>]
37
+ def get_workspaces
38
+ response = self.search :workspaces => nil
39
+ doc = Nokogiri::XML(response)
40
+ doc.xpath(Workspace.root_xpath).collect { |w| Workspace.new self, :name => w.text }
41
+ end
42
+
43
+ # @param [String] workspace
44
+ # @return [<RGeoServer::Workspace]
45
+ def get_workspace workspace
46
+ response = self.search :workspaces => workspace
47
+ doc = Nokogiri::XML(response)
48
+ name = doc.at_xpath(Workspace.member_xpath)
49
+ return Workspace.new self, :name => name.text if name
50
+ end
51
+
52
+ # @return [<RGeoServer::Workspace]
53
+ def get_default_workspace
54
+ return Workspace.new self, :name => 'default'
55
+ end
56
+
57
+ def set_default_workspace
58
+ raise NotImplementedError
59
+ end
60
+
61
+ # @param [String] store
62
+ # @param [String] workspace
63
+ def reassign_workspace store, workspace
64
+ pass
65
+ end
66
+
67
+ # List of feature types
68
+ # @return [Array<RGeoServer::Namespace>]
69
+ # TODO: Implement when the stable release includes it
70
+ def get_namespaces
71
+ raise NotImplementedError
72
+ end
73
+
74
+ def get_default_namespace
75
+ raise NotImplementedError
76
+ end
77
+
78
+ def set_default_namespace id, prefix, uri
79
+ raise NotImplementedError
80
+ end
81
+
82
+ #= Data Stores (Vector datasets)
83
+
84
+ # List of vector based spatial data
85
+ # @param [String] workspace
86
+ # @return [Array<RGeoServer::DataStore>]
87
+ def get_data_stores workspace = nil
88
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
89
+ ds = []
90
+ ws.each{ |w| ds += w.data_stores if w.data_stores }
91
+ ds
92
+ end
93
+
94
+ # @param [String] workspace
95
+ # @param [String] datastore
96
+ # @return [RGeoServer::DataStore]
97
+ def get_data_store workspace, datastore
98
+ response = self.search({:workspaces => workspace, :name => datastore})
99
+ doc = Nokogiri::XML(response)
100
+ name = doc.at_xpath(DataStore.member_xpath)
101
+ return DataStore.new self, workspace, name.text if name
102
+ end
103
+
104
+ # List of feature types
105
+ # @param [String] workspace
106
+ # @param [String] datastore
107
+ # @return [Array<RGeoServer::FeatureType>]
108
+ def get_feature_types workspace, datastore
109
+ pass
110
+
111
+ end
112
+
113
+ # @param [String] workspace
114
+ # @param [String] datastore
115
+ # @param [String] featuretype_id
116
+ # @return [RGeoServer::FeatureType]
117
+ def get_feature_type workspace, datastore, featuretype_id
118
+ pass
119
+
120
+ end
121
+
122
+
123
+ #= Coverages (Raster datasets)
124
+
125
+ # List of coverage stores
126
+ # @param [String] workspace
127
+ # @return [Array<RGeoServer::CoverageStore>]
128
+ def get_coverage_stores workspace = nil
129
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
130
+ cs = []
131
+ ws.each{ |w| cs += w.coverage_stores if w.coverage_stores }
132
+ cs
133
+ end
134
+
135
+ # @param [String] workspace
136
+ # @param [String] coveragestore
137
+ # @return [RGeoServer::CoverageStore]
138
+ def get_coverage_store workspace, coveragestore
139
+ response = self.search({:workspaces => workspace, :name => coveragestore})
140
+ doc = Nokogiri::XML(response)
141
+ name = doc.at_xpath(CoverageStore.member_xpath)
142
+ return CoverageStore.new self, workspace, name.text if name
143
+ end
144
+
145
+ #= WMS Stores (Web Map Services)
146
+ # TODO: Implement when the stable release includes it
147
+ # List of WMS stores.
148
+ # @param [String] workspace
149
+ # @return [Array<RGeoServer::WmsStore>]
150
+ def get_wms_stores workspace = nil
151
+ ws = workspace.nil?? get_workspaces : [get_workspace(workspace)]
152
+ cs = []
153
+ ws.each{ |w| cs += w.wms_stores if w.wms_stores }
154
+ cs
155
+ end
156
+
157
+ # @param [String] workspace
158
+ # @param [String] wmsstore
159
+ # @return [RGeoServer::WmsStore]
160
+ def get_wms_store workspace, wmsstore
161
+ response = self.search({:workspaces => workspace, :name => wmsstore})
162
+ doc = Nokogiri::XML(response)
163
+ name = doc.at_xpath(WmsStore.member_xpath)
164
+ return WmsStore.new self, workspace, name.text if name
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,7 @@
1
+ require 'confstruct/configuration'
2
+
3
+ module RGeoServer
4
+ Config = Confstruct::Configuration.new(YAML.load(File.read(File.expand_path('../../../config/config_defaults.yml', __FILE__))))
5
+ end
6
+
7
+
@@ -0,0 +1,84 @@
1
+
2
+ module RGeoServer
3
+
4
+ class Coverage < ResourceInfo
5
+
6
+ OBJ_ATTRIBUTES = {:catalog => "catalog", :name => "name", :workspace => "workspace", :enabled => "enabled" }
7
+ OBJ_DEFAULT_ATTRIBUTES = {:catalog => nil, :workspace => nil, :coverage_store => nil, :name => nil, :enabled => false }
8
+
9
+ define_attribute_methods OBJ_ATTRIBUTES.keys
10
+ update_attribute_accessors OBJ_ATTRIBUTES
11
+
12
+ @@r = Confstruct::Configuration.new(
13
+ :route => "workspaces/%s/coveragestores/%s/coverages",
14
+ :root => "coverages",
15
+ :resource_name => "coverage"
16
+ )
17
+
18
+ def self.root
19
+ @@r.root
20
+ end
21
+
22
+ def self.method
23
+ :put
24
+ end
25
+
26
+ def self.member_xpath
27
+ "//#{resource_name}"
28
+ end
29
+
30
+ def self.resource_name
31
+ @@r.resource_name
32
+ end
33
+
34
+ def route
35
+ @@r.route % [@workspace.name , @coverage_store.name]
36
+ end
37
+
38
+
39
+ # @param [RGeoServer::Catalog] catalog
40
+ # @param [Hash] options
41
+ def initialize catalog, options
42
+ super({})
43
+ _run_initialize_callbacks do
44
+ @catalog = catalog
45
+ workspace = options[:workspace] || 'default'
46
+ if workspace.instance_of? String
47
+ @workspace = @catalog.get_workspace(workspace)
48
+ elsif workspace.instance_of? Workspace
49
+ @workspace = workspace
50
+ else
51
+ raise "Not a valid workspace"
52
+ end
53
+ coverage_store = options[:coverage_store]
54
+ if coverage_store.instance_of? String
55
+ @coverage_store = CoverageStore.new @catalog, :workspace => @workspace, :name => coverage_store
56
+ elsif coverage_store.instance_of? CoverageStore
57
+ @coverage_store = coverage_store
58
+ else
59
+ raise "Not a valid coverage store"
60
+ end
61
+
62
+ @name = options[:name]
63
+ @type = options[:type]
64
+ @enabled = options[:enabled] || true
65
+ @route = route
66
+ end
67
+ end
68
+
69
+ def profile_xml_to_hash profile_xml
70
+ doc = profile_xml_to_ng profile_xml
71
+ h = {
72
+ "coverage_store" => @coverage_store.name,
73
+ "workspace" => @workspace.name,
74
+ "name" => doc.at_xpath('//name/text()').text.strip,
75
+ "nativeName" => doc.at_xpath('//nativeName/text()').to_s,
76
+ "title" => doc.at_xpath('//title/text()').to_s,
77
+ "supportedFormats" => doc.xpath('//supportedFormats/string/text()').collect{ |t| t.to_s }
78
+ }.freeze
79
+ h
80
+ end
81
+
82
+
83
+ end
84
+ end