cmis_active 0.3.7

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,121 @@
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
+ # @return [Hash] Options to be used by the HTTP objects
10
+ attr_reader :options
11
+
12
+ # @return [Server] Cached by endpoint and logger
13
+ def self.new(endpoint, logger = nil, authentication_info = nil, options = nil)
14
+ endpoint = case endpoint
15
+ when URI; endpoint
16
+ else URI(endpoint.to_s)
17
+ end
18
+ server = super(endpoint, logger || ActiveCMIS.default_logger, authentication_info, options)
19
+ endpoints[endpoint.to_s][authentication_info][logger] ||= server
20
+ end
21
+
22
+ # @return [{(URI, Logger) => Server}] The cache of known Servers
23
+ def self.endpoints
24
+ @endpoints ||= Hash.new {|h, k| h[k] = Hash.new {|h2, k2| h2[k2] = {}}}
25
+ end
26
+
27
+ # @return [String]
28
+ def inspect
29
+ "Server #{@endpoint}"
30
+ end
31
+ # @return [String]
32
+ def to_s
33
+ "Server " + @endpoint.to_s + " : " + repositories.map {|h| h[:name] + "(#{h[:id]})"}.join(", ")
34
+ end
35
+
36
+ # A connection needs the URL to a CMIS REST endpoint.
37
+ #
38
+ # It's used to manage all communication with the CMIS Server
39
+ # @param endpoint [URI] The URL where the CMIS AtomPub REST endpoint can be found
40
+ # @param logger [Logger] The logger that will be used to log debug/info messages
41
+ # @param authentication_info [Array?] Optional authentication info to be used when retrieving the data from the AtomPub endpoint
42
+ def initialize(endpoint, logger, authentication_info = nil, options = nil)
43
+ @endpoint = endpoint
44
+ @logger = logger
45
+ @options = options || {}
46
+
47
+ method, *params = authentication_info
48
+ @authentication_info = authentication_info
49
+ if method
50
+ conn.authenticate(method, *params)
51
+ end
52
+ end
53
+
54
+ # This returns a new Server object using the specified authentication info
55
+ #
56
+ # @param (see ActiveCMIS::Internal::Connection#authenticate)
57
+ # @see Internal::Connection#authenticate
58
+ # @return [void]
59
+ def authenticate(*authentication_info)
60
+ self.class.new(endpoint, logger, authentication_info)
61
+ end
62
+
63
+ # Returns the _Repository identified by the ID
64
+ # Authentication will take place with the optional second paramater, if it
65
+ # is absent and there is server authentcation then the server authentication
66
+ # will be used
67
+ #
68
+ # Cached by the repository_id and, authentcation info. The cache can be reset
69
+ # by calling clear_repositories.
70
+ #
71
+ # @param [String] repository_id
72
+ # @param [Array] authentication_info
73
+ # @return [Repository]
74
+ def repository(repository_id, authentication_info = @authentication_info)
75
+ key = [repository_id, authentication_info]
76
+ cached_repositories[key] ||= uncached_repository(*key)
77
+ end
78
+
79
+ def uncached_repository(repository_id, authentication_info)
80
+ path = "/app:service/app:workspace[cra:repositoryInfo/c:repositoryId[child::text() = '#{repository_id}']]"
81
+ repository_data = repository_info.xpath(path, NS::COMBINED)
82
+ if repository_data.empty?
83
+ raise Error::ObjectNotFound.new("The repository #{repository_id} doesn't exist")
84
+ else
85
+ Repository.new(self, conn.dup, logger.dup, repository_data, authentication_info)
86
+ end
87
+ end
88
+ private :uncached_repository
89
+
90
+ # Reset cache of Repository objects
91
+ #
92
+ # @return [void]
93
+ def clear_repositories
94
+ @cached_repositories = {}
95
+ end
96
+
97
+
98
+ # Lists all the available repositories
99
+ #
100
+ # @return [<{:id, :name} => String>]
101
+ def repositories
102
+ repositories = repository_info.xpath("/app:service/app:workspace/cra:repositoryInfo", NS::COMBINED)
103
+ repositories.map {|ri| next {:id => ri.xpath("ns:repositoryId", "ns" => NS::CMIS_CORE).text,
104
+ :name => ri.xpath("ns:repositoryName", "ns" => NS::CMIS_CORE).text }}
105
+ end
106
+
107
+ private
108
+ def repository_info
109
+ @repository_info ||= conn.get_xml(endpoint)
110
+ end
111
+ cache :repository_info
112
+
113
+ def cached_repositories
114
+ @cached_repositories ||= {}
115
+ end
116
+
117
+ def conn
118
+ @conn ||= Internal::Connection.new(logger.dup, @options)
119
+ end
120
+ end
121
+ 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,10 @@
1
+ require 'yaml'
2
+ module ActiveCMIS
3
+ module Version
4
+ yaml = YAML.load_file(File.join(File.dirname(__FILE__), '/../../VERSION.yml'))
5
+ MAJOR = yaml[:major]
6
+ MINOR = yaml[:minor]
7
+ PATCH = yaml[:patch]
8
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cmis_active
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.7
5
+ platform: ruby
6
+ authors:
7
+ - Joeri Samson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: ntlm-http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.1
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '0.1'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.1.1
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.1'
47
+ - !ruby/object:Gem::Dependency
48
+ name: require_relative
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.0.2
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '1.0'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.0.2
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.0'
67
+ description: A CMIS library implementing both reading and updating capabilities through
68
+ the AtomPub/REST binding to CMIS.
69
+ email: joeri@xaop.com
70
+ executables: []
71
+ extensions: []
72
+ extra_rdoc_files:
73
+ - LICENSE
74
+ - README.md
75
+ - TODO
76
+ files:
77
+ - AUTHORS
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - TODO
82
+ - VERSION.yml
83
+ - active_cmis.gemspec
84
+ - lib/active_cmis.rb
85
+ - lib/active_cmis/acl.rb
86
+ - lib/active_cmis/acl_entry.rb
87
+ - lib/active_cmis/active_cmis.rb
88
+ - lib/active_cmis/atomic_types.rb
89
+ - lib/active_cmis/attribute_prefix.rb
90
+ - lib/active_cmis/collection.rb
91
+ - lib/active_cmis/document.rb
92
+ - lib/active_cmis/exceptions.rb
93
+ - lib/active_cmis/folder.rb
94
+ - lib/active_cmis/internal/caching.rb
95
+ - lib/active_cmis/internal/connection.rb
96
+ - lib/active_cmis/internal/utils.rb
97
+ - lib/active_cmis/ns.rb
98
+ - lib/active_cmis/object.rb
99
+ - lib/active_cmis/policy.rb
100
+ - lib/active_cmis/property_definition.rb
101
+ - lib/active_cmis/query_result.rb
102
+ - lib/active_cmis/rel.rb
103
+ - lib/active_cmis/relationship.rb
104
+ - lib/active_cmis/rendition.rb
105
+ - lib/active_cmis/repository.rb
106
+ - lib/active_cmis/server.rb
107
+ - lib/active_cmis/type.rb
108
+ - lib/active_cmis/version.rb
109
+ homepage: http://xaop.com/labs/activecmis/
110
+ licenses: []
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: 1.8.6
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.7.6
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A library to interact with CMIS repositories through the AtomPub/REST binding
132
+ test_files: []