timfel-active_cmis 0.3.1

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.
@@ -0,0 +1,113 @@
1
+ module ActiveCMIS
2
+ # This class is used to manage different CMIS servers.
3
+ class Server
4
+ include Internal::Caching
5
+ # @return [URI] The location of the server
6
+ attr_reader :endpoint
7
+ # @return [Logger] A default logger for derived repositories
8
+ attr_reader :logger
9
+
10
+ # @return [Server] Cached by endpoint and logger
11
+ def self.new(endpoint, logger = nil, authentication_info = nil)
12
+ endpoint = case endpoint
13
+ when URI; endpoint
14
+ else URI(endpoint.to_s)
15
+ end
16
+ server = super(endpoint, logger || ActiveCMIS.default_logger, authentication_info)
17
+ endpoints[endpoint.to_s][authentication_info][logger] ||= server
18
+ end
19
+
20
+ # @return [{(URI, Logger) => Server}] The cache of known Servers
21
+ def self.endpoints
22
+ @endpoints ||= Hash.new {|h, k| h[k] = Hash.new {|h2, k2| h2[k2] = {}}}
23
+ end
24
+
25
+ # @return [String]
26
+ def inspect
27
+ "Server #{@endpoint}"
28
+ end
29
+ # @return [String]
30
+ def to_s
31
+ "Server " + @endpoint.to_s + " : " + repositories.map {|h| h[:name] + "(#{h[:id]})"}.join(", ")
32
+ end
33
+
34
+ # A connection needs the URL to a CMIS REST endpoint.
35
+ #
36
+ # It's used to manage all communication with the CMIS Server
37
+ # @param endpoint [URI] The URL where the CMIS AtomPub REST endpoint can be found
38
+ # @param logger [Logger] The logger that will be used to log debug/info messages
39
+ # @param authentication_info [Array?] Optional authentication info to be used when retrieving the data from the AtomPub endpoint
40
+ def initialize(endpoint, logger, authentication_info = nil)
41
+ @endpoint = endpoint
42
+ @logger = logger
43
+
44
+ method, *params = authentication_info
45
+ if method
46
+ conn.authenticate(method, *params)
47
+ end
48
+ end
49
+
50
+ # This returns a new Server object using the specified authentication info
51
+ #
52
+ # @param (see ActiveCMIS::Internal::Connection#authenticate)
53
+ # @see Internal::Connection#authenticate
54
+ # @return [void]
55
+ def authenticate(*authentication_info)
56
+ self.class.new(endpoint, logger, authentication_info)
57
+ end
58
+
59
+ # Returns the _Repository identified by the ID
60
+ # Authentication will take place with the optional second paramater, if it
61
+ # is absent and there is server authentcation then the server authentication
62
+ # will be used
63
+ #
64
+ # Cached by the repository_id and, authentcation info. The cache can be reset
65
+ # by calling clear_repositories.
66
+ #
67
+ # @param [String] repository_id
68
+ # @param [Array] authentication_info
69
+ # @return [Repository]
70
+ def repository(repository_id, authentication_info = self.authentcation_info)
71
+ cached_repositories[[repository_id, authentication_info]] ||= begin
72
+ repository_data = repository_info.
73
+ xpath("/app:service/app:workspace[cra:repositoryInfo/c:repositoryId[child::text() = '#{repository_id}']]", NS::COMBINED)
74
+ if repository_data.empty?
75
+ raise Error::ObjectNotFound.new("The repository #{repository_id} doesn't exist")
76
+ else
77
+ Repository.new(self, conn.dup, logger.dup, repository_data, authentication_info)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Reset cache of Repository objects
83
+ #
84
+ # @return [void]
85
+ def clear_repositories
86
+ @cached_repositories = {}
87
+ end
88
+
89
+
90
+ # Lists all the available repositories
91
+ #
92
+ # @return [<{:id, :name} => String>]
93
+ def repositories
94
+ repositories = repository_info.xpath("/app:service/app:workspace/cra:repositoryInfo", NS::COMBINED)
95
+ repositories.map {|ri| next {:id => ri.xpath("ns:repositoryId", "ns" => NS::CMIS_CORE).text,
96
+ :name => ri.xpath("ns:repositoryName", "ns" => NS::CMIS_CORE).text }}
97
+ end
98
+
99
+ private
100
+ def repository_info
101
+ @repository_info ||= conn.get_xml(endpoint)
102
+ end
103
+ cache :repository_info
104
+
105
+ def cached_repositories
106
+ @cached_repositories ||= {}
107
+ end
108
+
109
+ def conn
110
+ @conn ||= Internal::Connection.new(logger.dup)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,200 @@
1
+ module ActiveCMIS
2
+ module Type
3
+ # @private
4
+ def self.create(param_conn, repository, klass_data)
5
+ parent_id = klass_data.xpath("cra:type/c:parentId/text()", NS::COMBINED)
6
+ superclass = if parent = parent_id.first
7
+ repository.type_by_id(parent.to_s)
8
+ else
9
+ base_type_id = klass_data.xpath("cra:type/c:baseId", NS::COMBINED).text
10
+ case base_type_id
11
+ when "cmis:document"
12
+ Document
13
+ when "cmis:folder"
14
+ Folder
15
+ when "cmis:relationship"
16
+ Relationship
17
+ when "cmis:policy"
18
+ Policy
19
+ else
20
+ raise ActiveCMIS::Error.new("Type #{klass_data.xpath("cra:type/c:id", NS::COMBINED).text} without supertype, and not actually a valid base_type (#{base_type_id.inspect})\n" + klass_data.to_s)
21
+ end
22
+ end
23
+
24
+ klass = ::Class.new(superclass) do
25
+ extend ActiveCMIS::Type::ClassMethods
26
+ include ActiveCMIS::Type::InstanceMethods
27
+
28
+ @repository = repository
29
+ @conn = param_conn
30
+ @data = klass_data
31
+ @self_link = klass_data.xpath("at:link[@rel = 'self']/@href", NS::COMBINED).text
32
+
33
+ end
34
+ klass
35
+ end
36
+
37
+ # Instance Methods on CMIS Types
38
+ module InstanceMethods
39
+ # Creates a new CMIS Object
40
+ # @overload initialize(attributes)
41
+ # @param [Hash] attributes Attributes for a newly created object of the current type
42
+ # @return [Object]
43
+ def initialize(rep = nil, data = nil, parameters = {})
44
+ case rep
45
+ when Hash
46
+ attributes = rep
47
+ rep = nil
48
+ data = nil # Force data and parameters to be empty in that case (NOTE: assert may be better?)
49
+ parameters = {}
50
+ when NilClass
51
+ else
52
+ if rep != self.class.repository
53
+ raise "Trying to create element in different repository than type"
54
+ end
55
+ end
56
+ super(rep || self.class.repository, data, parameters)
57
+ unless attributes.nil?
58
+ update(attributes)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Class Methods on CMIS Types
64
+ #
65
+ # The following info is also available:
66
+ # id, local_name, local_namespace, display_name, query_name, description, base_id, parent_id, creatable, fileable,
67
+ # queryable, fulltext_indexed, controllable_policy, controllable_acl, versionable, content_stream_allowed
68
+ module ClassMethods
69
+ include Internal::Caching
70
+
71
+ cached_reader :id, :local_name, :local_namespace, :display_name, :query_name, :description, :base_id,
72
+ :parent_id, :creatable, :fileable, :queryable, :fulltext_indexed, :controllable_policy, :controllable_acl,
73
+ :versionable, :content_stream_allowed
74
+
75
+ # @param [Boolean] inherited (false) *Ignored*
76
+ # @return [{String => PropertyDefinition}] A list of propery definitions for all properties on the type
77
+ def attributes(inherited = false)
78
+ load_from_data unless defined?(@attributes)
79
+ if inherited && superclass.respond_to?(:attributes)
80
+ super.merge(@attributes)
81
+ else
82
+ @attributes
83
+ end
84
+ end
85
+
86
+ # @return [{String => PropertyDefinition}] A list of all required definitions (includes inherited attributes)
87
+ def required_attributes
88
+ attributes(true).reject {|key, value| !value.required}
89
+ end
90
+
91
+ # @return [<String>] A list of prefixes that can be used for adressing attributes (like cmis:)
92
+ def attribute_prefixes
93
+ @prefixes ||= attributes(true).keys.map do |key|
94
+ if key =~ /^([^:]+):/
95
+ $1
96
+ end
97
+ end.compact.uniq
98
+ end
99
+
100
+ # @return [void]
101
+ def reload
102
+ remove_instance_variable(:@attributes) if defined? @attributes
103
+ [:attributes] + __reload # Could also do if defined?(super) then super else __reload end, but we don't do anything but remove_instance_variable @attributes in superclasses anyway
104
+ end
105
+
106
+ # @return [String]
107
+ def inspect
108
+ "#<#{repository.key}::Class #{key}>"
109
+ end
110
+
111
+ # @return [String] The CMIS ID of the type
112
+ def key
113
+ @key ||= data.xpath("cra:type/c:id", NS::COMBINED).text
114
+ end
115
+
116
+ # @return [Collection<Class>] All direct subtypes (1 level deep)
117
+ def subtypes
118
+ types_feed = Internal::Utils.extract_links(data, 'down', 'application/atom+xml', 'type' => 'feed')
119
+ raise "No subtypes link for #{id}" if types_feed.empty?
120
+
121
+ Collection.new(repository, types_feed.first) do |entry|
122
+ id = entry.xpath("cra:type/c:id", NS::COMBINED).text
123
+ repository.type_by_id id
124
+ end
125
+ end
126
+ cache :subtypes
127
+
128
+ # @return [Array<Class>] All subtypes
129
+ def all_subtypes
130
+ subtypes.map do |t|
131
+ t.all_subtypes
132
+ end.flatten << self
133
+ end
134
+ cache :all_subtypes
135
+
136
+ private
137
+ # @private
138
+ attr_reader :self_link, :conn
139
+ def data
140
+ @data ||= conn.get_atom_entry(self_link)
141
+ end
142
+ cache :data
143
+
144
+ def load_from_data
145
+ @attributes = {}
146
+ data.xpath('cra:type', NS::COMBINED).children.each do |node|
147
+ next unless node.namespace
148
+ next unless node.namespace.href == NS::CMIS_CORE
149
+
150
+ case node.node_name
151
+ when "id"
152
+ @id = node.text
153
+ when "localName"
154
+ @local_name = node.text
155
+ when "localNamespace"
156
+ @local_namespace = node.text
157
+ when "displayName"
158
+ @display_name = node.text
159
+ when "queryName"
160
+ @query_name = node.text
161
+ when "description"
162
+ @description = node.text
163
+ when "baseId"
164
+ @base_id = node.text
165
+ when "parentId"
166
+ @parent_id = node.text
167
+ when "creatable"
168
+ @creatable = AtomicType::Boolean.xml_to_bool(node.text)
169
+ when "fileable"
170
+ @fileable = AtomicType::Boolean.xml_to_bool(node.text)
171
+ when "queryable"
172
+ @queryable = AtomicType::Boolean.xml_to_bool(node.text)
173
+ when "fulltextIndexed"
174
+ @fulltext_indexed = AtomicType::Boolean.xml_to_bool(node.text)
175
+ when "controllablePolicy"
176
+ @controllable_policy = AtomicType::Boolean.xml_to_bool(node.text)
177
+ when "controllableACL"
178
+ @controllable_acl = AtomicType::Boolean.xml_to_bool(node.text)
179
+ when "versionable"
180
+ @versionable = AtomicType::Boolean.xml_to_bool(node.text)
181
+ when "contentStreamAllowed"
182
+ # FIXME? this is an enumeration, should perhaps wrap
183
+ @content_stream_allowed = node.text
184
+ when /^property(?:DateTime|String|Html|Id|Boolean|Integer|Decimal)Definition$/
185
+ attr = PropertyDefinition.new(self, node.children)
186
+ @attributes[attr.id] = attr
187
+ end
188
+ end
189
+ if %w(cmis:folder cmis:document).include? @base_id and not @fileable
190
+ repository.logger.warn "The server behaved strange: #{@id}, with basetype #{@base_id} MUST be fileable"
191
+ @fileable = true
192
+ elsif @base_id == "cmis:relationship" and @fileable
193
+ repository.logger.warn "The server behaved strange: #{@id}, with basetype #{@base_id} MUST NOT be fileable"
194
+ @fileable = false
195
+ end
196
+ @attributes.freeze
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,8 @@
1
+ module ActiveCMIS
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 3
5
+ PATCH = 1
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ require 'nokogiri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'net/ntlm_http'
5
+ require 'yaml'
6
+ require 'logger'
7
+ require 'require_relative'
8
+ require_relative 'active_cmis/version'
9
+ require_relative 'active_cmis/internal/caching'
10
+ require_relative 'active_cmis/internal/connection'
11
+ require_relative 'active_cmis/exceptions'
12
+ require_relative 'active_cmis/server'
13
+ require_relative 'active_cmis/repository'
14
+ require_relative 'active_cmis/object'
15
+ require_relative 'active_cmis/document'
16
+ require_relative 'active_cmis/folder'
17
+ require_relative 'active_cmis/policy'
18
+ require_relative 'active_cmis/relationship'
19
+ require_relative 'active_cmis/type'
20
+ require_relative 'active_cmis/atomic_types'
21
+ require_relative 'active_cmis/property_definition'
22
+ require_relative 'active_cmis/collection.rb'
23
+ require_relative 'active_cmis/rendition.rb'
24
+ require_relative 'active_cmis/acl.rb'
25
+ require_relative 'active_cmis/acl_entry.rb'
26
+ require_relative 'active_cmis/ns'
27
+ require_relative 'active_cmis/active_cmis'
28
+ require_relative 'active_cmis/internal/utils'
29
+ require_relative 'active_cmis/rel'
30
+ require_relative 'active_cmis/attribute_prefix'
31
+ require_relative 'active_cmis/query_result'
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timfel-active_cmis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joeri Samson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: &70272915629220 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70272915629220
25
+ - !ruby/object:Gem::Dependency
26
+ name: ntlm-http
27
+ requirement: &70272915627840 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70272915627840
36
+ - !ruby/object:Gem::Dependency
37
+ name: require_relative
38
+ requirement: &70272915627300 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.2
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70272915627300
47
+ description: A CMIS library implementing both reading and updating capabilities through
48
+ the AtomPub/REST binding to CMIS.
49
+ email: joeri@xaop.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.md
55
+ - TODO
56
+ files:
57
+ - LICENSE
58
+ - README.md
59
+ - Rakefile
60
+ - TODO
61
+ - active_cmis.gemspec
62
+ - lib/active_cmis.rb
63
+ - lib/active_cmis/acl.rb
64
+ - lib/active_cmis/acl_entry.rb
65
+ - lib/active_cmis/active_cmis.rb
66
+ - lib/active_cmis/atomic_types.rb
67
+ - lib/active_cmis/attribute_prefix.rb
68
+ - lib/active_cmis/collection.rb
69
+ - lib/active_cmis/document.rb
70
+ - lib/active_cmis/exceptions.rb
71
+ - lib/active_cmis/folder.rb
72
+ - lib/active_cmis/internal/caching.rb
73
+ - lib/active_cmis/internal/connection.rb
74
+ - lib/active_cmis/internal/utils.rb
75
+ - lib/active_cmis/ns.rb
76
+ - lib/active_cmis/object.rb
77
+ - lib/active_cmis/policy.rb
78
+ - lib/active_cmis/property_definition.rb
79
+ - lib/active_cmis/query_result.rb
80
+ - lib/active_cmis/rel.rb
81
+ - lib/active_cmis/relationship.rb
82
+ - lib/active_cmis/rendition.rb
83
+ - lib/active_cmis/repository.rb
84
+ - lib/active_cmis/server.rb
85
+ - lib/active_cmis/type.rb
86
+ - lib/active_cmis/version.rb
87
+ homepage: http://xaop.com/labs/activecmis/
88
+ licenses: []
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: 1.8.6
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.8.11
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: A library to interact with CMIS repositories through the AtomPub/REST binding
111
+ test_files: []