timfel-active_cmis 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []