deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core] CIMI: Initial implementation of $filter,$first and $last
Date Tue, 28 Aug 2012 14:17:36 GMT
From: Michal Fojtik <mfojtik@redhat.com>

* $filter will limit entities to those who patch the filter
  condition. (/machines?$filter=name=machine1)

* $first and $last will slice the array of elements in collection

Signed-off-by: Michal fojtik <mfojtik@redhat.com>
---
 server/lib/cimi/helpers.rb                         |    3 +
 server/lib/sinatra/rack_cimi_filter.rb             |  107 ++++++++++++++++++++
 server/tests/cimi/collections/cimi_filter_test.rb  |   50 +++++++++
 .../tests/cimi/collections/fixtures/sample1.json   |   25 +++++
 server/tests/cimi/collections/fixtures/sample1.xml |   22 ++++
 5 files changed, 207 insertions(+)
 create mode 100644 server/lib/sinatra/rack_cimi_filter.rb
 create mode 100644 server/tests/cimi/collections/cimi_filter_test.rb
 create mode 100644 server/tests/cimi/collections/fixtures/sample1.json
 create mode 100644 server/tests/cimi/collections/fixtures/sample1.xml

diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
index 2dba3be..98b7652 100644
--- a/server/lib/cimi/helpers.rb
+++ b/server/lib/cimi/helpers.rb
@@ -38,6 +38,7 @@ require_relative '../deltacloud/helpers/url_helper'
 require_relative '../deltacloud/helpers/deltacloud_helper'
 require_relative '../deltacloud/helpers/rabbit_helper'
 require_relative './helpers/cimi_helper'
+require_relative '../sinatra/rack_cimi_filter'
 require_relative './models'
 
 module CIMI::Collections
@@ -55,6 +56,8 @@ module CIMI::Collections
     helpers Deltacloud::Helpers::Application
     helpers CIMIHelper
 
+    use Rack::CIMIFilter
+
     register Rack::RespondTo
 
     enable :xhtml
diff --git a/server/lib/sinatra/rack_cimi_filter.rb b/server/lib/sinatra/rack_cimi_filter.rb
new file mode 100644
index 0000000..69e4849
--- /dev/null
+++ b/server/lib/sinatra/rack_cimi_filter.rb
@@ -0,0 +1,107 @@
+module Rack
+
+  class CIMIFilter
+
+    require 'nokogiri'
+    require 'json'
+
+    def initialize(app, no_cache_control = nil, cache_control = nil)
+      @app = app
+    end
+
+    def call(env)
+      @request = Rack::Request.new(env)
+      status, headers, body = @app.call(env)
+      if @request.params.key? '$filter'
+        body = CIMIFilter.filter(@request.media_type, body, @request.params['$filter'])
+      end
+      if @request.params.key? '$first' and @request.params.key? '$last'
+        body = CIMIFilter.slice(@request.media_type, body, @request.params['$first'], @request.params['$last'])
+      end
+      [status, headers, body]
+    end
+
+    def self.filter(format, body, filter)
+      if format == 'application/json'
+        JSONFilter.filter(body, filter)
+      elsif ['application/xml', 'text/xml'].include? format
+        XMLFilter.filter(body, filter)
+      end
+    end
+
+    def self.slice(format, body, start_pos, end_pos)
+      if format == 'application/json'
+        JSONFilter.slice(body, start_pos, end_pos)
+      elsif ['application/xml', 'text/xml'].include? format
+        XMLFilter.slice(body, start_pos, end_pos)
+      end
+    end
+
+    class JSONFilter
+      def self.filter(body, filter)
+        k, v = filter.split('=')
+        json = JSON::parse(body)
+        collection_name = json.reject { |key, val| !val.kind_of? Array }
+        return body if collection_name.empty?
+        collection_name = collection_name.keys.first
+        result = json[collection_name].select do |entity|
+          entity[k] == v
+        end
+        json[collection_name] = result
+        json['count'] = json[collection_name].size.to_s
+        JSON::dump(json)
+      end
+
+      def self.slice(body, start_pos, end_pos)
+        json = JSON::parse(body)
+        collection_name = json.reject { |key, val| !val.kind_of? Array }
+        return body if collection_name.empty?
+        collection_name = collection_name.keys.first
+        json[collection_name] = json[collection_name][start_pos-1..end_pos]
+        json['count'] = json[collection_name].size.to_s
+        JSON::dump(json)
+      end
+    end
+
+    class XMLFilter
+      def self.filter(body, filter)
+        k, v = filter.split('=')
+        xml = Nokogiri::XML(body)
+        return body if xml.root.name != 'Collection'
+        counter = 0
+        xml.root.element_children.each do |node|
+          next if node.element_children.empty?
+          if (!node.at(k).nil?) && (node.at(k).text.strip == v)
+            counter += 1
+          else
+            node.remove
+          end
+        end
+        xml.root.at('count').content = counter.to_s if xml.root.at('count')
+        xml.to_s
+      end
+
+      def self.slice(body, start_pos, end_pos)
+        xml = Nokogiri::XML(body)
+        return body if xml.root.name != 'Collection'
+        counter = 0
+        children = xml.root.element_children.select do |node|
+          !node.element_children.empty?
+        end
+        children = children[start_pos-1..end_pos]
+        xml.root.element_children.each do |node|
+          next if node.element_children.empty?
+          if children.include? node
+            counter += 1
+          else
+            node.remove
+          end
+        end
+        xml.root.at('count').content = counter.to_s if xml.root.at('count')
+        xml.to_s
+      end
+    end
+
+  end
+
+end
diff --git a/server/tests/cimi/collections/cimi_filter_test.rb b/server/tests/cimi/collections/cimi_filter_test.rb
new file mode 100644
index 0000000..4d52dd2
--- /dev/null
+++ b/server/tests/cimi/collections/cimi_filter_test.rb
@@ -0,0 +1,50 @@
+require 'rubygems'
+require 'require_relative' if RUBY_VERSION < '1.9'
+require 'minitest/autorun'
+require_relative './common.rb'
+
+describe Rack::CIMIFilter do
+
+  def sample(name)
+    File.read(File.join(File.dirname(__FILE__), 'fixtures', name))
+  end
+
+  it 'should filter the collection using element name and value in XML' do
+    result = Rack::CIMIFilter.filter('application/xml', sample('sample1.xml'), 'name=disk1')
+    result = Nokogiri::XML(result)
+    (result/'Collection/Disk').size.must_equal 1
+    result.at('Collection/count').text.must_equal '1'
+    result.at('Collection/Disk/name').text.must_equal 'disk1'
+  end
+
+  it 'should filter the collection using element name and value in JSON' do
+    result = Rack::CIMIFilter.filter('application/json', sample('sample1.json'), 'name=disk1')
+    result = JSON::parse(result)
+    result['disks'].size.must_equal 1
+    result['count'].must_equal '1'
+    result['disks'][0]['name'].must_equal 'disk1'
+  end
+
+  it 'should slice the collection using $start and $end params in XML' do
+    result = Rack::CIMIFilter.slice('application/xml', sample('sample1.xml'), 2, 3)
+    result = Nokogiri::XML(result)
+    (result/'Collection/Disk').size.must_equal 2
+    result.at('Collection/count').text.must_equal '2'
+    result = Rack::CIMIFilter.slice('application/xml', sample('sample1.xml'), 3, 3)
+    result = Nokogiri::XML(result)
+    (result/'Collection/Disk').size.must_equal 1
+    result.at('Collection/count').text.must_equal '1'
+  end
+
+  it 'should slice the collection using $start and $end params in JSON' do
+    result = Rack::CIMIFilter.slice('application/json', sample('sample1.json'), 2, 3)
+    result = JSON::parse(result)
+    result['disks'].size.must_equal 2
+    result['count'].must_equal '2'
+    result = Rack::CIMIFilter.slice('application/json', sample('sample1.json'), 3, 3)
+    result = JSON::parse(result)
+    result['disks'].size.must_equal 1
+    result['count'].must_equal '1'
+  end
+
+end
diff --git a/server/tests/cimi/collections/fixtures/sample1.json b/server/tests/cimi/collections/fixtures/sample1.json
new file mode 100644
index 0000000..761b971
--- /dev/null
+++ b/server/tests/cimi/collections/fixtures/sample1.json
@@ -0,0 +1,25 @@
+{
+  "resourceURI": "http://schemas.dmtf.org/cimi/1/DiskCollection",
+  "id": "testcollection",
+  "count": "3",
+  "disks": [
+    {
+    "resourceURI": "http://schemas.dmtf.org/cimi/1/Disk",
+    "id": "1",
+    "name": "disk1",
+    "description": "disk1desc"
+  },
+  {
+    "resourceURI": "http://schemas.dmtf.org/cimi/2/Disk",
+    "id": "2",
+    "name": "disk2",
+    "description": "disk3desc"
+  },
+  {
+    "resourceURI": "http://schemas.dmtf.org/cimi/3/Disk",
+    "id": "3",
+    "name": "disk3",
+    "description": "disk3desc"
+  }
+  ]
+}
diff --git a/server/tests/cimi/collections/fixtures/sample1.xml b/server/tests/cimi/collections/fixtures/sample1.xml
new file mode 100644
index 0000000..273215d
--- /dev/null
+++ b/server/tests/cimi/collections/fixtures/sample1.xml
@@ -0,0 +1,22 @@
+<Collection resourceURI="http://schemas.dmtf.org/cimi/1/DiskCollection" xmlns="http://schemas.dmtf.org/cimi/1">
+  <id>http://localhost/cimi/Disk</id>
+  <count>3</count>
+  <Disk>
+    <id>/disks/1</id>
+    <name>disk1</name>
+    <description>disk1_desc</description>
+    <capacity>100</capacity>
+  </Disk>
+  <Disk>
+    <id>/disks/2</id>
+    <name>disk2</name>
+    <description>disk2_desc</description>
+    <capacity>200</capacity>
+  </Disk>
+  <Disk>
+    <id>/disks/3</id>
+    <name>disk3</name>
+    <description>disk3_desc</description>
+    <capacity>300</capacity>
+  </Disk>
+</Collection>
-- 
1.7.10.2


Mime
View raw message