active_cmis 0.1.0
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.
- data/.gitignore +3 -0
- data/LICENSE +26 -0
- data/README.md +30 -0
- data/Rakefile +36 -0
- data/TODO +8 -0
- data/VERSION +1 -0
- data/lib/active_cmis.rb +27 -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 +74 -0
- data/lib/active_cmis/atomic_types.rb +232 -0
- data/lib/active_cmis/attribute_prefix.rb +35 -0
- data/lib/active_cmis/collection.rb +175 -0
- data/lib/active_cmis/document.rb +314 -0
- data/lib/active_cmis/exceptions.rb +82 -0
- data/lib/active_cmis/folder.rb +21 -0
- data/lib/active_cmis/internal/caching.rb +86 -0
- data/lib/active_cmis/internal/connection.rb +171 -0
- data/lib/active_cmis/internal/utils.rb +69 -0
- data/lib/active_cmis/ns.rb +18 -0
- data/lib/active_cmis/object.rb +543 -0
- data/lib/active_cmis/policy.rb +13 -0
- data/lib/active_cmis/property_definition.rb +175 -0
- data/lib/active_cmis/rel.rb +17 -0
- data/lib/active_cmis/relationship.rb +47 -0
- data/lib/active_cmis/rendition.rb +65 -0
- data/lib/active_cmis/repository.rb +258 -0
- data/lib/active_cmis/server.rb +88 -0
- data/lib/active_cmis/type.rb +193 -0
- metadata +110 -0
@@ -0,0 +1,88 @@
|
|
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)
|
12
|
+
endpoint = case endpoint
|
13
|
+
when URI; endpoint
|
14
|
+
else URI(endpoint.to_s)
|
15
|
+
end
|
16
|
+
endpoints[[endpoint, logger]] ||= super(endpoint, logger || ActiveCMIS.default_logger)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [{(URI, Logger) => Server}] The cache of known Servers
|
20
|
+
def self.endpoints
|
21
|
+
@endpoints ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String]
|
25
|
+
def inspect
|
26
|
+
"Server #{@endpoint}"
|
27
|
+
end
|
28
|
+
# @return [String]
|
29
|
+
def to_s
|
30
|
+
"Server " + @endpoint.to_s + " : " + repositories.map {|h| h[:name] + "(#{h[:id]})"}.join(", ")
|
31
|
+
end
|
32
|
+
|
33
|
+
# A connection needs the URL to a CMIS REST endpoint.
|
34
|
+
#
|
35
|
+
# It's used to manage all communication with the CMIS Server
|
36
|
+
def initialize(endpoint, logger)
|
37
|
+
@endpoint = endpoint
|
38
|
+
@logger = logger
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param (see ActiveCMIS::Internal::Connection#authenticate)
|
42
|
+
# @see Internal::Connection#authenticate
|
43
|
+
# @return [void]
|
44
|
+
def authenticate(method, *params)
|
45
|
+
conn.authenticate(method, *params)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the _Repository identified by the ID
|
49
|
+
#
|
50
|
+
# Cached by the repository_id, no way to reset cache yet
|
51
|
+
# @param [String] repository_id
|
52
|
+
# @return [Repository]
|
53
|
+
def repository(repository_id)
|
54
|
+
cached_repositories[repository_id] ||= begin
|
55
|
+
repository_data = repository_info.
|
56
|
+
xpath("/app:service/app:workspace[cra:repositoryInfo/c:repositoryId[child::text() = '#{repository_id}']]", NS::COMBINED)
|
57
|
+
if repository_data.empty?
|
58
|
+
raise Error::ObjectNotFound.new("The repository #{repository_id} doesn't exist")
|
59
|
+
else
|
60
|
+
Repository.new(conn.dup, logger.dup, repository_data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Lists all the available repositories
|
66
|
+
#
|
67
|
+
# @return [<{:id, :name} => String>]
|
68
|
+
def repositories
|
69
|
+
repositories = repository_info.xpath("/app:service/app:workspace/cra:repositoryInfo", NS::COMBINED)
|
70
|
+
repositories.map {|ri| next {:id => ri.xpath("ns:repositoryId", "ns" => NS::CMIS_CORE).text,
|
71
|
+
:name => ri.xpath("ns:repositoryName", "ns" => NS::CMIS_CORE).text }}
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def repository_info
|
76
|
+
@repository_info ||= conn.get_xml(endpoint)
|
77
|
+
end
|
78
|
+
cache :repository_info
|
79
|
+
|
80
|
+
def cached_repositories
|
81
|
+
@cached_repositories ||= {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def conn
|
85
|
+
@conn ||= Internal::Connection.new(logger.dup)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,193 @@
|
|
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
|
+
@attributes.freeze
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_cmis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Joeri Samson
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-09 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: nokogiri
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 4
|
30
|
+
- 1
|
31
|
+
version: 1.4.1
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: A CMIS library implementing both reading and updating capabilities through the AtomPub/REST binding to CMIS.
|
35
|
+
email: joeri@xaop.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- TODO
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- LICENSE
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- TODO
|
48
|
+
- VERSION
|
49
|
+
- lib/active_cmis.rb
|
50
|
+
- lib/active_cmis/acl.rb
|
51
|
+
- lib/active_cmis/acl_entry.rb
|
52
|
+
- lib/active_cmis/active_cmis.rb
|
53
|
+
- lib/active_cmis/atomic_types.rb
|
54
|
+
- lib/active_cmis/attribute_prefix.rb
|
55
|
+
- lib/active_cmis/collection.rb
|
56
|
+
- lib/active_cmis/document.rb
|
57
|
+
- lib/active_cmis/exceptions.rb
|
58
|
+
- lib/active_cmis/folder.rb
|
59
|
+
- lib/active_cmis/internal/caching.rb
|
60
|
+
- lib/active_cmis/internal/connection.rb
|
61
|
+
- lib/active_cmis/internal/utils.rb
|
62
|
+
- lib/active_cmis/ns.rb
|
63
|
+
- lib/active_cmis/object.rb
|
64
|
+
- lib/active_cmis/policy.rb
|
65
|
+
- lib/active_cmis/property_definition.rb
|
66
|
+
- lib/active_cmis/rel.rb
|
67
|
+
- lib/active_cmis/relationship.rb
|
68
|
+
- lib/active_cmis/rendition.rb
|
69
|
+
- lib/active_cmis/repository.rb
|
70
|
+
- lib/active_cmis/server.rb
|
71
|
+
- lib/active_cmis/type.rb
|
72
|
+
has_rdoc: yard
|
73
|
+
homepage: http://xaop.com/labs/activecmis/
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options:
|
78
|
+
- --charset=UTF-8
|
79
|
+
- --default-return
|
80
|
+
- "::Object"
|
81
|
+
- --query
|
82
|
+
- "!@private"
|
83
|
+
- --hide-void-return
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 1
|
92
|
+
- 8
|
93
|
+
- 6
|
94
|
+
version: 1.8.6
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 1.3.6
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: A library to interact with CMIS repositories through the AtomPub/REST binding
|
109
|
+
test_files: []
|
110
|
+
|