You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltacloud.apache.org by lu...@apache.org on 2013/02/06 00:04:25 UTC
[2/2] git commit: CIMI: Cleanup in CIMI base models
Updated Branches:
refs/heads/master c282e7a5a -> b2c15bc47
CIMI: Cleanup in CIMI base models
- CIMI::Model::Resource moved from base.rb to separate file
- The $select methods moved to a separate module
- CIMI::Model::Collection helpers now extend the Base class without
reopening it (extend CollectionMethods)
- CIMI::Model::Base methods layout reorganized to be more readable
Signed-off-by: Michal fojtik <mf...@redhat.com>
TrackedAt: http://tracker.deltacloud.org/patch/f76c0e6bdc4ec7ec6ba8686735e0baac9b9ce1aa
Project: http://git-wip-us.apache.org/repos/asf/deltacloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltacloud/commit/ed4cc825
Tree: http://git-wip-us.apache.org/repos/asf/deltacloud/tree/ed4cc825
Diff: http://git-wip-us.apache.org/repos/asf/deltacloud/diff/ed4cc825
Branch: refs/heads/master
Commit: ed4cc82574f8a90d0f3fc904b89bd689c339bd40
Parents: c282e7a
Author: Michal Fojtik <mf...@redhat.com>
Authored: Wed Jan 30 13:56:54 2013 +0100
Committer: David Lutterkort <lu...@redhat.com>
Committed: Tue Feb 5 14:56:08 2013 -0800
----------------------------------------------------------------------
server/lib/cimi/helpers/select_helper.rb | 62 +++++++
server/lib/cimi/models.rb | 23 +++-
server/lib/cimi/models/base.rb | 241 ++-----------------------
server/lib/cimi/models/collection.rb | 124 +++++++-------
server/lib/cimi/models/resource.rb | 188 +++++++++++++++++++
5 files changed, 346 insertions(+), 292 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltacloud/blob/ed4cc825/server/lib/cimi/helpers/select_helper.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/helpers/select_helper.rb b/server/lib/cimi/helpers/select_helper.rb
new file mode 100644
index 0000000..59ce034
--- /dev/null
+++ b/server/lib/cimi/helpers/select_helper.rb
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI
+ module Helpers
+ module SelectResourceMethods
+
+ def select_by(filter_opts)
+ return self if filter_opts.nil?
+ return self unless kind_of? CIMI::Model::Collection
+ if filter_opts.include? ','
+ return select_attributes(filter_opts.split(',').map{ |a| a.intern })
+ end
+ case filter_opts
+ when /^([\w\_]+)$/ then select_attributes([$1.intern])
+ when /^([\w\_]+)\[(\d+\-\d+)\]$/ then select_by_arr_range($1.intern, $2)
+ when /^([\w\_]+)\[(\d+)\]$/ then select_by_arr_index($1.intern, $2)
+ else self
+ end
+ end
+
+ def select_by_arr_index(attr, filter)
+ return self unless self.respond_to?(attr)
+ self.class.new(attr => [self.send(attr)[filter.to_i]])
+ end
+
+ def select_by_arr_range(attr, filter)
+ return self unless self.respond_to?(attr)
+ filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
+ self.class.new(attr => self.send(attr)[filter])
+ end
+
+ end
+
+ module SelectBaseMethods
+ def select_attributes(attr_list)
+ attrs = attr_list.inject({}) do |result, attr|
+ attr = attr.to_s.underscore
+ result[attr.to_sym] = self.send(attr) if self.respond_to?(attr)
+ result
+ end
+ self.class.new(attrs.merge(
+ :select_attr_list => attr_list,
+ :base_id => self.send(:id)
+ ))
+ end
+ end
+
+ end
+end
http://git-wip-us.apache.org/repos/asf/deltacloud/blob/ed4cc825/server/lib/cimi/models.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
index 356f5a7..20c0ef1 100644
--- a/server/lib/cimi/models.rb
+++ b/server/lib/cimi/models.rb
@@ -13,8 +13,26 @@
# License for the specific language governing permissions and limitations
# under the License.
#
+
module CIMI
- module Model; end
+ module Model
+ def self.register_as_root_entity!(klass, opts = {})
+ @root_entities ||= [CIMI::Model::CloudEntryPoint]
+ @root_entities << klass
+ name = klass.name.split("::").last.pluralize
+ unless CIMI::Model::CloudEntryPoint.href_defined?(name)
+ params = {}
+ if opts[:as]
+ params[:xml_name] = params[:json_name] = opts[:as]
+ end
+ CIMI::Model::CloudEntryPoint.send(:href, name.underscore, params)
+ end
+ end
+
+ def self.root_entities
+ @root_entities || []
+ end
+ end
end
require 'require_relative' if RUBY_VERSION < '1.9'
@@ -31,8 +49,9 @@ unless Deltacloud.test_environment?
end
require_relative './models/schema'
-require_relative './models/base'
+require_relative './models/resource'
require_relative './models/collection'
+require_relative './models/base'
require_relative './models/errors'
require_relative './models/action'
require_relative './models/machine_volume'
http://git-wip-us.apache.org/repos/asf/deltacloud/blob/ed4cc825/server/lib/cimi/models/base.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
index c1ed579..c74b8c3 100644
--- a/server/lib/cimi/models/base.rb
+++ b/server/lib/cimi/models/base.rb
@@ -15,6 +15,8 @@
require 'xmlsimple'
+require_relative '../helpers/database_helper'
+
# The base class for any CIMI object that we either read from a request or
# write as a response. This class handles serializing/deserializing XML and
# JSON into a common form.
@@ -71,238 +73,21 @@ require 'xmlsimple'
module CIMI::Model
- def self.register_as_root_entity!(klass, opts = {})
- @root_entities ||= [CIMI::Model::CloudEntryPoint]
- @root_entities << klass
- name = klass.name.split("::").last.pluralize
- unless CIMI::Model::CloudEntryPoint.href_defined?(name)
- params = {}
- if opts[:as]
- params[:xml_name] = params[:json_name] = opts[:as]
- end
- CIMI::Model::CloudEntryPoint.send(:href, name.underscore, params)
- end
- end
-
- def self.root_entities
- @root_entities || []
- end
-
-end
-
-class CIMI::Model::Resource
-
- #
- # We keep the values of the attributes in a hash
- #
- attr_reader :attribute_values
-
- CMWG_NAMESPACE = "http://schemas.dmtf.org/cimi/1"
-
- # Keep the list of all attributes in an array +attributes+; for each
- # attribute, we also define a getter and a setter to access/change the
- # value for that attribute
- class << self
-
- def <<(model)
- clone_base_schema unless base_schema_cloned?
- member_name = model.name.split("::").last
- if ::Struct.const_defined?("CIMI_#{member_name}")
- ::Struct.send(:remove_const, "CIMI_#{member_name}")
- end
- member_symbol = member_name.underscore.pluralize.to_sym
- members = CIMI::Model::Schema::Array.new(member_symbol)
- members.struct.schema.attributes = model.schema.attributes
- base_schema.attributes << members
- end
-
- def base_schema
- @schema ||= CIMI::Model::Schema.new
- end
-
- def clone_base_schema
- @schema_duped = true
- @schema = Marshal::load(Marshal.dump(superclass.base_schema))
- end
-
- def base_schema_cloned?
- @schema_duped
- end
+ class Base < Resource
- private :clone_base_schema, :base_schema_cloned?
+ # Extend the base model with database methods
+ extend Deltacloud::Helpers::Database
- def inherited(child)
- child.instance_eval do
- def schema
- base_schema_cloned? ? @schema : clone_base_schema
- end
- end
- end
+ # Extend the base model with the collection handling methods
+ extend CIMI::Model::CollectionMethods
- def add_attributes!(names, attr_klass, &block)
- if self.respond_to? :schema
- schema.add_attributes!(names, attr_klass, &block)
- else
- base_schema.add_attributes!(names, attr_klass, &block)
- end
- names.each do |name|
- define_method(name) { self[name] }
- define_method(:"#{name}=") { |newval| self[name] = newval }
- end
- end
-
- # Return Array of links to current CIMI object
- def all_uri(context)
- self.all(context).map { |e| { :href => e.id } }
- end
- end
-
- extend CIMI::Model::Schema::DSL
-
- def [](a)
- @attribute_values[a]
- end
-
- def []=(a, v)
- return @attribute_values.delete(a) if v.nil?
- @attribute_values[a] = self.class.schema.convert(a, v)
- end
-
- # Prepare to serialize
- def prepare
- self.class.schema.collections.map { |coll| coll.name }.each do |n|
- if @select_attrs.empty? or @select_attrs.include?(n)
- self[n].href = "#{self.base_id}/#{n}" if !self[n].href
- self[n].id = "#{self.base_id}/#{n}" if !self[n].entries.empty?
- else
- self[n] = nil
- end
- end
- end
-
- #
- # Factory methods
- #
- def initialize(values = {})
- names = self.class.schema.attribute_names
- @select_attrs = values[:select_attr_list] || []
- # Make sure we always have the :id of the entity even
- # the $select parameter is used and :id is filtered out
+ # Include methods needed to handle the $select query parameter
+ include CIMI::Helpers::SelectBaseMethods
#
- @base_id = values[:base_id] || values[:id]
- @attribute_values = names.inject(OrderedHash.new) do |hash, name|
- hash[name] = self.class.schema.convert(name, values[name])
- hash
- end
- end
-
- def base_id
- self.id || @base_id
- end
-
- # Construct a new object from the XML representation +xml+
- def self.from_xml(text)
- xml = XmlSimple.xml_in(text, :force_content => true)
- model = self.new
- @schema.from_xml(xml, model)
- model
- end
-
- # Construct a new object
- def self.from_json(text)
- json = JSON::parse(text)
- model = self.new
- @schema.from_json(json, model)
- model
- end
-
- def self.parse(text, content_type)
- if content_type == "application/xml"
- from_xml(text)
- elsif content_type == "application/json"
- from_json(text)
- else
- raise "Can not parse content type #{content_type}"
- end
- end
-
- #
- # Serialize
- #
-
- def self.xml_tag_name
- self.name.split("::").last
- end
-
- def self.resource_uri
- CMWG_NAMESPACE + "/" + self.name.split("::").last
- end
-
- def self.to_json(model)
- json = @schema.to_json(model)
- json[:resourceURI] = resource_uri
- JSON::unparse(json)
- end
-
- def self.to_xml(model)
- xml = @schema.to_xml(model)
- xml["xmlns"] = CMWG_NAMESPACE
- xml["resourceURI"] = resource_uri
- XmlSimple.xml_out(xml, :root_name => xml_tag_name)
- end
-
- def to_json
- self.class.to_json(self)
- end
-
- def to_xml
- self.class.to_xml(self)
- end
-
- def select_by(filter_opts)
- return self if filter_opts.nil?
- return select_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
- case filter_opts
- when /^([\w\_]+)$/ then select_attributes([$1.intern])
- when /^([\w\_]+)\[(\d+\-\d+)\]$/ then select_by_arr_range($1.intern, $2)
- when /^([\w\_]+)\[(\d+)\]$/ then select_by_arr_index($1.intern, $2)
- else self
- end
- end
-
- def select_by_arr_index(attr, filter)
- return self unless self.respond_to?(attr)
- self.class.new(attr => [self.send(attr)[filter.to_i]])
- end
-
- def select_by_arr_range(attr, filter)
- return self unless self.respond_to?(attr)
- filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
- self.class.new(attr => self.send(attr)[filter])
- end
-end
-
-require_relative '../helpers/database_helper'
-
-class CIMI::Model::Base < CIMI::Model::Resource
- extend Deltacloud::Helpers::Database
- #
- # Common attributes for all resources
- #
- text :id, :name, :description, :created
-
- hash :property
-
- def select_attributes(attr_list)
- attrs = attr_list.inject({}) do |result, attr|
- attr = attr.to_s.underscore
- result[attr.to_sym] = self.send(attr) if self.respond_to?(attr)
- result
- end
- self.class.new(attrs.merge(
- :select_attr_list => attr_list,
- :base_id => self.send(:id)
- ))
+ # Common attributes for all resources
+ #
+ text :id, :name, :description, :created
+ hash :property
end
end
http://git-wip-us.apache.org/repos/asf/deltacloud/blob/ed4cc825/server/lib/cimi/models/collection.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models/collection.rb b/server/lib/cimi/models/collection.rb
index 931adcc..f36c081 100644
--- a/server/lib/cimi/models/collection.rb
+++ b/server/lib/cimi/models/collection.rb
@@ -19,10 +19,36 @@ module CIMI::Model
class << self
attr_accessor :entry_name, :embedded
+
+ def xml_tag_name
+ 'Collection'
+ end
+
+ def generate(model_class, opts = {})
+ model_name = model_class.name.split("::").last
+ scope = opts[:scope] || CIMI::Model
+ coll_class = Class.new(CIMI::Model::Collection)
+ scope.const_set(:"#{model_name}Collection", coll_class)
+ coll_class.entry_name = model_name.underscore.pluralize.to_sym
+ coll_class.embedded = opts[:embedded]
+ entry_schema = model_class.schema
+ coll_class.instance_eval do
+ text :id
+ scalar :href
+ text :count
+ scalar :href if opts[:embedded]
+ array self.entry_name, :schema => entry_schema, :xml_name => model_name
+ array :operations do
+ scalar :rel, :href
+ end
+ end
+ coll_class
+ end
+
end
# Make sure the base schema gets cloned
- self.schema
+ schema
# You can initialize collection by passing the Hash representation of the
# collection or passing another Collection object.
@@ -76,76 +102,50 @@ module CIMI::Model
end
self
end
-
- def self.xml_tag_name
- "Collection"
- end
-
- def self.generate(model_class, opts = {})
- model_name = model_class.name.split("::").last
- scope = opts[:scope] || CIMI::Model
- coll_class = Class.new(CIMI::Model::Collection)
- scope.const_set(:"#{model_name}Collection", coll_class)
- coll_class.entry_name = model_name.underscore.pluralize.to_sym
- coll_class.embedded = opts[:embedded]
- entry_schema = model_class.schema
- coll_class.instance_eval do
- text :id
- scalar :href
- text :count
- scalar :href if opts[:embedded]
- array self.entry_name, :schema => entry_schema, :xml_name => model_name
- array :operations do
- scalar :rel, :href
- end
- end
- coll_class
- end
end
- #
- # We need to reopen Base and add some stuff to avoid circular dependencies
- #
- class Base
- #
- # Toplevel collections
- #
+ module CollectionMethods
- class << self
+ def collection_class=(klass)
+ @collection_class = klass
+ end
- attr_accessor :collection_class
+ def collection_class
+ @collection_class
+ end
- def acts_as_root_entity(opts = {})
- self.collection_class = Collection.generate(self)
- CIMI::Model.register_as_root_entity! self, opts
- end
+ def acts_as_root_entity(opts = {})
+ self.collection_class = Collection.generate(self)
+ CIMI::Model.register_as_root_entity! self, opts
+ end
- # Return a collection of entities
- def list(context)
- entries = find(:all, context)
- desc = "#{self.name.split("::").last} Collection for the #{context.driver.name.capitalize} driver"
- acts_as_root_entity unless collection_class
- id = context.send("#{collection_class.entry_name}_url")
- ops = []
- cimi_entity = collection_class.entry_name.to_s.singularize
- cimi_create = "create_#{cimi_entity}_url"
- dcloud_create = context.deltacloud_create_method_for(cimi_entity)
- if(context.respond_to?(cimi_create) &&
- context.driver.respond_to?(dcloud_create)) ||
- provides?(cimi_entity)
- url = context.send(cimi_create)
- ops << { :rel => "add", :href => url }
- end
- collection_class.new(:id => id,
- :count => entries.size,
- :entries => entries,
- :operations => ops,
- :description => desc)
+ # Return a collection of entities
+ def list(context)
+ entries = find(:all, context)
+ desc = "#{self.name.split("::").last} Collection for the #{context.driver.name.capitalize} driver"
+ acts_as_root_entity unless collection_class
+ id = context.send("#{collection_class.entry_name}_url")
+ ops = []
+ cimi_entity = collection_class.entry_name.to_s.singularize
+ cimi_create = "create_#{cimi_entity}_url"
+ dcloud_create = context.deltacloud_create_method_for(cimi_entity)
+ if(context.respond_to?(cimi_create) &&
+ context.driver.respond_to?(dcloud_create)) ||
+ provides?(cimi_entity)
+ url = context.send(cimi_create)
+ ops << { :rel => "add", :href => url }
end
+ collection_class.new(:id => id,
+ :count => entries.size,
+ :entries => entries,
+ :operations => ops,
+ :description => desc)
end
- def self.all(context)
- find(:all, context)
+ def all(context)
+ find :all, context
end
+
end
+
end
http://git-wip-us.apache.org/repos/asf/deltacloud/blob/ed4cc825/server/lib/cimi/models/resource.rb
----------------------------------------------------------------------
diff --git a/server/lib/cimi/models/resource.rb b/server/lib/cimi/models/resource.rb
new file mode 100644
index 0000000..735aa6b
--- /dev/null
+++ b/server/lib/cimi/models/resource.rb
@@ -0,0 +1,188 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require_relative '../helpers/select_helper'
+
+module CIMI
+ module Model
+ class Resource
+
+ extend CIMI::Model::Schema::DSL
+ include CIMI::Helpers::SelectResourceMethods
+
+ #
+ # We keep the values of the attributes in a hash
+ #
+ attr_reader :attribute_values
+
+ CMWG_NAMESPACE = "http://schemas.dmtf.org/cimi/1"
+
+ #
+ # Factory methods
+ #
+ def initialize(values = {})
+ names = self.class.schema.attribute_names
+ @select_attrs = values[:select_attr_list] || []
+ # Make sure we always have the :id of the entity even
+ # the $select parameter is used and :id is filtered out
+ #
+ @base_id = values[:base_id] || values[:id]
+ @attribute_values = names.inject(OrderedHash.new) do |hash, name|
+ hash[name] = self.class.schema.convert(name, values[name])
+ hash
+ end
+ end
+
+ # The CIMI::Model::Resource class methods
+ class << self
+
+ def base_schema
+ @schema ||= CIMI::Model::Schema.new
+ end
+
+ def clone_base_schema
+ @schema_duped = true
+ @schema = Marshal::load(Marshal.dump(superclass.base_schema))
+ end
+
+ def base_schema_cloned?
+ @schema_duped
+ end
+
+ private :clone_base_schema, :base_schema_cloned?
+
+ # If the model is inherited by another model, we want to clone
+ # the base schema instead of using the parent model schema, which
+ # might be modified
+ #
+ def inherited(child)
+ child.instance_eval do
+ def schema
+ base_schema_cloned? ? @schema : clone_base_schema
+ end
+ end
+ end
+
+ def add_attributes!(names, attr_klass, &block)
+ if self.respond_to? :schema
+ schema.add_attributes!(names, attr_klass, &block)
+ else
+ base_schema.add_attributes!(names, attr_klass, &block)
+ end
+ names.each do |name|
+ define_method(name) { self[name] }
+ define_method(:"#{name}=") { |newval| self[name] = newval }
+ end
+ end
+
+ # Return Array of links to current CIMI object
+ #
+ def all_uri(context)
+ self.all(context).map { |e| { :href => e.id } }
+ end
+
+ # Construct a new object from the XML representation +xml+
+ def from_xml(text)
+ xml = XmlSimple.xml_in(text, :force_content => true)
+ model = self.new
+ @schema.from_xml(xml, model)
+ model
+ end
+
+ # Construct a new object
+ def from_json(text)
+ json = JSON::parse(text)
+ model = self.new
+ @schema.from_json(json, model)
+ model
+ end
+
+ def parse(text, content_type)
+ if content_type == "application/xml"
+ from_xml(text)
+ elsif content_type == "application/json"
+ from_json(text)
+ else
+ raise "Can not parse content type #{content_type}"
+ end
+ end
+
+ #
+ # Serialize
+ #
+
+ def xml_tag_name
+ self.name.split("::").last
+ end
+
+ def resource_uri
+ CMWG_NAMESPACE + "/" + self.name.split("::").last
+ end
+
+ def to_json(model)
+ json = @schema.to_json(model)
+ json[:resourceURI] = resource_uri
+ JSON::unparse(json)
+ end
+
+ def to_xml(model)
+ xml = @schema.to_xml(model)
+ xml["xmlns"] = CMWG_NAMESPACE
+ xml["resourceURI"] = resource_uri
+ XmlSimple.xml_out(xml, :root_name => xml_tag_name)
+ end
+ end
+
+ # END of class methods
+
+ def [](a)
+ @attribute_values[a]
+ end
+
+ def []=(a, v)
+ return @attribute_values.delete(a) if v.nil?
+ @attribute_values[a] = self.class.schema.convert(a, v)
+ end
+
+ # Apply the $select options to all sub-collections and prepare then
+ # to serialize by setting correct :href and :id attributes.
+ #
+ def prepare
+ self.class.schema.collections.map { |coll| coll.name }.each do |n|
+ if @select_attrs.empty? or @select_attrs.include?(n)
+ self[n].href = "#{self.base_id}/#{n}" if !self[n].href
+ self[n].id = "#{self.base_id}/#{n}" if !self[n].entries.empty?
+ else
+ self[n] = nil
+ end
+ end
+ end
+
+ def base_id
+ self.id || @base_id
+ end
+
+ def to_json
+ self.class.to_json(self)
+ end
+
+ def to_xml
+ self.class.to_xml(self)
+ end
+
+ end
+
+ end
+end