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.
- checksums.yaml +7 -0
- data/AUTHORS +9 -0
- data/LICENSE +26 -0
- data/README.md +55 -0
- data/Rakefile +34 -0
- data/TODO +7 -0
- data/VERSION.yml +5 -0
- data/active_cmis.gemspec +79 -0
- data/lib/active_cmis.rb +30 -0
- data/lib/active_cmis/acl.rb +181 -0
- data/lib/active_cmis/acl_entry.rb +26 -0
- data/lib/active_cmis/active_cmis.rb +87 -0
- data/lib/active_cmis/atomic_types.rb +245 -0
- data/lib/active_cmis/attribute_prefix.rb +35 -0
- data/lib/active_cmis/collection.rb +206 -0
- data/lib/active_cmis/document.rb +356 -0
- data/lib/active_cmis/exceptions.rb +82 -0
- data/lib/active_cmis/folder.rb +36 -0
- data/lib/active_cmis/internal/caching.rb +86 -0
- data/lib/active_cmis/internal/connection.rb +241 -0
- data/lib/active_cmis/internal/utils.rb +82 -0
- data/lib/active_cmis/ns.rb +18 -0
- data/lib/active_cmis/object.rb +563 -0
- data/lib/active_cmis/policy.rb +13 -0
- data/lib/active_cmis/property_definition.rb +179 -0
- data/lib/active_cmis/query_result.rb +40 -0
- data/lib/active_cmis/rel.rb +17 -0
- data/lib/active_cmis/relationship.rb +49 -0
- data/lib/active_cmis/rendition.rb +86 -0
- data/lib/active_cmis/repository.rb +327 -0
- data/lib/active_cmis/server.rb +121 -0
- data/lib/active_cmis/type.rb +200 -0
- data/lib/active_cmis/version.rb +10 -0
- metadata +132 -0
@@ -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
|
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: []
|