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