mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merging BRANCHES/DEV/CMIS_10 to HEAD:
17717: This check-in contains changes in Java and .NET TCK tests related to CMIS-43 and CMIS-44 JIRA tasks. Also some bugs were faced out and fixed in 17727: CMIS-69: Alfresco to CMIS ACL mapping: Part 1: API 17732: Merge HEAD to DEV/CMIS10 17756: MOB-563: SQL Tests - Lexer 17764: CMIS-69: Alfresco to CMIS ACL mapping: get ACL support 17802: More for CMIS-69: Alfresco to CMIS ACL mapping. Implementation for applyAcl. 17830: Fixes for CMIS lexer and parser tests 17838: Access fix ups for access by the WS/Rest layers 17869: 1) remote-api: 17874: SAIL-146: Alfresco to CMIS ACL mapping: Support to group ACEs by principal id 17883: Adjust version properties for dev/cmis10 branch. 17885: Update OASIS CMIS TC status. 17889: Fix issue where objectid is not rendered correctly for CMIS private working copies. 17890: SAIL-146: Alfresco to CMIS ACL mapping: Fixes for ACL merging when reporting and ordering of ACEs. Report full permissions and not unique short names. 17902: Fix issue where CMIS queries via GET used incorrect defaults for paging. 17909: Fix CMIS link relations for folder tree. 17912: Fix CMIS type descendants atompub link 17922: Update AtomPub binding to CMIS 1.0 CD05 XSDs. 17924: SAIL-146: Alfresco to CMIS ACL mapping: Test set using full permissions (as opposed to short unique names) 17927: Fix content stream create/update status to comply with CMIS 1.0 CD05. 17934: Resolve encoding issues in CMIS AtomPub binding. 17973: SAIL-171: CMIS Renditions REST binding 17975: SAIL-146: Alfresco to CMIS ACL mapping: Completed AllowedAction and Permissions mapping. Added missing canDeleteTree. 17990: Update CMIS AtomPub to CD06 17996: Updates for cmis.alfresco.com for CD06 in prep for public review 2. 18007: WS-Bindings were updated with CMIS 1.0 cd06 changes. 18016: CMIS web services: Add missing generated files from WSDL 18018: CMIS index page updates for cmis.alfresco.com 18041: Merged HEAD to DEV/CMIS_10 18059: SAIL-227: 18067: SAIL-157: Strict vs Non-Strict Query Language: Enforce restrictions on the use of SCORE() and CONTAINS() 18080: Fix for SAIL-213:Bug: Query engine does not check that select list properties are valid for selectors 18131: SAIL-156: Query Language Compliance: Fix support for LIKE, including escaping of '%' and '_' with '\'. 18132: SAIL-156: Query Language Compliance: Fix support for LIKE, including escaping of '%' and '_' with '\': Fix underlying lucene impl for prefix and fuzzy queries to match wildcard/like 18143: SAIL-156: Query Language Compliance: Fix and check qualifiers in IN_TREE and IN_FOLDER. Improved scoring for CONTAINS() 18173: SAIL-245: Exclude thumbnails from normal query results 18179: SAIL 214: Query Language Compliance: Check for valid object ids in IN_FOLDER and IN_TREE 18210: SAIL-156: Query Language Compliance: Support for simple column aliases in predicates/function arguments/embedded FTS. Check property/selector binding in embedded FTS. 18211: SAIL-156: Query Language Compliance: Support for simple column aliases in predicates/function arguments/embedded FTS. Check property/selector binding in embedded FTS. 18215: SAIL 156: Query Language Compliance: Fix CMIS type info to reflect the underlying settings of the Alfresco type for includeInSuperTypeQuery 18244: SAIL 156: Query Language Compliance: includeInSuperTypeQuery -> includedInSuperTypeQuery: First cut of cmis query test model. Fixed modelSchema.xml to validate 18255: SAIL 156: Query Language Compliance: First set of tests for predicates using properties mapped to CMIS Strings. 18261: CMIS-49 SAIL-163: Alfresco to CMIS Change Log mapping - New CMIS Audit mapping is implemented. ChangeLogDataExtractor was added. 18263: Build Fix 18285: SAIL 156: Query Language Compliance: Restrictions on predicates that may be used by single-valued and multi-valued properties 18287: SAIL-186: Changes to make CMIS Rendition REST bindings pass new TCK tests 18291: Fix Eclipse classpath problems 18323: CMIS-44 SAIL-187: Change Log tests (WS) – Java and .NET tests for change log were implemented. 18325: SAIL 156: Query Language Compliance: Fixes and tests for d:mltext mappings 18329: Updated Chemistry TCK jar including Dave W's rendition tests. 18333: Fix compile error - spurious imports. 18334: Fix issue where absurl web script method failed when deployed to root context. 18339: Update CMIS index page for start of public review 2. 18387: SAIL-147: CMIS ACL REST bindings + framework fixes 18392: Fix typo 18394: SAIL 156: Query Language Compliance: Fixes and tests for d:<numeric> 18406: SAIL 156: Query Language Compliance: Remaining type/predicate combinations. Restriction of In/Comparisons for ID/Boolean 18408: CMIS Query language - remove (pointless) multi-valued column from language definition 18409: Formatting change for CMIS.g 18410: Formatting change for FTS.g 18411: CMIS TCK tests were updated to CMIS 1.0 cd06 schemas. 18412: SAIL 156: Query Language Compliance: Tests and fixes for aliases for all data types in simple predicates (they behave as the direct column reference) 18417: Update Chemistry TCK which now incorporates Dave W's ACL tests. 18419: Update CMIS index page to include public review end date. 18427: SAIL 156: Query Language Compliance: Expose multi-valued properties in queries. Tests for all accessors. Fix content length to be long. 18435: SAIL 156: Query Language Compliance: Use queryable correctly and fix up model mappings. Add tests for baseTypeId, contentStreamId and path. 18472: SAIL 156: Query Language Compliance: Tests and fixes for FTS/Contains expressions. Adhere strictly to the spec - no extensions available by default. Improved FTS error reporting (and stop any recovery). 18477: SAIL-164: CMIS change log REST bindings 18495: SAIL 156: Query Language Compliance: Tests and fixes for escaping in string literals, LIKE and FTS expressions. 18537: SAIL 156: Query Language Compliance: Sorting support. Basic sort test for all orderable/indexed CMIS properties. 18538: SAIL-164: CMIS change log fixes for TCK compliance 18547: SAIL 156: Query Language Compliance: Ordering tests for all datatypes, including null values. 18582: Incorporate latest Chemistry TCK 18583: Update list of supported CMIS capabilities in index page. 18606: SAIL-156, SAIL-157, SAIL-158: Query Language Compliance: Respect all query options including locale. Fixes and tests for MLText cross language support. 18608: SAIL-159: Java / Javascript API access to CMIS Query Language 18617: SAIL-158: Query Tests: Check policy and relationship types are not queryable. 18636: SAIL-184: ACL tests (WS) 18663: ACL tests were updated in accordance with last requirements by David Caruana. 18680: Update to CMIS CD07 18681: Fix CMIS ContentStreamId property when document has no content. 18700: CMIS: Head merge problem resolution. Phase 1: Merge up to and including revision 18700, as this the point where both AtomPub and Web Services TCK tests succeed completely on dev branch. Note: includes CMIS rendition support ready for integration and testing with DM renditions. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18790 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="source/java"/>
|
||||
<classpathentry kind="src" path="config"/>
|
||||
<classpathentry kind="src" path="source/test-resources"/>
|
||||
<classpathentry exported="true" kind="lib" path="config"/>
|
||||
<classpathentry exported="true" kind="lib" path="source/test-resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="src" path="/Core"/>
|
||||
<classpathentry kind="src" path="/3rd Party"/>
|
||||
|
@@ -117,19 +117,16 @@
|
||||
<property name="nodeService" ref="nodeService" />
|
||||
</bean>
|
||||
|
||||
<!-- Models -->
|
||||
<bean id="auditModel.modelRegistry" class="org.alfresco.repo.audit.model.AuditModelRegistry">
|
||||
<property name="transactionService" ref="transactionService"/>
|
||||
<property name="auditDAO" ref="auditDAO"/>
|
||||
<property name="dataExtractors" ref="auditModel.extractorRegistry"/>
|
||||
<property name="dataGenerators" ref="auditModel.generatorRegistry"/>
|
||||
</bean>
|
||||
|
||||
<bean id="auditModel.repository" class="org.alfresco.repo.audit.model.AuditModelReader">
|
||||
<property name="auditModelUrl">
|
||||
<value>classpath:alfresco/audit/alfresco-audit-repository.xml</value>
|
||||
<!-- Mount registry from Audit subsystem -->
|
||||
<bean id="auditModel.modelRegistry" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||
<property name="sourceApplicationContextFactory">
|
||||
<ref bean="Audit" />
|
||||
</property>
|
||||
<property name="interfaces">
|
||||
<list>
|
||||
<value>org.alfresco.repo.audit.model.AuditModelRegistry</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
66
config/alfresco/audit/alfresco-audit-cmis.xml
Executable file
66
config/alfresco/audit/alfresco-audit-cmis.xml
Executable file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<Audit xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd">
|
||||
|
||||
<DataExtractors>
|
||||
<DataExtractor name="simpleValue" registeredName="auditModel.extractor.simpleValue"/>
|
||||
<DataExtractor name="nullValue" registeredName="auditModel.extractor.nullValue"/>
|
||||
<DataExtractor name="changeLog" registeredName="CMISChangeLogDataExtractor"/>
|
||||
</DataExtractors>
|
||||
|
||||
<PathMappings>
|
||||
<PathMap source="/CMISChangeLog" target="/CMISChangeLog" />
|
||||
<PathMap source="/alfresco-api/post/FileFolderService/create" target="/CMISChangeLog/CREATED" />
|
||||
<PathMap source="/alfresco-api/post/NodeService/setProperties" target="/CMISChangeLog/UPDATED" />
|
||||
<PathMap source="/alfresco-api/post/NodeService/addProperties" target="/CMISChangeLog/UPDATED" />
|
||||
<PathMap source="/alfresco-api/post/NodeService/setProperty" target="/CMISChangeLog/UPDATED" />
|
||||
<PathMap source="/alfresco-api/post/NodeService/removeProperty" target="/CMISChangeLog/UPDATED" />
|
||||
<PathMap source="/alfresco-node/beforeDeleteNode" target="/CMISChangeLog/DELETED" />
|
||||
<PathMap source="/alfresco-api/post/PermissionService/setPermission" target="/CMISChangeLog/SECURITY" />
|
||||
<PathMap source="/alfresco-api/post/PermissionService/setInheritParentPermissions" target="/CMISChangeLog/SECURITY" />
|
||||
<PathMap source="/alfresco-api/post/PermissionService/clearPermission" target="/CMISChangeLog/SECURITY" />
|
||||
<PathMap source="/alfresco-api/post/PermissionService/deletePermission" target="/CMISChangeLog/SECURITY" />
|
||||
</PathMappings>
|
||||
|
||||
<Application name="CMISChangeLog" key="CMISChangeLog">
|
||||
<AuditPath key="CREATED">
|
||||
<AuditPath key="result">
|
||||
<RecordValue key="value" dataExtractor="changeLog" />
|
||||
</AuditPath>
|
||||
<AuditPath key="error">
|
||||
<RecordValue key="value" dataExtractor="nullValue" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
|
||||
<AuditPath key="UPDATED">
|
||||
<AuditPath key="args">
|
||||
<AuditPath key="nodeRef">
|
||||
<RecordValue key="value" dataExtractor="changeLog" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
<AuditPath key="error">
|
||||
<RecordValue key="value" dataExtractor="nullValue" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
|
||||
<AuditPath key="DELETED">
|
||||
<AuditPath key="node">
|
||||
<RecordValue key="value" dataExtractor="changeLog" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
|
||||
<AuditPath key="SECURITY">
|
||||
<AuditPath key="args">
|
||||
<AuditPath key="nodeRef">
|
||||
<RecordValue key="value" dataExtractor="simpleValue" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
<AuditPath key="error">
|
||||
<RecordValue key="value" dataExtractor="nullValue" />
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
</Application>
|
||||
|
||||
</Audit>
|
@@ -552,9 +552,10 @@
|
||||
</bean>
|
||||
|
||||
<!-- Start Auditing -->
|
||||
<bean id="audit.bootstrap" class="org.alfresco.repo.audit.AuditBootstrap">
|
||||
<property name="transactionService" ref="transactionService"/>
|
||||
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
|
||||
<bean id="Audit" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean">
|
||||
<property name="autoStart">
|
||||
<value>true</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Repository helper class -->
|
||||
|
@@ -14,11 +14,12 @@
|
||||
|
||||
<bean id="CMISService" class="org.alfresco.cmis.mapping.CMISServicesImpl">
|
||||
<property name="CMISSpecVersion"><value>1.0</value></property>
|
||||
<property name="CMISSpecTitle"><value>Version 1.0 Committee Draft 04</value></property>
|
||||
<property name="CMISSpecTitle"><value>Version 1.0 Committee Draft 07</value></property>
|
||||
<property name="defaultStore"><value>workspace://SpacesStore</value></property>
|
||||
<property name="defaultRootPath"><value>/Company Home</value></property>
|
||||
<property name="dictionaryService" ref="dictionaryService" />
|
||||
<property name="CMISDictionaryService" ref="CMISDictionaryService" />
|
||||
<property name="CMISRenditionService" ref="CMISRenditionService" />
|
||||
<property name="searchService" ref="SearchService" />
|
||||
<property name="transactionHelper" ref="retryingTransactionHelper" />
|
||||
<property name="tenantAdminService" ref="tenantAdminService" />
|
||||
@@ -68,11 +69,79 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="CMISRenditionService" class="org.alfresco.cmis.renditions.CMISRenditionServiceImpl">
|
||||
<property name="renditionKindMapping">
|
||||
<map>
|
||||
<entry key="cmis:thumbnail">
|
||||
<list><value>doclib</value></list>
|
||||
</entry>
|
||||
<entry key="alf:webpreview">
|
||||
<list><value>webpreview</value><value>imgpreview</value></list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<property name="customRenditions">
|
||||
<list>
|
||||
<bean class="org.alfresco.cmis.renditions.CMISRenditionImpl">
|
||||
<property name="streamId"><value>alf:icon16</value></property>
|
||||
<property name="mimeType"><value>image/gif</value></property>
|
||||
<property name="kind"><value>ICON16</value></property>
|
||||
<property name="width"><value>16</value></property>
|
||||
<property name="height"><value>16</value></property>
|
||||
</bean>
|
||||
<bean class="org.alfresco.cmis.renditions.CMISRenditionImpl">
|
||||
<property name="streamId"><value>alf:icon32</value></property>
|
||||
<property name="mimeType"><value>image/gif</value></property>
|
||||
<property name="kind"><value>ICON32</value></property>
|
||||
<property name="width"><value>32</value></property>
|
||||
<property name="height"><value>32</value></property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
<property name="thumbnailService">
|
||||
<ref bean="ThumbnailService" />
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="CMISChangeLogService" class="org.alfresco.cmis.changelog.CMISChangeLogServiceImpl">
|
||||
<property name="cmisAuditApplicationName" value="CMISChangeLog" />
|
||||
<property name="changesOnTypeCapability">
|
||||
<list>
|
||||
<value>FOLDER</value>
|
||||
<value>DOCUMENT</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="auditService" ref="auditService" />
|
||||
</bean>
|
||||
|
||||
<bean id="CMISChangeLogDataExtractor" class="org.alfresco.cmis.changelog.CMISChangeLogDataExtractor">
|
||||
<property name="cmisService" ref="CMISService" />
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="registry" ref="auditModel.extractorRegistry" />
|
||||
</bean>
|
||||
|
||||
<bean id="CMISReferenceFactory" class="org.alfresco.cmis.reference.ReferenceFactory">
|
||||
<property name="CMISService" ref="CMISService" />
|
||||
<property name="CMISDictionaryService" ref="CMISDictionaryService" />
|
||||
</bean>
|
||||
|
||||
<bean id="CMISAccessControlService" class="org.alfresco.cmis.acl.CMISAccessControlServiceImpl" >
|
||||
<!-- Valid values are: NONE, DISCOVER, MANAGE -->
|
||||
<property name="aclCapabilityEnum" value="MANAGE" />
|
||||
<!-- Valid values are: BASIC, REPOSITORY, BOTH -->
|
||||
<property name="aclSupportedPermissionEnum" value="BOTH" />
|
||||
<!-- Alfrecso only supports PROPAGATE -->
|
||||
<property name="aclPropagationEnum" value="PROPAGATE" />
|
||||
<property name="permissionModelDao" ref="permissionsModelDAO" />
|
||||
<property name="permissionService" ref="PermissionService" />
|
||||
<property name="CMISMapping" ref="CMISMapping" />
|
||||
<property name="CMISDictionaryService" ref="CMISDictionaryService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
<bean id="lucene.sql.cmis.strict" class="org.alfresco.repo.search.impl.lucene.LuceneCmisStrictSqlQueryLanguage" >
|
||||
<property name="cmisQueryService">
|
||||
<ref bean="CMISQueryService" />
|
||||
|
@@ -9,7 +9,7 @@
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/model/cmis/1.0/cd04" prefix="cmis" />
|
||||
<namespace uri="http://www.alfresco.org/model/cmis/1.0/cd07" prefix="cmis" />
|
||||
</namespaces>
|
||||
|
||||
<data-types>
|
||||
@@ -78,9 +78,7 @@
|
||||
<protected>true</protected>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
<index enabled="false" />
|
||||
</property>
|
||||
<property name="cmis:createdBy">
|
||||
<title>Created by</title>
|
||||
@@ -215,9 +213,7 @@
|
||||
<protected>true</protected>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
<index enabled="false"/>
|
||||
</property>
|
||||
<property name="cmis:isVersionSeriesCheckedOut">
|
||||
<title>Is Version Series Checked Out</title>
|
||||
@@ -258,7 +254,7 @@
|
||||
<property name="cmis:contentStreamLength">
|
||||
<title>Content Stream Length</title>
|
||||
<description>The length of the content stream</description>
|
||||
<type>d:int</type>
|
||||
<type>d:long</type>
|
||||
<protected>true</protected>
|
||||
<mandatory enforced="false">false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
@@ -295,9 +291,7 @@
|
||||
<protected>true</protected>
|
||||
<mandatory enforced="false">false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
<index enabled="false" />
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
@@ -325,9 +319,7 @@
|
||||
<protected>true</protected>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
<index enabled="false"/>
|
||||
</property>
|
||||
<property name="cmis:allowedChildObjectTypeIds">
|
||||
<title>Allowed Child Object Types Ids</title>
|
||||
|
@@ -1,4 +1,8 @@
|
||||
<model name="cm:contentmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- xsi:schemaLocation="http://www.alfresco.org/model/dictionary/1.0 modelSchema.xsd" -->
|
||||
<model name="cm:contentmodel"
|
||||
xmlns="http://www.alfresco.org/model/dictionary/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<description>Alfresco Content Domain Model</description>
|
||||
<author>Alfresco</author>
|
||||
@@ -419,6 +423,7 @@
|
||||
<title>Thumbnail</title>
|
||||
<parent>cm:content</parent>
|
||||
<archive>true</archive>
|
||||
<includedInSuperTypeQuery>false</includedInSuperTypeQuery>
|
||||
<properties>
|
||||
<property name="cm:thumbnailName">
|
||||
<title>Thumbnail Name</title>
|
||||
|
@@ -104,6 +104,8 @@
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
<xs:element name="archive" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
<xs:element name="includedInSuperTypeQuery" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
<xs:element name="properties" maxOccurs="1"
|
||||
minOccurs="0">
|
||||
<xs:complexType>
|
||||
@@ -257,7 +259,8 @@
|
||||
<xs:complexType name="association">
|
||||
<xs:sequence>
|
||||
<xs:group ref="dd:TextualDescription"></xs:group>
|
||||
<xs:element name="source" maxOccurs="1" minOccurs="0">
|
||||
<xs:element name="source" maxOccurs="1" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="role" type="xs:string" maxOccurs="1"
|
||||
minOccurs="0" />
|
||||
@@ -266,7 +269,7 @@
|
||||
<xs:element name="many" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="target">
|
||||
<xs:complexType>
|
||||
@@ -293,17 +296,6 @@
|
||||
<xs:element name="duplicate" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
<xs:element name="propagateTimestamps" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:group name="role">
|
||||
<xs:sequence>
|
||||
<xs:element name="role" type="xs:string" maxOccurs="1"
|
||||
minOccurs="0" />
|
||||
<xs:element name="mandatory" type="xs:boolean"
|
||||
maxOccurs="1" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
|
@@ -160,7 +160,7 @@
|
||||
|
||||
on - if required permission must be present on the node, its primary parent, or its children
|
||||
|
||||
imples - false - the permission wil be checked
|
||||
implies - false - the permission wil be checked
|
||||
- true - the permission is effectively granted along with this one.
|
||||
|
||||
This will normally be false. For example, to require read permission on the
|
||||
|
@@ -235,4 +235,13 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeAuditor" class="org.alfresco.repo.node.NodeAuditor">
|
||||
<property name="policyComponent">
|
||||
<ref bean="policyComponent"/>
|
||||
</property>
|
||||
<property name="auditComponent">
|
||||
<ref bean="auditComponent"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -40,9 +40,6 @@
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService"/>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<value>${audit.enabled}</value>
|
||||
</property>
|
||||
<property name="useNewConfig">
|
||||
<value>${audit.useNewConfig}</value>
|
||||
</property>
|
||||
|
@@ -250,7 +250,9 @@ db.pool.abandoned.time=300
|
||||
|
||||
# Audit configuration
|
||||
audit.enabled=false
|
||||
audit.useNewConfig=false
|
||||
audit.repository.enabled=true
|
||||
audit.cmis.enabled=true
|
||||
audit.useNewConfig=true
|
||||
|
||||
# Email configuration
|
||||
mail.host=
|
||||
|
@@ -0,0 +1,43 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Start Auditing -->
|
||||
<bean id="audit.bootstrap" class="org.alfresco.repo.audit.AuditBootstrap">
|
||||
<property name="active">
|
||||
<value>${audit.enabled}</value>
|
||||
</property>
|
||||
<property name="transactionService" ref="transactionService"/>
|
||||
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
|
||||
</bean>
|
||||
|
||||
<!-- Models -->
|
||||
<bean id="auditModel.modelRegistry" class="org.alfresco.repo.audit.model.AuditModelRegistryImpl">
|
||||
<property name="transactionService" ref="transactionService"/>
|
||||
<property name="auditDAO" ref="auditDAO"/>
|
||||
<property name="dataExtractors" ref="auditModel.extractorRegistry"/>
|
||||
<property name="dataGenerators" ref="auditModel.generatorRegistry"/>
|
||||
</bean>
|
||||
|
||||
<bean id="auditModel.repository" class="org.alfresco.repo.audit.model.AuditModelReader">
|
||||
<property name="active">
|
||||
<value>${audit.repository.enabled}</value>
|
||||
</property>
|
||||
<property name="auditModelUrl">
|
||||
<value>classpath:alfresco/audit/alfresco-audit-repository.xml</value>
|
||||
</property>
|
||||
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
|
||||
</bean>
|
||||
|
||||
<bean id="auditModel.cmis" class="org.alfresco.repo.audit.model.AuditModelReader">
|
||||
<property name="active">
|
||||
<value>${audit.cmis.enabled}</value>
|
||||
</property>
|
||||
<property name="auditModelUrl">
|
||||
<value>classpath:alfresco/audit/alfresco-audit-cmis.xml</value>
|
||||
</property>
|
||||
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -0,0 +1,3 @@
|
||||
audit.enabled=false
|
||||
audit.repository.enabled=true
|
||||
audit.cmis.enabled=true
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISAccessControlEntriesGroupedByPrincipalId
|
||||
{
|
||||
/**
|
||||
* Get the principal id.
|
||||
* @return principal id
|
||||
*/
|
||||
public String getPrincipalId();
|
||||
|
||||
/**
|
||||
* Get the direct permissions
|
||||
* @return the direct permissions
|
||||
*/
|
||||
public List<String> getDirectPermissions();
|
||||
|
||||
/**
|
||||
* Get the indirect permissions
|
||||
* @return the indirect permissions
|
||||
*/
|
||||
public List<String> getIndirectPermissions();
|
||||
|
||||
|
||||
}
|
54
source/java/org/alfresco/cmis/CMISAccessControlEntry.java
Normal file
54
source/java/org/alfresco/cmis/CMISAccessControlEntry.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* An Access control entry
|
||||
*
|
||||
* Note: we report one permission at a time rather than group them
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISAccessControlEntry
|
||||
{
|
||||
/**
|
||||
* Get the principal id.
|
||||
* @return principal id
|
||||
*/
|
||||
public String getPrincipalId();
|
||||
|
||||
/**
|
||||
* Get the unique permission id
|
||||
* @return the unique permission id
|
||||
*/
|
||||
public String getPermission();
|
||||
|
||||
/**
|
||||
* Is the assignment direct on the object
|
||||
* @return <code>true</code> if directly assigned, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean getDirect();
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public enum CMISAccessControlFormatEnum implements EnumLabel
|
||||
{
|
||||
/**
|
||||
* Report only CMIS basic permissions
|
||||
*/
|
||||
CMIS_BASIC_PERMISSIONS("onlyBasicPermissions"),
|
||||
|
||||
/**
|
||||
* May report CMIS basic permission, repository specific permissions or a mixture of both.
|
||||
*/
|
||||
REPOSITORY_SPECIFIC_PERMISSIONS("repositorySpecificPermissions");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAccessControlFormatEnum(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for CMISAclPropagationEnum
|
||||
*/
|
||||
public static EnumFactory<CMISAccessControlFormatEnum> FACTORY = new EnumFactory<CMISAccessControlFormatEnum>(CMISAccessControlFormatEnum.class, CMIS_BASIC_PERMISSIONS, true);
|
||||
|
||||
}
|
60
source/java/org/alfresco/cmis/CMISAccessControlReport.java
Normal file
60
source/java/org/alfresco/cmis/CMISAccessControlReport.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An Access control report.
|
||||
* This is an ACL.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISAccessControlReport
|
||||
{
|
||||
/**
|
||||
* Get the list of ACEs.
|
||||
* @return the list of ACEs.
|
||||
*/
|
||||
public List<? extends CMISAccessControlEntry> getAccessControlEntries();
|
||||
|
||||
/**
|
||||
* Is this report incomplete?
|
||||
* If so there are other other security constraints that apply
|
||||
*
|
||||
* @return <code>false</code> means the report fully describes security access, <code>true</code> means other
|
||||
* security constraints apply but are not reported.
|
||||
*/
|
||||
public boolean isExtract();
|
||||
|
||||
/**
|
||||
* Get ACEs grouped by principal id
|
||||
* @return
|
||||
*/
|
||||
public List<? extends CMISAccessControlEntriesGroupedByPrincipalId> getAccessControlEntriesGroupedByPrincipalId();
|
||||
|
||||
|
||||
}
|
131
source/java/org/alfresco/cmis/CMISAccessControlService.java
Normal file
131
source/java/org/alfresco/cmis/CMISAccessControlService.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Service for CMIS access control support.
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
public interface CMISAccessControlService
|
||||
{
|
||||
/**
|
||||
* CMIS Read (properties and content)
|
||||
*/
|
||||
public static final String CMIS_READ_PERMISSION = "cmis:read";
|
||||
|
||||
/**
|
||||
* CMIS Write (properties and content)
|
||||
*/
|
||||
public static final String CMIS_WRITE_PERMISSION = "cmis:write";
|
||||
|
||||
/**
|
||||
* CMIS ALL permissions (includes all permissions defined within the repository)
|
||||
*/
|
||||
public static final String CMIS_ALL_PERMISSION = "cmis:all";
|
||||
|
||||
/**
|
||||
* Get the ACL capability enum.
|
||||
* @return the ACL capability enum.
|
||||
*/
|
||||
public CMISAclCapabilityEnum getAclCapability();
|
||||
|
||||
/**
|
||||
* Gets the supported permission types
|
||||
* @return the supported permission types
|
||||
*/
|
||||
public CMISAclSupportedPermissionEnum getSupportedPermissions();
|
||||
|
||||
/**
|
||||
* Get the ACL propagation enum.
|
||||
* @return the ACL propagation enum.
|
||||
*/
|
||||
public CMISAclPropagationEnum getAclPropagation();
|
||||
|
||||
/**
|
||||
* Get all the permissions defined by the repository.
|
||||
* @return a list of permissions
|
||||
*/
|
||||
public List<CMISPermissionDefinition> getRepositoryPermissions();
|
||||
|
||||
/**
|
||||
* Get the list of permission mappings.
|
||||
* @return get the permission mapping as defined by the CMIS specification.
|
||||
*/
|
||||
public List<? extends CMISPermissionMapping> getPermissionMappings();
|
||||
|
||||
/**
|
||||
* Gets the name of the principal who is used for anonymous access. This principal can then be passed to the ACL
|
||||
* services to specify what permissions anonymous users should have.
|
||||
*
|
||||
* @return name of the principal who is used for anonymous access
|
||||
*/
|
||||
public String getPrincipalAnonymous();
|
||||
|
||||
/**
|
||||
* Gets the name of the principal who is used to indicate any authenticated user. This principal can then be passed
|
||||
* to the ACL services to specify what permissions any authenticated user should have.
|
||||
*
|
||||
* @return name of the principal who is used to indicate any authenticated user
|
||||
*/
|
||||
public String getPrincipalAnyone();
|
||||
|
||||
/**
|
||||
* Get the ACLs set on a node.
|
||||
* @param nodeRef
|
||||
* @param format
|
||||
* @return an access control report
|
||||
*/
|
||||
public CMISAccessControlReport getAcl(NodeRef nodeRef, CMISAccessControlFormatEnum format);
|
||||
|
||||
/**
|
||||
* Update the ACEs on a node.
|
||||
* Those already existing, are preserved, those new are added and those missing are removed.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param acesToApply
|
||||
* @return an access control report of the final state
|
||||
*/
|
||||
public CMISAccessControlReport applyAcl(NodeRef nodeRef, List<CMISAccessControlEntry> acesToApply);
|
||||
|
||||
/**
|
||||
* Update the ACEs on a node.
|
||||
* The deletions are applied before the additions.
|
||||
* Existing ACEs not deleted or added remain unchanged.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param acesToRemove
|
||||
* @param acesToAdd
|
||||
* @param propagation
|
||||
* @param format
|
||||
* @return an access control report of the final state
|
||||
* @exception UnsupportedCMISAclPropagationMode will be thrown for unsupported propagation modes.
|
||||
*/
|
||||
public CMISAccessControlReport applyAcl(NodeRef nodeRef, List<CMISAccessControlEntry> acesToRemove, List<CMISAccessControlEntry> acesToAdd, CMISAclPropagationEnum propagation, CMISAccessControlFormatEnum format);
|
||||
}
|
74
source/java/org/alfresco/cmis/CMISAclCapabilityEnum.java
Normal file
74
source/java/org/alfresco/cmis/CMISAclCapabilityEnum.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* CMIS ACL capability
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
public enum CMISAclCapabilityEnum implements EnumLabel
|
||||
{
|
||||
/**
|
||||
* ACLs are not supported
|
||||
*/
|
||||
NONE("none"),
|
||||
/**
|
||||
* ACLs can be read but not set
|
||||
*/
|
||||
DISCOVER("discover"),
|
||||
/**
|
||||
* ACLs can be read and set
|
||||
*/
|
||||
MANAGE("manage");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAclCapabilityEnum(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for CMISAclCapabilityEnum
|
||||
*/
|
||||
public static EnumFactory<CMISAclCapabilityEnum> FACTORY = new EnumFactory<CMISAclCapabilityEnum>(CMISAclCapabilityEnum.class, MANAGE, true);
|
||||
|
||||
}
|
79
source/java/org/alfresco/cmis/CMISAclPropagationEnum.java
Normal file
79
source/java/org/alfresco/cmis/CMISAclPropagationEnum.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* CMIS ACL propagation
|
||||
*
|
||||
* Used to request a particular behaviour or report back behaviour.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public enum CMISAclPropagationEnum implements EnumLabel
|
||||
{
|
||||
/**
|
||||
* The ACL only applies to the object
|
||||
* (not yet supported in Alfresco)
|
||||
*/
|
||||
OBJECT_ONLY("objectonly"),
|
||||
/**
|
||||
* ACLs are applied to all inheriting objects
|
||||
* (the default in Alfresco)
|
||||
*/
|
||||
PROPAGATE("propagate"),
|
||||
/**
|
||||
* Some other mechanism by which ACL changes influence other ACL's non-direct ACEs.
|
||||
*/
|
||||
REPOSITORY_DETERMINED("repositorydetermined");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAclPropagationEnum(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for CMISAclPropagationEnum
|
||||
*/
|
||||
public static EnumFactory<CMISAclPropagationEnum> FACTORY = new EnumFactory<CMISAclPropagationEnum>(CMISAclPropagationEnum.class, PROPAGATE, true);
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* Specifies which types of permissions are supported..
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public enum CMISAclSupportedPermissionEnum
|
||||
{
|
||||
/**
|
||||
* CMIS Basic permissions are supported.
|
||||
*/
|
||||
BASIC("basic"),
|
||||
/**
|
||||
* Repository specific permissions are supported.
|
||||
*/
|
||||
REPOSITORY("repository"),
|
||||
/**
|
||||
* both CMIS basic permissions and repository specific permissions are supported. (the default in Alfresco)
|
||||
*/
|
||||
BOTH("both");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAclSupportedPermissionEnum(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for CMISAclSupportedPermissionEnum
|
||||
*/
|
||||
public static EnumFactory<CMISAclSupportedPermissionEnum> FACTORY = new EnumFactory<CMISAclSupportedPermissionEnum>(
|
||||
CMISAclSupportedPermissionEnum.class, BOTH, true);
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,12 +18,17 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* CMIS Allowed Action Enum
|
||||
*
|
||||
@@ -31,60 +36,76 @@ package org.alfresco.cmis;
|
||||
*/
|
||||
public enum CMISAllowedActionEnum implements EnumLabel
|
||||
{
|
||||
|
||||
// navigation services
|
||||
CAN_GET_DESCENDANTS("canGetDescendants"),
|
||||
CAN_GET_FOLDER_TREE("canGetFolderTree"),
|
||||
CAN_GET_CHILDREN("canGetChildren"),
|
||||
CAN_GET_FOLDER_PARENT("canGetFolderParent"),
|
||||
CAN_GET_OBJECT_PARENTS("canGetObjectParents"),
|
||||
CAN_GET_DESCENDANTS("canGetDescendants", "canGetDescendents.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetDescendents.Folder", "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"),
|
||||
CAN_GET_FOLDER_TREE("canGetFolderTree"/*, "canGetFolderTree.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetFolderTree.Folder", "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"*/),
|
||||
CAN_GET_CHILDREN("canGetChildren", "canGetChildren.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetChildren.Folder", "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"),
|
||||
CAN_GET_FOLDER_PARENT("canGetFolderParent", "canGetParents.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetParents.Folder", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"),
|
||||
CAN_GET_OBJECT_PARENTS("canGetObjectParents", "canGetFolderParent.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetFolderParent.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"),
|
||||
|
||||
// object services
|
||||
CAN_CREATE_DOCUMENT("canCreateDocument"),
|
||||
CAN_CREATE_FOLDER("canCreateFolder"),
|
||||
CAN_CREATE_DOCUMENT("canCreateDocument", "canCreateDocument.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "canCreateDocument.Folder", "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"),
|
||||
CAN_CREATE_FOLDER("canCreateFolder", "canCreateFolder.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "canCreateFolder.Folder", "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"),
|
||||
CAN_CREATE_RELATIONSHIP("canCreateRelationship"),
|
||||
CAN_CREATE_POLICY("canCreatePolicy"),
|
||||
CAN_GET_PROPERTIES("canGetProperties"),
|
||||
CAN_GET_RENDITIONS("canGetRenditions"),
|
||||
CAN_GET_CONTENT_STREAM("canGetContentStream"),
|
||||
CAN_UPDATE_PROPERTIES("canUpdateProperties"),
|
||||
CAN_MOVE_OBJECT("canMoveObject"),
|
||||
CAN_DELETE_OBJECT("canDeleteObject"),
|
||||
CAN_SET_CONTENT_STREAM("canSetContentStream"),
|
||||
CAN_DELETE_CONTENT_STREAM("canDeleteContentStream"),
|
||||
CAN_GET_PROPERTIES("canGetProperties", "canGetProperties.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetProperties.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"),
|
||||
CAN_GET_RENDITIONS("canGetRenditions"/*, "canGetRenditions.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetRenditions.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"*/),
|
||||
CAN_GET_CONTENT_STREAM("canGetContentStream", "canViewContent.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canViewContent.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadContent"),
|
||||
CAN_UPDATE_PROPERTIES("canUpdateProperties", "canUpdateProperties.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "canUpdateProperties.Object", "{http://www.alfresco.org/model/system/1.0}base.WriteProperties"),
|
||||
CAN_MOVE_OBJECT("canMoveObject", "canMove.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "canMove.Target", CMISAccessControlService.CMIS_ALL_PERMISSION, "canMove.Object", "{http://www.alfresco.org/model/system/1.0}base.DeleteNode", "canMove.Target", "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"),
|
||||
CAN_DELETE_OBJECT("canDeleteObject", "canDelete.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "canDelete.Object", "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"),
|
||||
CAN_SET_CONTENT_STREAM("canSetContentStream", "canSetContent.Document", CMISAccessControlService.CMIS_WRITE_PERMISSION, "canSetContent.Document", "{http://www.alfresco.org/model/system/1.0}base.WriteContent"),
|
||||
CAN_DELETE_CONTENT_STREAM("canDeleteContentStream", "canDeleteContent.Document", CMISAccessControlService.CMIS_WRITE_PERMISSION, "canDeleteContent.Document", "{http://www.alfresco.org/model/system/1.0}base.WriteContent"),
|
||||
CAN_DELETE_TREE("canDeleteTree", "canDeleteTree.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "canDeleteTree.Folder", "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"),
|
||||
|
||||
// multi-filing services
|
||||
CAN_ADD_OBJECT_TO_FOLDER("canAddObjectToFolder"),
|
||||
CAN_REMOVE_OBJECT_FROM_FOLDER("canRemoveObjectFromFolder"),
|
||||
CAN_ADD_OBJECT_TO_FOLDER("canAddObjectToFolder", "canAddToFolder.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canAddToFolder.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "canAddToFolder.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties", "canAddToFolder.Folder", "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"),
|
||||
CAN_REMOVE_OBJECT_FROM_FOLDER("canRemoveObjectFromFolder", "canRemoveFromFolder.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "canRemoveFromFolder.Object", "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"),
|
||||
|
||||
// versioning services
|
||||
CAN_CHECKOUT("canCheckOut"),
|
||||
CAN_CANCEL_CHECKOUT("canCancelCheckOut"),
|
||||
CAN_CHECKIN("canCheckIn"),
|
||||
CAN_GET_ALL_VERSIONS("canGetAllVersions"),
|
||||
CAN_CHECKOUT("canCheckOut", "canCheckout.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "canCheckout.Document", "{http://www.alfresco.org/model/content/1.0}lockable.CheckOut"),
|
||||
CAN_CANCEL_CHECKOUT("canCancelCheckOut", "canCancelCheckout.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "canCancelCheckout.Document", "{http://www.alfresco.org/model/content/1.0}lockable.CancelCheckOut"),
|
||||
CAN_CHECKIN("canCheckIn", "canCheckin.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "canCheckin.Document", "{http://www.alfresco.org/model/content/1.0}lockable.CheckIn"),
|
||||
CAN_GET_ALL_VERSIONS("canGetAllVersions", "canGetAllVersions.VersionSeries", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetAllVersions.VersionSeries", "{http://www.alfresco.org/model/system/1.0}base.Read"),
|
||||
|
||||
// relationship services
|
||||
CAN_GET_OBJECT_RELATIONSHIPS("canGetObjectRelationships"),
|
||||
|
||||
// policy services
|
||||
CAN_APPLY_POLICY("canApplyPolicy"),
|
||||
CAN_REMOVE_POLICY("canRemovePolicy"),
|
||||
CAN_GET_APPLIED_POLICIES("canGetAppliedPolicies"),
|
||||
CAN_APPLY_POLICY("canApplyPolicy", "canAddPolicy.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "canAddPolicy.Policy", CMISAccessControlService.CMIS_READ_PERMISSION, "canAddPolicy.Object", "{http://www.alfresco.org/model/system/1.0}base.Write"),
|
||||
CAN_REMOVE_POLICY("canRemovePolicy", "canRemovePolicy.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "canRemovePolicy.Policy", CMISAccessControlService.CMIS_READ_PERMISSION, "canRemovePolicy.Object", "{http://www.alfresco.org/model/system/1.0}base.Write"),
|
||||
CAN_GET_APPLIED_POLICIES("canGetAppliedPolicies", "canGetAppliedPolicies.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "canGetAppliedPolicies.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"),
|
||||
|
||||
// acl services
|
||||
CAN_GET_ACL("canGetACL"),
|
||||
CAN_APPLY_ACL("canApplyACL");
|
||||
CAN_GET_ACL("canGetACL", "canGetACL.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "canGetACL.Object", "{http://www.alfresco.org/model/system/1.0}base.ReadPermissions"),
|
||||
CAN_APPLY_ACL("canApplyACL", "canApplyACL.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "canApplyACL.Object", "{http://www.alfresco.org/model/system/1.0}base.ChangePermissions");
|
||||
|
||||
|
||||
private String label;
|
||||
|
||||
private Map<String, List<String>> mapping = new HashMap<String, List<String>>();
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAllowedActionEnum(String label)
|
||||
CMISAllowedActionEnum(String label, String ... keysAndPermissions)
|
||||
{
|
||||
this.label = label;
|
||||
assert(keysAndPermissions.length % 2 == 0);
|
||||
for(int i = 0; i < keysAndPermissions.length; i++)
|
||||
{
|
||||
String key = keysAndPermissions[i];
|
||||
String permission = keysAndPermissions[++i];
|
||||
List<String> permissions = mapping.get(key);
|
||||
if(permissions == null)
|
||||
{
|
||||
permissions = new ArrayList<String>(1);
|
||||
mapping.put(key, permissions);
|
||||
}
|
||||
permissions.add(permission);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -95,5 +116,10 @@ public enum CMISAllowedActionEnum implements EnumLabel
|
||||
return label;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getPermissionMapping()
|
||||
{
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public static EnumFactory<CMISAllowedActionEnum> FACTORY = new EnumFactory<CMISAllowedActionEnum>(CMISAllowedActionEnum.class);
|
||||
}
|
||||
|
53
source/java/org/alfresco/cmis/CMISBaseObjectTypeIds.java
Executable file
53
source/java/org/alfresco/cmis/CMISBaseObjectTypeIds.java
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* Enumeration of base Alfresco Object type Ids. Possible values:<br />
|
||||
* <b>DOCUMENT</b>,<br />
|
||||
* <b>FOLDER</b>,<br />
|
||||
* <b>RELATIONSHIP</b>,<br />
|
||||
* <b>POLICY</b>
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public enum CMISBaseObjectTypeIds implements EnumLabel
|
||||
{
|
||||
DOCUMENT("cmis:document"), FOLDER("cmis:folder"), RELATIONSHIP("cmis:relationship"), POLICY("cmis:policy");
|
||||
|
||||
private String label;
|
||||
|
||||
CMISBaseObjectTypeIds(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
public static final EnumFactory<CMISBaseObjectTypeIds> FACTORY = new EnumFactory<CMISBaseObjectTypeIds>(CMISBaseObjectTypeIds.class);
|
||||
}
|
49
source/java/org/alfresco/cmis/CMISCapabilityChanges.java
Executable file
49
source/java/org/alfresco/cmis/CMISCapabilityChanges.java
Executable file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* Enumeration of the <b>CMIS Changes Capability</b>
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public enum CMISCapabilityChanges implements EnumLabel
|
||||
{
|
||||
NONE("none"), OBJECTIDSONLY("objectidsonly");
|
||||
|
||||
private String label;
|
||||
|
||||
CMISCapabilityChanges(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
public static final EnumFactory<CMISCapabilityChanges> FACTORY = new EnumFactory<CMISCapabilityChanges>(CMISCapabilityChanges.class);
|
||||
}
|
52
source/java/org/alfresco/cmis/CMISChangeEvent.java
Executable file
52
source/java/org/alfresco/cmis/CMISChangeEvent.java
Executable file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* This class describes entry record for some <b>Change Log</b> descriptor
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public interface CMISChangeEvent
|
||||
{
|
||||
/**
|
||||
* @return {@link NodeRef} instance that represents <b>Id</b> of one of the <b>Change Event</b> objects for some <b>Change Log Token</b>
|
||||
*/
|
||||
public NodeRef getNode();
|
||||
|
||||
/**
|
||||
* @return {@link CMISChangeType} <b>enum</b> value that determines the type of current <b>Change Event</b>
|
||||
*/
|
||||
public CMISChangeType getChangeType();
|
||||
|
||||
/**
|
||||
* @return {@link Date} value that represents time of current <b>Change Event</b>
|
||||
*/
|
||||
public Date getChangeTime();
|
||||
}
|
58
source/java/org/alfresco/cmis/CMISChangeLog.java
Executable file
58
source/java/org/alfresco/cmis/CMISChangeLog.java
Executable file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents descriptor for some <b>Change Log Token</b>
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public interface CMISChangeLog
|
||||
{
|
||||
/**
|
||||
* @return {@link List}<{@link CMISChangeEvent}> collection that contains all available for some <b>Change Log Token</b> <b>Change Events</b> descriptors
|
||||
*/
|
||||
public List<CMISChangeEvent> getChangeEvents();
|
||||
|
||||
/**
|
||||
* @return {@link Boolean} value that determines whether repository contains any more <b>Change Events</b> after some {@link CMISChangeLogService}.{@link #getChangeEvents()}
|
||||
* invocation
|
||||
*/
|
||||
public boolean hasMoreItems();
|
||||
|
||||
/**
|
||||
* <b>Note:</b> this is optional operation and actual <b>Change Events</b> amount in collection may not be equal to result of this method invocation
|
||||
*
|
||||
* @return {@link Integer} value that determines amount of <b>Change Events</b> those were returned
|
||||
*/
|
||||
public Integer getEventCount();
|
||||
|
||||
/**
|
||||
* @return {@link String} value that represents the next generated <b>Change Log Token</b>
|
||||
*/
|
||||
public String getNextChangeToken();
|
||||
}
|
85
source/java/org/alfresco/cmis/CMISChangeLogService.java
Executable file
85
source/java/org/alfresco/cmis/CMISChangeLogService.java
Executable file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Service for manipulating with <b>Change Log Events</b> by <b>Change Log Tokens</b>. Also this service exposes some methods for describing <b>Auditing</b> features
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public interface CMISChangeLogService
|
||||
{
|
||||
/**
|
||||
* @param changeLogToken - {@link String} value that represents some <b>Change Log Token</b>
|
||||
* @param maxItems - {@link Integer} value that determines required amount of entries
|
||||
* @return {@link CMISChangeLog} instance that describes entry mapped to specified <b>Change Log Token</b>
|
||||
*/
|
||||
public CMISChangeLog getChangeLogEvents(String changeLogToken, Integer maxItems);
|
||||
|
||||
/**
|
||||
* @return {@link String} value that represents <b>Change Log Token</b> which is currently actual
|
||||
*/
|
||||
public String getLastChangeLogToken();
|
||||
|
||||
/**
|
||||
* Gets the change log token maxItems entries before the given one
|
||||
*
|
||||
* @param currentPageToken
|
||||
* a change log token
|
||||
* @param maxItems
|
||||
* the number of entries to skip backwards
|
||||
* @return the change log token maxItems entries before currentPageToken
|
||||
*/
|
||||
public String getPreviousPageChangeLogToken(String currentPageToken, Integer maxItems);
|
||||
|
||||
/**
|
||||
* Assuming that currentPageToken begins a page of maxItems entries, gets the token at the start of the final page.
|
||||
*
|
||||
* @param currentPageToken
|
||||
* a change log token
|
||||
* @param maxItems
|
||||
* the number of entries per page
|
||||
* @return the change log token at the start of the final page
|
||||
*/
|
||||
public String getLastPageChangeLogToken(String currentPageToken, Integer maxItems);
|
||||
|
||||
/**
|
||||
* @return {@link CMISCapabilityChanges} <b>enum</b> value that specifies currently configured <b>Auditing</b> feature mode
|
||||
*/
|
||||
public CMISCapabilityChanges getCapability();
|
||||
|
||||
/**
|
||||
* @return {@link List}<{@link CMISBaseObjectTypeIds}> collection instance that contains configured value for Changes On Type capability
|
||||
* @see CMISBaseObjectTypeIds
|
||||
*/
|
||||
public List<CMISBaseObjectTypeIds> getChangesOnTypeCapability();
|
||||
|
||||
/**
|
||||
* @return always <b>true</b>
|
||||
*/
|
||||
public boolean getChangesIncomplete();
|
||||
}
|
53
source/java/org/alfresco/cmis/CMISChangeType.java
Executable file
53
source/java/org/alfresco/cmis/CMISChangeType.java
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* Enumeration of the <b>CMIS Change Type</b>. Possible values:<br />
|
||||
* <b>CREATED</b><br />
|
||||
* <b>UPDATED</b><br />
|
||||
* <b>DELETED</b><br />
|
||||
* <b>SECURITY</b>
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public enum CMISChangeType implements EnumLabel
|
||||
{
|
||||
CREATED("created"), UPDATED("updated"), DELETED("deleted"), SECURITY("security");
|
||||
|
||||
private String label;
|
||||
|
||||
CMISChangeType(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
public static final EnumFactory<CMISChangeType> FACTORY = new EnumFactory<CMISChangeType>(CMISChangeType.class);
|
||||
}
|
79
source/java/org/alfresco/cmis/CMISConstraintException.java
Normal file
79
source/java/org/alfresco/cmis/CMISConstraintException.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISConstraintException extends CMISRuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 575343231113393902L;
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
*/
|
||||
public CMISConstraintException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
*/
|
||||
public CMISConstraintException(String msgId, Object[] msgParams)
|
||||
{
|
||||
super(msgId, msgParams);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param cause
|
||||
*/
|
||||
public CMISConstraintException(String msgId, Throwable cause)
|
||||
{
|
||||
super(msgId, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
* @param cause
|
||||
*/
|
||||
public CMISConstraintException(String msgId, Object[] msgParams, Throwable cause)
|
||||
{
|
||||
super(msgId, msgParams, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
48
source/java/org/alfresco/cmis/CMISPermissionDefinition.java
Normal file
48
source/java/org/alfresco/cmis/CMISPermissionDefinition.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
/**
|
||||
* A permission definition
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISPermissionDefinition
|
||||
{
|
||||
/**
|
||||
* The unique permission string (used for assignment)
|
||||
* @return the permission.
|
||||
*/
|
||||
public String getPermission();
|
||||
|
||||
/**
|
||||
* An optional permission description.
|
||||
* If not set, this defaults to the permission.
|
||||
*
|
||||
* @return the optional description.
|
||||
*/
|
||||
public String getDescription();
|
||||
}
|
52
source/java/org/alfresco/cmis/CMISPermissionMapping.java
Normal file
52
source/java/org/alfresco/cmis/CMISPermissionMapping.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A CMIS permission mapping.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISPermissionMapping
|
||||
{
|
||||
/**
|
||||
* Get the allowed action key.
|
||||
* @return the key.
|
||||
*/
|
||||
public String getKey();
|
||||
|
||||
/**
|
||||
* Get the required permissions.
|
||||
* If the list is of zero length the action is unprotected and allowed.
|
||||
* (Disallowed actions never appear at all)
|
||||
* For one or more entries a match against any permission allws.
|
||||
*
|
||||
* @return the list of required permissions.
|
||||
*/
|
||||
public List<String> getPermissions();
|
||||
}
|
@@ -128,9 +128,10 @@ public interface CMISPropertyLuceneBuilder
|
||||
public Query buildLuceneLike(LuceneQueryParser lqp, Serializable value, Boolean not) throws ParseException;
|
||||
|
||||
/**
|
||||
* @param lqp TODO
|
||||
* @return the sort field
|
||||
*/
|
||||
public String getLuceneSortField();
|
||||
public String getLuceneSortField(LuceneQueryParser lqp);
|
||||
|
||||
/**
|
||||
* @return the field name
|
||||
|
@@ -24,13 +24,12 @@
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISQueryException extends AlfrescoRuntimeException
|
||||
public class CMISQueryException extends CMISRuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
|
90
source/java/org/alfresco/cmis/CMISRendition.java
Executable file
90
source/java/org/alfresco/cmis/CMISRendition.java
Executable file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* CMIS Document Rendition
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public interface CMISRendition
|
||||
{
|
||||
/**
|
||||
* Gets the thumbnail node reference
|
||||
*/
|
||||
public NodeRef getNodeRef();
|
||||
|
||||
/**
|
||||
* Get the rendition stream id
|
||||
* @return
|
||||
*/
|
||||
public String getStreamId();
|
||||
|
||||
/**
|
||||
* Get the MIME type of the rendition stream.
|
||||
* @return
|
||||
*/
|
||||
public String getMimeType();
|
||||
|
||||
/**
|
||||
* Get rendition kind.
|
||||
* @return
|
||||
*/
|
||||
public CMISRenditionKind getKind();
|
||||
|
||||
/**
|
||||
* Get the height of image. Typically used for ‘image’ renditions (expressed as pixels).
|
||||
* @return
|
||||
*/
|
||||
public Integer getHeight();
|
||||
|
||||
/**
|
||||
* Get the width of image. Typically used for ‘image’ renditions (expressed as pixels).
|
||||
* @return
|
||||
*/
|
||||
public Integer getWidth();
|
||||
|
||||
/**
|
||||
* Get a human readable information about the rendition.
|
||||
* @return
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
* Get the length of the rendition stream in bytes.
|
||||
* @return
|
||||
*/
|
||||
public Integer getLength();
|
||||
|
||||
/**
|
||||
* Get the rendition document id. If specified, then the rendition can also be accessed
|
||||
* as a document object in the CMIS services.
|
||||
* @return
|
||||
*/
|
||||
public String getRenditionDocumentId();
|
||||
|
||||
}
|
64
source/java/org/alfresco/cmis/CMISRenditionKind.java
Executable file
64
source/java/org/alfresco/cmis/CMISRenditionKind.java
Executable file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of the CMIS Rendition Kinds
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public enum CMISRenditionKind implements EnumLabel
|
||||
{
|
||||
THUMBNAIL("cmis:thumbnail"),
|
||||
WEB_PREVIEW("alf:webpreview"),
|
||||
ICON16("alf:icon16"),
|
||||
ICON32("alf:icon32");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISRenditionKind(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
public static EnumFactory<CMISRenditionKind> FACTORY = new EnumFactory<CMISRenditionKind>(CMISRenditionKind.class);
|
||||
|
||||
}
|
47
source/java/org/alfresco/cmis/CMISRenditionService.java
Executable file
47
source/java/org/alfresco/cmis/CMISRenditionService.java
Executable file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Service to retrieving renditions of document
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public interface CMISRenditionService
|
||||
{
|
||||
/**
|
||||
* Get renditions for a document.
|
||||
*
|
||||
* @param node node reference of document
|
||||
* @param renditionFilter renditions filter
|
||||
* @return list of renditions
|
||||
*/
|
||||
public List<CMISRendition> getRenditions(NodeRef node, String renditionFilter);
|
||||
|
||||
}
|
81
source/java/org/alfresco/cmis/CMISRuntimeException.java
Normal file
81
source/java/org/alfresco/cmis/CMISRuntimeException.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISRuntimeException extends AlfrescoRuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 121670154804835474L;
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
*/
|
||||
public CMISRuntimeException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
*/
|
||||
public CMISRuntimeException(String msgId, Object[] msgParams)
|
||||
{
|
||||
super(msgId, msgParams);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param cause
|
||||
*/
|
||||
public CMISRuntimeException(String msgId, Throwable cause)
|
||||
{
|
||||
super(msgId, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
* @param cause
|
||||
*/
|
||||
public CMISRuntimeException(String msgId, Object[] msgParams, Throwable cause)
|
||||
{
|
||||
super(msgId, msgParams, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,7 +18,7 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
@@ -83,6 +83,17 @@ public interface CMISServices
|
||||
*/
|
||||
public NodeRef getNode(String referenceType, String[] reference);
|
||||
|
||||
/**
|
||||
* Gets a map of node attributes relating to renditions.
|
||||
*
|
||||
* @param nodeRef
|
||||
* the node ref
|
||||
* @param renditionFilter
|
||||
* the rendition filter
|
||||
* @return the attribute map
|
||||
*/
|
||||
public Map<String, Object> getRenditions(NodeRef nodeRef, String renditionFilter);
|
||||
|
||||
/**
|
||||
* Query for node children
|
||||
*
|
||||
|
@@ -139,7 +139,7 @@ public interface CMISTypeDefinition
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isIncludeInSuperTypeQuery();
|
||||
public boolean isIncludedInSuperTypeQuery();
|
||||
|
||||
/**
|
||||
* Is this type versionable? If true this implies all instances of the type are versionable.
|
||||
|
@@ -40,8 +40,8 @@ import java.util.TreeMap;
|
||||
*/
|
||||
public class EnumFactory<E extends Enum<E>>
|
||||
{
|
||||
private Enum<E> defaultEnum;
|
||||
private Map<String, Enum<E>> labelMap = new HashMap<String, Enum<E>>(10);
|
||||
private E defaultEnum;
|
||||
private Map<String, E> labelMap = new HashMap<String, E>(10);
|
||||
|
||||
/**
|
||||
* @param enumClass
|
||||
@@ -55,7 +55,7 @@ public class EnumFactory<E extends Enum<E>>
|
||||
* @param enumClass
|
||||
* @param defaultEnum
|
||||
*/
|
||||
public EnumFactory(Class<E> enumClass, Enum<E> defaultEnum)
|
||||
public EnumFactory(Class<E> enumClass, E defaultEnum)
|
||||
{
|
||||
this(enumClass, defaultEnum, false);
|
||||
}
|
||||
@@ -65,17 +65,17 @@ public class EnumFactory<E extends Enum<E>>
|
||||
* @param defaultEnum
|
||||
* @param caseSensitive case-sensitive lookup for Enum label
|
||||
*/
|
||||
public EnumFactory(Class<E> enumClass, Enum<E> defaultEnum, boolean caseSensitive)
|
||||
public EnumFactory(Class<E> enumClass, E defaultEnum, boolean caseSensitive)
|
||||
{
|
||||
this.defaultEnum = defaultEnum;
|
||||
|
||||
// setup label map
|
||||
labelMap = caseSensitive ? new HashMap<String, Enum<E>>(10) : new TreeMap<String, Enum<E>>(String.CASE_INSENSITIVE_ORDER);
|
||||
labelMap = caseSensitive ? new HashMap<String, E>(10) : new TreeMap<String, E>(String.CASE_INSENSITIVE_ORDER);
|
||||
EnumSet<E> enumSet = EnumSet.allOf(enumClass);
|
||||
Iterator<E> iter = enumSet.iterator();
|
||||
while(iter.hasNext())
|
||||
{
|
||||
Enum<E> e = iter.next();
|
||||
E e = iter.next();
|
||||
if (e instanceof EnumLabel)
|
||||
{
|
||||
labelMap.put(((EnumLabel)e).getLabel(), e);
|
||||
@@ -109,7 +109,7 @@ public class EnumFactory<E extends Enum<E>>
|
||||
* @param e enum
|
||||
* @return label (or null, if no label specified)
|
||||
*/
|
||||
public String label(Enum<E> e)
|
||||
public String label(E e)
|
||||
{
|
||||
if (e instanceof EnumLabel)
|
||||
{
|
||||
@@ -135,7 +135,7 @@ public class EnumFactory<E extends Enum<E>>
|
||||
* @param label
|
||||
* @return enum (or null, if no enum has specified label)
|
||||
*/
|
||||
public Enum<E> fromLabel(String label)
|
||||
public E fromLabel(String label)
|
||||
{
|
||||
return labelMap.get(label);
|
||||
}
|
||||
@@ -148,9 +148,9 @@ public class EnumFactory<E extends Enum<E>>
|
||||
* @param label
|
||||
* @return enum (or default enum, if label is invalid)
|
||||
*/
|
||||
public Enum<E> toEnum(String label)
|
||||
public E toEnum(String label)
|
||||
{
|
||||
Enum<E> e = (label == null) ? null : fromLabel(label);
|
||||
E e = (label == null) ? null : fromLabel(label);
|
||||
if (e == null)
|
||||
{
|
||||
e = defaultEnum;
|
||||
|
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* Thrown when an unsupported CMISAclPropagationModeEnum is specified.
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class UnsupportedCMISAclPropagationMode extends AlfrescoRuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3844368557738616296L;
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
* @param cause
|
||||
*/
|
||||
public UnsupportedCMISAclPropagationMode(String msgId, Object[] msgParams, Throwable cause)
|
||||
{
|
||||
super(msgId, msgParams, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
*/
|
||||
public UnsupportedCMISAclPropagationMode(String msgId, Object[] msgParams)
|
||||
{
|
||||
super(msgId, msgParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param cause
|
||||
*/
|
||||
public UnsupportedCMISAclPropagationMode(String msgId, Throwable cause)
|
||||
{
|
||||
super(msgId, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
*/
|
||||
public UnsupportedCMISAclPropagationMode(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId;
|
||||
import org.alfresco.cmis.CMISAccessControlEntry;
|
||||
import org.alfresco.cmis.CMISConstraintException;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISAccessControlEntriesGroupedByPrincipalIdImpl implements CMISAccessControlEntriesGroupedByPrincipalId
|
||||
{
|
||||
private String principalId;
|
||||
|
||||
private List<String> directPermissions = new ArrayList<String>();
|
||||
|
||||
private List<String> indirectPermissions = new ArrayList<String>();
|
||||
|
||||
/*package */ CMISAccessControlEntriesGroupedByPrincipalIdImpl(String principalId)
|
||||
{
|
||||
this.principalId = principalId;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId#getDirectPermissions()
|
||||
*/
|
||||
public List<String> getDirectPermissions()
|
||||
{
|
||||
return directPermissions;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId#getInirectPermissions()
|
||||
*/
|
||||
public List<String> getIndirectPermissions()
|
||||
{
|
||||
return indirectPermissions;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId#getPrincipalId()
|
||||
*/
|
||||
public String getPrincipalId()
|
||||
{
|
||||
return principalId;
|
||||
}
|
||||
|
||||
/* package */ void addEntry(CMISAccessControlEntry entry)
|
||||
{
|
||||
if(!principalId.equals(entry.getPrincipalId()))
|
||||
{
|
||||
throw new CMISConstraintException("Grouping error in principal id");
|
||||
}
|
||||
if(entry.getDirect())
|
||||
{
|
||||
directPermissions.add(entry.getPermission());
|
||||
}
|
||||
else
|
||||
{
|
||||
indirectPermissions.add(entry.getPermission());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlEntry;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISAccessControlEntryImpl implements CMISAccessControlEntry
|
||||
{
|
||||
private String principalId;
|
||||
|
||||
private String permission;
|
||||
|
||||
private int position;
|
||||
|
||||
/*package*/ CMISAccessControlEntryImpl(String principalId, String permission, int position)
|
||||
{
|
||||
this.principalId = principalId;
|
||||
this.permission = permission;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used for external calls to add or delete aces.
|
||||
* (All must be at position 0 === directly set on the object)
|
||||
*
|
||||
* @param principalId
|
||||
* @param permission
|
||||
*/
|
||||
public CMISAccessControlEntryImpl(String principalId, String permission)
|
||||
{
|
||||
this(principalId, permission, 0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntry#getDirect()
|
||||
*/
|
||||
public boolean getDirect()
|
||||
{
|
||||
return position == 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntry#getPermission()
|
||||
*/
|
||||
public String getPermission()
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlEntry#getPrincipalId()
|
||||
*/
|
||||
public String getPrincipalId()
|
||||
{
|
||||
return principalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the position
|
||||
*/
|
||||
public int getPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((permission == null) ? 0 : permission.hashCode());
|
||||
result = prime * result + position;
|
||||
result = prime * result + ((principalId == null) ? 0 : principalId.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final CMISAccessControlEntryImpl other = (CMISAccessControlEntryImpl) obj;
|
||||
if (permission == null)
|
||||
{
|
||||
if (other.permission != null)
|
||||
return false;
|
||||
}
|
||||
else if (!permission.equals(other.permission))
|
||||
return false;
|
||||
if (position != other.position)
|
||||
return false;
|
||||
if (principalId == null)
|
||||
{
|
||||
if (other.principalId != null)
|
||||
return false;
|
||||
}
|
||||
else if (!principalId.equals(other.principalId))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[");
|
||||
builder.append(getPrincipalId()).append(", ");
|
||||
builder.append(getPermission()).append(", ");
|
||||
builder.append(getPosition()).append(", ");
|
||||
builder.append(getDirect()).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId;
|
||||
import org.alfresco.cmis.CMISAccessControlEntry;
|
||||
import org.alfresco.cmis.CMISAccessControlReport;
|
||||
|
||||
/**
|
||||
* A simple CMIS access control report
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISAccessControlReportImpl implements CMISAccessControlReport
|
||||
{
|
||||
private ArrayList<CMISAccessControlEntry> entries = new ArrayList<CMISAccessControlEntry>();
|
||||
|
||||
private boolean extract = false;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlReport#getAccessControlEntries()
|
||||
*/
|
||||
public List<CMISAccessControlEntry> getAccessControlEntries()
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlReport#isExtract()
|
||||
*/
|
||||
public boolean isExtract()
|
||||
{
|
||||
return extract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extract.
|
||||
* @param extract
|
||||
*/
|
||||
public void setExtract(boolean extract)
|
||||
{
|
||||
this.extract = extract;
|
||||
}
|
||||
|
||||
/*package*/ void addEntry(CMISAccessControlEntry entry)
|
||||
{
|
||||
removeEntry(entry);
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
/*package*/ void removeEntry(CMISAccessControlEntry entry)
|
||||
{
|
||||
for(int i = 0; i < entries.size(); i++)
|
||||
{
|
||||
CMISAccessControlEntry current = entries.get(i);
|
||||
if(current.getPrincipalId().equals(entry.getPrincipalId()) && current.getPermission().equals(entry.getPermission()))
|
||||
{
|
||||
entries.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlReport#getAccessControlEntriesGroupedByPrincipalId()
|
||||
*/
|
||||
public List<? extends CMISAccessControlEntriesGroupedByPrincipalId> getAccessControlEntriesGroupedByPrincipalId()
|
||||
{
|
||||
HashMap<String, CMISAccessControlEntriesGroupedByPrincipalIdImpl> grouped = new HashMap<String, CMISAccessControlEntriesGroupedByPrincipalIdImpl>();
|
||||
for(CMISAccessControlEntry entry : getAccessControlEntries())
|
||||
{
|
||||
CMISAccessControlEntriesGroupedByPrincipalIdImpl value = grouped.get(entry.getPrincipalId());
|
||||
if(value == null)
|
||||
{
|
||||
value = new CMISAccessControlEntriesGroupedByPrincipalIdImpl(entry.getPrincipalId());
|
||||
grouped.put(entry.getPrincipalId(), value);
|
||||
}
|
||||
value.addEntry(entry);
|
||||
}
|
||||
ArrayList<CMISAccessControlEntriesGroupedByPrincipalIdImpl> answer = new ArrayList<CMISAccessControlEntriesGroupedByPrincipalIdImpl>(grouped.values());
|
||||
return answer;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlEntry;
|
||||
import org.alfresco.cmis.CMISAccessControlFormatEnum;
|
||||
import org.alfresco.cmis.CMISAccessControlReport;
|
||||
import org.alfresco.cmis.CMISAccessControlService;
|
||||
import org.alfresco.cmis.CMISAclCapabilityEnum;
|
||||
import org.alfresco.cmis.CMISAclPropagationEnum;
|
||||
import org.alfresco.cmis.CMISAclSupportedPermissionEnum;
|
||||
import org.alfresco.cmis.CMISAllowedActionEnum;
|
||||
import org.alfresco.cmis.CMISConstraintException;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISPermissionDefinition;
|
||||
import org.alfresco.cmis.CMISPermissionMapping;
|
||||
import org.alfresco.cmis.CMISTypeDefinition;
|
||||
import org.alfresco.cmis.mapping.CMISMapping;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.permissions.PermissionReference;
|
||||
import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl;
|
||||
import org.alfresco.repo.security.permissions.impl.ModelDAO;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*/
|
||||
public class CMISAccessControlServiceImpl implements CMISAccessControlService
|
||||
{
|
||||
private CMISAclCapabilityEnum aclCapabilityEnum;
|
||||
|
||||
private CMISAclSupportedPermissionEnum aclSupportedPermissionEnum;
|
||||
|
||||
private CMISAclPropagationEnum aclPropagationEnum;
|
||||
|
||||
private ModelDAO permissionModelDao;
|
||||
|
||||
private PermissionService permissionService;
|
||||
|
||||
private CMISMapping cmisMapping;
|
||||
|
||||
private NodeService nodeService;
|
||||
|
||||
private CMISDictionaryService cmisDictionaryService;
|
||||
|
||||
/**
|
||||
* @param aclCapabilityEnum
|
||||
* the aclCapabilityEnum to set
|
||||
*/
|
||||
public void setAclCapabilityEnum(CMISAclCapabilityEnum aclCapabilityEnum)
|
||||
{
|
||||
this.aclCapabilityEnum = aclCapabilityEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the acl supported permission enum.
|
||||
*
|
||||
* @param aclSupportedPermissionEnum
|
||||
* the aclSupportedPermissionEnum to set
|
||||
*/
|
||||
public void setAclSupportedPermissionEnum(CMISAclSupportedPermissionEnum aclSupportedPermissionEnum)
|
||||
{
|
||||
this.aclSupportedPermissionEnum = aclSupportedPermissionEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aclPropagationEnum
|
||||
* the aclPropagationEnum to set
|
||||
*/
|
||||
public void setAclPropagationEnum(CMISAclPropagationEnum aclPropagationEnum)
|
||||
{
|
||||
this.aclPropagationEnum = aclPropagationEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissionModelDao
|
||||
* the permissionModelDao to set
|
||||
*/
|
||||
public void setPermissionModelDao(ModelDAO permissionModelDao)
|
||||
{
|
||||
this.permissionModelDao = permissionModelDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissionService
|
||||
* the permissionService to set
|
||||
*/
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cmis mapping.
|
||||
*
|
||||
* @param cmisMapping
|
||||
* the cmis mapping
|
||||
*/
|
||||
public void setCMISMapping(CMISMapping cmisMapping)
|
||||
{
|
||||
this.cmisMapping = cmisMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
* the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmisDictionaryService
|
||||
* the cmisDictionaryService to set
|
||||
*/
|
||||
public void setCMISDictionaryService(CMISDictionaryService cmisDictionaryService)
|
||||
{
|
||||
this.cmisDictionaryService = cmisDictionaryService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#applyAcl(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* java.util.List)
|
||||
*/
|
||||
public CMISAccessControlReport applyAcl(NodeRef nodeRef, List<CMISAccessControlEntry> acesToApply)
|
||||
{
|
||||
Set<CMISAccessControlEntry> acesToAdd = new LinkedHashSet<CMISAccessControlEntry>(acesToApply);
|
||||
List<? extends CMISAccessControlEntry> acesExisting = getAcl(nodeRef,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS).getAccessControlEntries();
|
||||
List<CMISAccessControlEntry> acesToRemove = new ArrayList<CMISAccessControlEntry>(acesExisting.size());
|
||||
for (CMISAccessControlEntry accessControlEntry : acesExisting)
|
||||
{
|
||||
// Only pay attention to existing direct entries
|
||||
if (accessControlEntry.getDirect() && !acesToAdd.remove(accessControlEntry))
|
||||
{
|
||||
acesToRemove.add(accessControlEntry);
|
||||
}
|
||||
}
|
||||
return applyAcl(nodeRef, acesToRemove, new ArrayList<CMISAccessControlEntry>(acesToAdd),
|
||||
CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#applyAcl(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* java.util.List, java.util.List, org.alfresco.cmis.CMISAclPropagationEnum)
|
||||
*/
|
||||
public CMISAccessControlReport applyAcl(NodeRef nodeRef, List<CMISAccessControlEntry> acesToRemove, List<CMISAccessControlEntry> acesToAdd, CMISAclPropagationEnum propagation,
|
||||
CMISAccessControlFormatEnum format)
|
||||
{
|
||||
if (propagation != CMISAclPropagationEnum.PROPAGATE)
|
||||
{
|
||||
throw new CMISConstraintException("Unsupported ACL propagation mode: " + propagation);
|
||||
}
|
||||
// Check controllable ACL
|
||||
QName type = nodeService.getType(nodeRef);
|
||||
CMISTypeDefinition cmisType = cmisDictionaryService.findTypeForClass(type);
|
||||
if (false == cmisType.isControllableACL())
|
||||
{
|
||||
throw new CMISConstraintException("ACLs are not supported for type: " + cmisType.getDisplayName());
|
||||
}
|
||||
// TODO: Check valid permissions. We do not check this internally. Ignore for now ...
|
||||
|
||||
if (acesToRemove != null)
|
||||
{
|
||||
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(nodeRef);
|
||||
for (CMISAccessControlEntry entry : acesToRemove)
|
||||
{
|
||||
String alfrescoPermission = cmisMapping.getSetPermission(compressPermission(entry.getPermission()));
|
||||
AccessPermission toCheck = new AccessPermissionImpl(alfrescoPermission, AccessStatus.ALLOWED, entry.getPrincipalId(), 0);
|
||||
if (false == permissions.contains(toCheck))
|
||||
{
|
||||
throw new CMISConstraintException("No matching ACE found to delete");
|
||||
}
|
||||
permissionService.deletePermission(nodeRef, entry.getPrincipalId(), alfrescoPermission);
|
||||
}
|
||||
}
|
||||
if (acesToAdd != null)
|
||||
{
|
||||
for (CMISAccessControlEntry entry : acesToAdd)
|
||||
{
|
||||
String alfrescoPermission = cmisMapping.getSetPermission(compressPermission(entry.getPermission()));
|
||||
permissionService.setPermission(nodeRef, entry.getPrincipalId(), alfrescoPermission, true);
|
||||
}
|
||||
}
|
||||
return getAcl(nodeRef, format);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getAcl(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.cmis.CMISAccessControlFormatEnum)
|
||||
*/
|
||||
public CMISAccessControlReport getAcl(NodeRef nodeRef, CMISAccessControlFormatEnum format)
|
||||
{
|
||||
CMISAccessControlReportImpl answer = new CMISAccessControlReportImpl();
|
||||
// Need to compact deny to mask correctly
|
||||
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(nodeRef);
|
||||
ArrayList<AccessPermission> ordered = new ArrayList<AccessPermission>();
|
||||
AccessPermissionComparator comparator = new AccessPermissionComparator();
|
||||
for (AccessPermission current : permissions)
|
||||
{
|
||||
int index = Collections.binarySearch(ordered, current, comparator);
|
||||
if (index < 0)
|
||||
{
|
||||
ordered.add(-index - 1, current);
|
||||
}
|
||||
}
|
||||
|
||||
for (AccessPermission entry : ordered)
|
||||
{
|
||||
if (entry.getAccessStatus() == AccessStatus.ALLOWED)
|
||||
{
|
||||
answer.addEntry(new CMISAccessControlEntryImpl(entry.getAuthority(), expandPermission(cmisMapping.getReportedPermission(getPermission(entry.getPermission()),
|
||||
format)), entry.getPosition()));
|
||||
}
|
||||
else if (entry.getAccessStatus() == AccessStatus.DENIED)
|
||||
{
|
||||
answer.removeEntry(new CMISAccessControlEntryImpl(entry.getAuthority(), expandPermission(cmisMapping.getReportedPermission(getPermission(entry.getPermission()),
|
||||
format)), entry.getPosition()));
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
private String getPermission(String string)
|
||||
{
|
||||
PermissionReference permissionReference = permissionModelDao.getPermissionReference(null, string);
|
||||
if (permissionModelDao.isUnique(permissionReference))
|
||||
{
|
||||
return permissionReference.getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
return permissionReference.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String expandPermission(String permission)
|
||||
{
|
||||
if (permission.equals(CMIS_ALL_PERMISSION))
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
else if (permission.equals(CMIS_READ_PERMISSION))
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
else if (permission.equals(CMIS_WRITE_PERMISSION))
|
||||
{
|
||||
return permission;
|
||||
|
||||
}
|
||||
else if (permission.startsWith("{"))
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
else
|
||||
{
|
||||
PermissionReference permissionReference = permissionModelDao.getPermissionReference(null, permission);
|
||||
return permissionReference.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String compressPermission(String permission) {
|
||||
int sepIndex;
|
||||
if (permission.equals(CMIS_ALL_PERMISSION) || permission.equals(CMIS_READ_PERMISSION)
|
||||
|| permission.equals(CMIS_WRITE_PERMISSION) || !permission.startsWith("{")
|
||||
|| (sepIndex = permission.lastIndexOf('.')) == -1) {
|
||||
return permission;
|
||||
}
|
||||
return permission.substring(sepIndex + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getAclCapability()
|
||||
*/
|
||||
public CMISAclCapabilityEnum getAclCapability()
|
||||
{
|
||||
return aclCapabilityEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the acl capability enum.
|
||||
*
|
||||
* @param aclCapabilityEnum
|
||||
*/
|
||||
public void setAclCapability(CMISAclCapabilityEnum aclCapabilityEnum)
|
||||
{
|
||||
this.aclCapabilityEnum = aclCapabilityEnum;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getSupportedPermissions()
|
||||
*/
|
||||
public CMISAclSupportedPermissionEnum getSupportedPermissions()
|
||||
{
|
||||
return this.aclSupportedPermissionEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the supported permissions.
|
||||
*
|
||||
* @param aclSupportedPermissionEnum
|
||||
* the supported permissions
|
||||
*/
|
||||
public void setSupportedPermissions(CMISAclSupportedPermissionEnum aclSupportedPermissionEnum)
|
||||
{
|
||||
this.aclSupportedPermissionEnum = aclSupportedPermissionEnum;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getAclPropagation()
|
||||
*/
|
||||
public CMISAclPropagationEnum getAclPropagation()
|
||||
{
|
||||
return aclPropagationEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the acl propagation enum.
|
||||
*
|
||||
* @param aclPropagationEnum
|
||||
*/
|
||||
public void setAclPropagation(CMISAclPropagationEnum aclPropagationEnum)
|
||||
{
|
||||
this.aclPropagationEnum = aclPropagationEnum;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getPermissionMappings()
|
||||
*/
|
||||
public List<? extends CMISPermissionMapping> getPermissionMappings()
|
||||
{
|
||||
ArrayList<CMISPermissionMappingImpl> mappings = new ArrayList<CMISPermissionMappingImpl>();
|
||||
for(CMISAllowedActionEnum e : EnumSet.allOf(CMISAllowedActionEnum.class))
|
||||
{
|
||||
Map<String, List<String>> enumMappings = e.getPermissionMapping();
|
||||
for(String key : enumMappings.keySet())
|
||||
{
|
||||
List<String> list = enumMappings.get(key);
|
||||
CMISPermissionMappingImpl mapping = new CMISPermissionMappingImpl(key, list);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getRepositoryPermissions()
|
||||
*/
|
||||
public List<CMISPermissionDefinition> getRepositoryPermissions()
|
||||
{
|
||||
ArrayList<CMISPermissionDefinition> answer = new ArrayList<CMISPermissionDefinition>();
|
||||
PermissionReference allPermission = permissionModelDao.getPermissionReference(null, PermissionService.ALL_PERMISSIONS);
|
||||
Set<PermissionReference> all = permissionModelDao.getAllExposedPermissions();
|
||||
for (PermissionReference pr : all)
|
||||
{
|
||||
addPermissionDefinition(answer, pr);
|
||||
}
|
||||
// Add All
|
||||
addPermissionDefinition(answer, allPermission);
|
||||
// Add CMIS permissions
|
||||
answer.add(new CMISPermissionDefinitionImpl(CMIS_ALL_PERMISSION));
|
||||
answer.add(new CMISPermissionDefinitionImpl(CMIS_READ_PERMISSION));
|
||||
answer.add(new CMISPermissionDefinitionImpl(CMIS_WRITE_PERMISSION));
|
||||
return answer;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getPrincipalAnonymous()
|
||||
*/
|
||||
public String getPrincipalAnonymous()
|
||||
{
|
||||
return AuthenticationUtil.getGuestUserName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISAccessControlService#getPrincipalAnyone()
|
||||
*/
|
||||
public String getPrincipalAnyone()
|
||||
{
|
||||
return PermissionService.ALL_AUTHORITIES;
|
||||
}
|
||||
|
||||
private void addPermissionDefinition(ArrayList<CMISPermissionDefinition> list, PermissionReference pr)
|
||||
{
|
||||
CMISPermissionDefinitionImpl def = new CMISPermissionDefinitionImpl(getPermissionString(pr));
|
||||
list.add(def);
|
||||
}
|
||||
|
||||
private String getPermissionString(PermissionReference pr)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(pr.getQName().toString());
|
||||
builder.append(".");
|
||||
builder.append(pr.getName());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static class AccessPermissionComparator implements Comparator<AccessPermission>
|
||||
{
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public int compare(AccessPermission left, AccessPermission right)
|
||||
{
|
||||
if (left.getPosition() != right.getPosition())
|
||||
{
|
||||
return right.getPosition() - left.getPosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.getAccessStatus() != right.getAccessStatus())
|
||||
{
|
||||
return (left.getAccessStatus() == AccessStatus.DENIED) ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int compare = left.getAuthority().compareTo(right.getAuthority());
|
||||
if (compare != 0)
|
||||
{
|
||||
return compare;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (left.getPermission().compareTo(right.getPermission()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlEntriesGroupedByPrincipalId;
|
||||
import org.alfresco.cmis.CMISAccessControlEntry;
|
||||
import org.alfresco.cmis.CMISAccessControlFormatEnum;
|
||||
import org.alfresco.cmis.CMISAccessControlReport;
|
||||
import org.alfresco.cmis.CMISAccessControlService;
|
||||
import org.alfresco.cmis.CMISAclCapabilityEnum;
|
||||
import org.alfresco.cmis.CMISAclPropagationEnum;
|
||||
import org.alfresco.cmis.CMISConstraintException;
|
||||
import org.alfresco.cmis.CMISPermissionDefinition;
|
||||
import org.alfresco.cmis.CMISPermissionMapping;
|
||||
import org.alfresco.cmis.acl.CMISAccessControlServiceImpl.AccessPermissionComparator;
|
||||
import org.alfresco.cmis.mapping.BaseCMISTest;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.permissions.PermissionReference;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*/
|
||||
public class CMISAccessControlServiceTest extends BaseCMISTest
|
||||
{
|
||||
private NodeRef parent;
|
||||
|
||||
private NodeRef child;
|
||||
|
||||
private NodeRef grandParent;
|
||||
|
||||
public void testAclPropagationMode()
|
||||
{
|
||||
assertEquals(CMISAclPropagationEnum.PROPAGATE, cmisAccessControlService.getAclPropagation());
|
||||
}
|
||||
|
||||
public void testAclCapability()
|
||||
{
|
||||
assertEquals(CMISAclCapabilityEnum.MANAGE, cmisAccessControlService.getAclCapability());
|
||||
}
|
||||
|
||||
public void testPermissions()
|
||||
{
|
||||
List<CMISPermissionDefinition> allPermissions = cmisAccessControlService.getRepositoryPermissions();
|
||||
assertEquals(69, allPermissions.size());
|
||||
HashSet<CMISPermissionDefinition> permissionSet = new HashSet<CMISPermissionDefinition>();
|
||||
permissionSet.addAll(allPermissions);
|
||||
assertEquals(69, permissionSet.size());
|
||||
|
||||
}
|
||||
|
||||
public void testAclReportingCmisPermissionsOnly()
|
||||
{
|
||||
createTestAcls();
|
||||
|
||||
CMISAccessControlReport grandParentReport = cmisAccessControlService.getAcl(grandParent, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(7, grandParentReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(grandParentReport, PermissionService.ADMINISTRATOR_AUTHORITY, 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, PermissionService.ALL_AUTHORITIES, 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "ToMask", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Full", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Reader", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Writer", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Multi", 1, 0));
|
||||
|
||||
CMISAccessControlReport parentReport = cmisAccessControlService.getAcl(parent, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(parentReport.isExtract());
|
||||
assertEquals(9, parentReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(parentReport, PermissionService.ADMINISTRATOR_AUTHORITY, 0, 1));
|
||||
assertTrue(checkCounts(parentReport, PermissionService.ALL_AUTHORITIES, 0, 1));
|
||||
assertTrue(checkAbsent(parentReport, "ToMask"));
|
||||
assertTrue(checkCounts(parentReport, "Full", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "Reader", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "Writer", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "SplitRead", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "SplitWrite", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "DuplicateRead", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "Multi", 1, 0));
|
||||
|
||||
CMISAccessControlReport childReport = cmisAccessControlService.getAcl(child, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(12, childReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(childReport, PermissionService.ADMINISTRATOR_AUTHORITY, 0, 1));
|
||||
assertTrue(checkCounts(childReport, PermissionService.ALL_AUTHORITIES, 0, 1));
|
||||
assertTrue(checkAbsent(childReport, "ToMask"));
|
||||
assertTrue(checkCounts(childReport, "Full", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "Reader", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "Writer", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "SplitRead", 1, 0));
|
||||
assertTrue(checkCounts(childReport, "SplitWrite", 1, 0));
|
||||
assertTrue(checkCounts(childReport, "DuplicateRead", 1, 0));
|
||||
assertTrue(checkCounts(childReport, "Writer2", 1, 0));
|
||||
assertTrue(checkCounts(childReport, "Multi", 3, 0));
|
||||
}
|
||||
|
||||
private Set<String> getAllPermissions()
|
||||
{
|
||||
HashSet<String> answer = new HashSet<String>();
|
||||
PermissionReference allPermission = permissionModelDao.getPermissionReference(null, PermissionService.ALL_PERMISSIONS);
|
||||
Set<PermissionReference> all = permissionModelDao.getAllPermissions();
|
||||
for (PermissionReference pr : all)
|
||||
{
|
||||
answer.add(pr.toString());
|
||||
}
|
||||
// Add All
|
||||
answer.add(allPermission.toString());
|
||||
// Add CMIS permissions
|
||||
answer.add(CMISAccessControlService.CMIS_ALL_PERMISSION);
|
||||
answer.add(CMISAccessControlService.CMIS_READ_PERMISSION);
|
||||
answer.add(CMISAccessControlService.CMIS_WRITE_PERMISSION);
|
||||
return answer;
|
||||
}
|
||||
|
||||
private boolean checkCounts(CMISAccessControlReport report, String key, int direct, int indirect)
|
||||
{
|
||||
// check all permissions are valid
|
||||
|
||||
Set<String> permissionNames = getAllPermissions();
|
||||
|
||||
for (CMISAccessControlEntry entry : report.getAccessControlEntries())
|
||||
{
|
||||
if (!permissionNames.contains(entry.getPermission()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check counts
|
||||
|
||||
for (CMISAccessControlEntriesGroupedByPrincipalId group : report.getAccessControlEntriesGroupedByPrincipalId())
|
||||
{
|
||||
if (group.getPrincipalId().equals(key))
|
||||
{
|
||||
if (group.getDirectPermissions().size() != direct)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (group.getIndirectPermissions().size() != indirect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkAbsent(CMISAccessControlReport report, String key)
|
||||
{
|
||||
for (CMISAccessControlEntriesGroupedByPrincipalId group : report.getAccessControlEntriesGroupedByPrincipalId())
|
||||
{
|
||||
if (group.getPrincipalId().equals(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void testAclReportingAllPermissions()
|
||||
{
|
||||
createTestAcls();
|
||||
|
||||
CMISAccessControlReport grandParentReport = cmisAccessControlService.getAcl(grandParent, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(7, grandParentReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(grandParentReport, PermissionService.ADMINISTRATOR_AUTHORITY, 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, PermissionService.ALL_AUTHORITIES, 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "ToMask", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Full", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Reader", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Writer", 1, 0));
|
||||
assertTrue(checkCounts(grandParentReport, "Multi", 1, 0));
|
||||
|
||||
CMISAccessControlReport parentReport = cmisAccessControlService.getAcl(parent, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(parentReport.isExtract());
|
||||
assertEquals(10, parentReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(parentReport, PermissionService.ADMINISTRATOR_AUTHORITY, 0, 1));
|
||||
assertTrue(checkCounts(parentReport, PermissionService.ALL_AUTHORITIES, 0, 1));
|
||||
assertTrue(checkAbsent(parentReport, "ToMask"));
|
||||
assertTrue(checkCounts(parentReport, "Full", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "Reader", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "Writer", 0, 1));
|
||||
assertTrue(checkCounts(parentReport, "SplitRead", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "SplitWrite", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "DuplicateRead", 1, 0));
|
||||
assertTrue(checkCounts(parentReport, "Multi", 1, 1));
|
||||
|
||||
CMISAccessControlReport childReport = cmisAccessControlService.getAcl(child, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(16, childReport.getAccessControlEntries().size());
|
||||
assertTrue(checkCounts(childReport, PermissionService.ADMINISTRATOR_AUTHORITY, 0, 1));
|
||||
assertTrue(checkCounts(childReport, PermissionService.ALL_AUTHORITIES, 0, 1));
|
||||
assertTrue(checkAbsent(childReport, "ToMask"));
|
||||
assertTrue(checkCounts(childReport, "Full", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "Reader", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "Writer", 0, 1));
|
||||
assertTrue(checkCounts(childReport, "SplitRead", 1, 1));
|
||||
assertTrue(checkCounts(childReport, "SplitWrite", 1, 1));
|
||||
assertTrue(checkCounts(childReport, "DuplicateRead", 1, 0));
|
||||
assertTrue(checkCounts(childReport, "Multi", 3, 2));
|
||||
assertTrue(checkCounts(childReport, "Writer2", 1, 0));
|
||||
}
|
||||
|
||||
private void createTestAcls()
|
||||
{
|
||||
grandParent = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Parent", namespaceService), ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(grandParent, ContentModel.PROP_NAME, "GrandParent");
|
||||
parent = nodeService.createNode(grandParent, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Child", namespaceService), ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(parent, ContentModel.PROP_NAME, "Parent");
|
||||
child = nodeService.createNode(parent, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Child", namespaceService), ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(child, ContentModel.PROP_NAME, "Child");
|
||||
permissionService.setPermission(grandParent, PermissionService.ADMINISTRATOR_AUTHORITY, PermissionService.ALL_PERMISSIONS, true);
|
||||
permissionService.setPermission(grandParent, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
|
||||
permissionService.setPermission(grandParent, "ToMask", PermissionService.READ, true);
|
||||
permissionService.setPermission(grandParent, "Full", PermissionService.FULL_CONTROL, true);
|
||||
permissionService.setPermission(grandParent, "Writer", PermissionService.WRITE, true);
|
||||
permissionService.setPermission(grandParent, "Reader", PermissionService.READ, true);
|
||||
permissionService.setPermission(grandParent, "Multi", PermissionService.DELETE, true);
|
||||
|
||||
permissionService.setPermission(parent, "ToMask", PermissionService.READ, false);
|
||||
permissionService.setPermission(parent, "SplitRead", PermissionService.READ_PROPERTIES, true);
|
||||
permissionService.setPermission(parent, "SplitWrite", PermissionService.WRITE_CONTENT, true);
|
||||
permissionService.setPermission(parent, "DuplicateRead", PermissionService.READ, true);
|
||||
permissionService.setPermission(parent, "Multi", PermissionService.CREATE_CHILDREN, true);
|
||||
|
||||
permissionService.setPermission(child, "SplitRead", PermissionService.READ_CONTENT, true);
|
||||
permissionService.setPermission(child, "Writer2", PermissionService.WRITE, true);
|
||||
permissionService.setPermission(child, "SplitWrite", PermissionService.WRITE_PROPERTIES, true);
|
||||
permissionService.setPermission(child, "DuplicateRead", PermissionService.READ, true);
|
||||
permissionService.setPermission(child, "Multi", PermissionService.READ, true);
|
||||
permissionService.setPermission(child, "Multi", PermissionService.WRITE, true);
|
||||
permissionService.setPermission(child, "Multi", PermissionService.SET_OWNER, true);
|
||||
|
||||
}
|
||||
|
||||
public void testAccessEntryOrdering()
|
||||
{
|
||||
createTestAcls();
|
||||
|
||||
Set<CMISPermissionDefinition> permDefs = new HashSet<CMISPermissionDefinition>();
|
||||
permDefs.addAll(cmisAccessControlService.getRepositoryPermissions());
|
||||
|
||||
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(child);
|
||||
ArrayList<AccessPermission> ordered = new ArrayList<AccessPermission>();
|
||||
AccessPermissionComparator comparator = new AccessPermissionComparator();
|
||||
for (AccessPermission current : permissions)
|
||||
{
|
||||
int index = Collections.binarySearch(ordered, current, comparator);
|
||||
if (index < 0)
|
||||
{
|
||||
ordered.add(-index - 1, current);
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Full", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals(PermissionService.ALL_AUTHORITIES, ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Multi", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals(PermissionService.ADMINISTRATOR_AUTHORITY, ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Reader", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("ToMask", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(4, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Writer", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(2, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.DENIED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("ToMask", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(2, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("DuplicateRead", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(2, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Multi", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(2, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("SplitRead", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(2, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("SplitWrite", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("DuplicateRead", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Multi", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Multi", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Multi", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("SplitRead", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("SplitWrite", ordered.get(i).getAuthority());
|
||||
|
||||
i++;
|
||||
assertEquals(0, ordered.get(i).getPosition());
|
||||
assertEquals(AccessStatus.ALLOWED, ordered.get(i).getAccessStatus());
|
||||
assertEquals("Writer2", ordered.get(i).getAuthority());
|
||||
}
|
||||
|
||||
public void testApplyAcl()
|
||||
{
|
||||
grandParent = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Parent", namespaceService), ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(grandParent, ContentModel.PROP_NAME, "GrandParent");
|
||||
parent = nodeService.createNode(grandParent, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Child", namespaceService), ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(parent, ContentModel.PROP_NAME, "Parent");
|
||||
child = nodeService.createNode(parent, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Child", namespaceService), ContentModel.TYPE_CONTENT).getChildRef();
|
||||
nodeService.setProperty(child, ContentModel.PROP_NAME, "Child");
|
||||
|
||||
List<CMISAccessControlEntry> acesToAdd = new ArrayList<CMISAccessControlEntry>();
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl(PermissionService.ADMINISTRATOR_AUTHORITY, PermissionService.ALL_PERMISSIONS));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl(PermissionService.ALL_AUTHORITIES, PermissionService.READ));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("ToMask", PermissionService.READ));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("Full", PermissionService.FULL_CONTROL));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("Writer", PermissionService.WRITE));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("Reader", PermissionService.READ));
|
||||
|
||||
CMISAccessControlReport grandParentReport = cmisAccessControlService.applyAcl(grandParent, null, acesToAdd, CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(6, grandParentReport.getAccessControlEntries().size());
|
||||
|
||||
List<CMISAccessControlEntry> acesToRemove = new ArrayList<CMISAccessControlEntry>();
|
||||
acesToRemove.add(new CMISAccessControlEntryImpl("ToMask", PermissionService.READ));
|
||||
|
||||
grandParentReport = cmisAccessControlService.applyAcl(grandParent, acesToRemove, null, CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(5, grandParentReport.getAccessControlEntries().size());
|
||||
|
||||
try
|
||||
{
|
||||
grandParentReport = cmisAccessControlService.applyAcl(grandParent, acesToRemove, null, CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
fail("A non existent ACE should not be removable");
|
||||
}
|
||||
catch (CMISConstraintException e)
|
||||
{
|
||||
|
||||
}
|
||||
acesToAdd = new ArrayList<CMISAccessControlEntry>();
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("SplitRead", permissionModelDao.getPermissionReference(null, PermissionService.READ_PROPERTIES).toString()));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("SplitWrite", permissionModelDao.getPermissionReference(null, PermissionService.WRITE_CONTENT).toString()));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("DuplicateRead", permissionModelDao.getPermissionReference(null, PermissionService.READ).toString()));
|
||||
|
||||
CMISAccessControlReport parentReport = cmisAccessControlService.applyAcl(parent, null, acesToAdd, CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(parentReport.isExtract());
|
||||
assertEquals(8, parentReport.getAccessControlEntries().size());
|
||||
|
||||
acesToAdd = new ArrayList<CMISAccessControlEntry>();
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("SplitRead", PermissionService.READ_CONTENT));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("Writer2", PermissionService.WRITE));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("SplitWrite", PermissionService.WRITE_PROPERTIES));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("DuplicateRead", PermissionService.READ));
|
||||
|
||||
CMISAccessControlReport childReport = cmisAccessControlService.applyAcl(child, null, acesToAdd, CMISAclPropagationEnum.PROPAGATE,
|
||||
CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(11, childReport.getAccessControlEntries().size());
|
||||
|
||||
grandParentReport = cmisAccessControlService.getAcl(grandParent, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(5, grandParentReport.getAccessControlEntries().size());
|
||||
|
||||
parentReport = cmisAccessControlService.getAcl(parent, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(parentReport.isExtract());
|
||||
assertEquals(8, parentReport.getAccessControlEntries().size());
|
||||
|
||||
childReport = cmisAccessControlService.getAcl(child, CMISAccessControlFormatEnum.CMIS_BASIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(9, childReport.getAccessControlEntries().size());
|
||||
|
||||
grandParentReport = cmisAccessControlService.getAcl(grandParent, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(grandParentReport.isExtract());
|
||||
assertEquals(5, grandParentReport.getAccessControlEntries().size());
|
||||
|
||||
parentReport = cmisAccessControlService.getAcl(parent, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(parentReport.isExtract());
|
||||
assertEquals(8, parentReport.getAccessControlEntries().size());
|
||||
|
||||
childReport = cmisAccessControlService.getAcl(child, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(11, childReport.getAccessControlEntries().size());
|
||||
|
||||
acesToAdd = new ArrayList<CMISAccessControlEntry>();
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("CMISReader", CMISAccessControlService.CMIS_READ_PERMISSION));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("CMISWriter", CMISAccessControlService.CMIS_WRITE_PERMISSION));
|
||||
acesToAdd.add(new CMISAccessControlEntryImpl("CMISAll", CMISAccessControlService.CMIS_ALL_PERMISSION));
|
||||
|
||||
childReport = cmisAccessControlService.applyAcl(child, null, acesToAdd, CMISAclPropagationEnum.PROPAGATE, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(14, childReport.getAccessControlEntries().size());
|
||||
|
||||
childReport = cmisAccessControlService.applyAcl(child, acesToAdd, acesToAdd, CMISAclPropagationEnum.PROPAGATE, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(14, childReport.getAccessControlEntries().size());
|
||||
|
||||
childReport = cmisAccessControlService.applyAcl(child, acesToAdd, null, CMISAclPropagationEnum.PROPAGATE, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
assertFalse(childReport.isExtract());
|
||||
assertEquals(11, childReport.getAccessControlEntries().size());
|
||||
|
||||
try
|
||||
{
|
||||
childReport = cmisAccessControlService.applyAcl(child, acesToAdd, null, CMISAclPropagationEnum.PROPAGATE, CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS);
|
||||
fail("A non existent ACE should not be removable");
|
||||
}
|
||||
catch (CMISConstraintException e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void testAllowableActionsAndPermissionMapping()
|
||||
{
|
||||
List<? extends CMISPermissionMapping> mappings = cmisAccessControlService.getPermissionMappings();
|
||||
assertEquals(29, mappings.size());
|
||||
assertTrue(contains(mappings, "canGetDescendants.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"));
|
||||
assertTrue(contains(mappings, "canGetFolderTree.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"));
|
||||
assertTrue(contains(mappings, "canGetChildren.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadChildren"));
|
||||
assertTrue(contains(mappings, "canGetFolderParent.Folder", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canGetObjectParents.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canCreateDocument.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"));
|
||||
assertTrue(contains(mappings, "canCreateFolder.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"));
|
||||
// "canCreateRelationship.Source"
|
||||
// "canCreateRelationship.Target"
|
||||
assertTrue(contains(mappings, "canGetProperties.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canGetRenditions.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canGetContentStream.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadContent"));
|
||||
assertTrue(contains(mappings, "canUpdateProperties.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.WriteProperties"));
|
||||
assertTrue(contains(mappings, "canMoveObject.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"));
|
||||
assertTrue(contains(mappings, "canMoveObject.Target", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"));
|
||||
// "canMoveObject.Source"
|
||||
assertTrue(contains(mappings, "canDelete.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"));
|
||||
// "canDelete.Folder"
|
||||
// === SPEC BUG - should really be those below ...
|
||||
// "canDeleteObject.Object"
|
||||
// "canDeleteObject.Folder"
|
||||
assertTrue(contains(mappings, "canSetContentStream.Document", CMISAccessControlService.CMIS_WRITE_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.WriteContent"));
|
||||
assertTrue(contains(mappings, "canDeleteContentStream.Document", CMISAccessControlService.CMIS_WRITE_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.WriteContent"));
|
||||
assertTrue(contains(mappings, "canDeleteTree.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"));
|
||||
assertTrue(contains(mappings, "canAddObjectToFolder.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canAddObjectToFolder.Folder", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.CreateChildren"));
|
||||
assertTrue(contains(mappings, "canRemoveObjectFromFolder.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.DeleteNode"));
|
||||
// "canRemoveObjectFromFolder.Folder"
|
||||
assertTrue(contains(mappings, "canCheckOut.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/content/1.0}lockable.CheckOut"));
|
||||
assertTrue(contains(mappings, "canCancelCheckOut.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/content/1.0}lockable.CancelCheckOut"));
|
||||
assertTrue(contains(mappings, "canCheckIn.Document", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/content/1.0}lockable.CheckIn"));
|
||||
assertTrue(contains(mappings, "canGetAllVersions.Document", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.Read"));
|
||||
// "canGetObjectRelationships.Object"
|
||||
assertTrue(contains(mappings, "canApplyPolicy.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.Write"));
|
||||
assertTrue(contains(mappings, "canApplyPolicy.Policy", CMISAccessControlService.CMIS_READ_PERMISSION));
|
||||
assertTrue(contains(mappings, "canRemovePolicy.Object", CMISAccessControlService.CMIS_WRITE_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.Write"));
|
||||
assertTrue(contains(mappings, "canRemovePolicy.Policy", CMISAccessControlService.CMIS_READ_PERMISSION));
|
||||
assertTrue(contains(mappings, "canGetAppliedPolicies.Object", CMISAccessControlService.CMIS_READ_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadProperties"));
|
||||
assertTrue(contains(mappings, "canGetACL.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ReadPermissions"));
|
||||
assertTrue(contains(mappings, "canApplyACL.Object", CMISAccessControlService.CMIS_ALL_PERMISSION, "{http://www.alfresco.org/model/system/1.0}base.ChangePermissions"));
|
||||
}
|
||||
|
||||
private boolean contains(List<? extends CMISPermissionMapping> mappings, String key, String... entries)
|
||||
{
|
||||
for (CMISPermissionMapping mapping : mappings)
|
||||
{
|
||||
if (mapping.getKey().equals(key))
|
||||
{
|
||||
// check entries are all valid
|
||||
Set<String> permissionNames = getAllPermissions();
|
||||
|
||||
for (String permission : mapping.getPermissions())
|
||||
{
|
||||
if (!permissionNames.contains(permission))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (entries.length > 0)
|
||||
{
|
||||
if (mapping.getPermissions().size() == entries.length)
|
||||
{
|
||||
for (String entry : entries)
|
||||
{
|
||||
if (!mapping.getPermissions().contains(entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import org.alfresco.cmis.EnumFactory;
|
||||
import org.alfresco.cmis.EnumLabel;
|
||||
|
||||
/**
|
||||
* Part two of the allowable action key for the permission mappings
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public enum CMISAllowedActionKeyTypeEnum implements EnumLabel
|
||||
{
|
||||
/**
|
||||
* Folder
|
||||
*/
|
||||
FOLDER("Folder"),
|
||||
/**
|
||||
* Object
|
||||
*/
|
||||
OBJECT("Object"),
|
||||
/**
|
||||
* Source
|
||||
*/
|
||||
SOURCE("Source"),
|
||||
/**
|
||||
* Target
|
||||
*/
|
||||
TARGET("Target"),
|
||||
/**
|
||||
* Document
|
||||
*/
|
||||
DOCUMENT("Document"),
|
||||
/**
|
||||
* Policy
|
||||
*/
|
||||
POLICY("Policy");
|
||||
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param label
|
||||
*/
|
||||
CMISAllowedActionKeyTypeEnum(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.EnumLabel#label()
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for CMISAclCapabilityEnum
|
||||
*/
|
||||
public static EnumFactory<CMISAllowedActionKeyTypeEnum> FACTORY = new EnumFactory<CMISAllowedActionKeyTypeEnum>(CMISAllowedActionKeyTypeEnum.class, null, true);
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import org.alfresco.cmis.CMISPermissionDefinition;
|
||||
|
||||
/**
|
||||
* Implementation class for a simple CMIS permission definition.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISPermissionDefinitionImpl implements CMISPermissionDefinition
|
||||
{
|
||||
private String permission;
|
||||
|
||||
private String description;
|
||||
|
||||
/*package*/ CMISPermissionDefinitionImpl(String permission)
|
||||
{
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/*package*/ CMISPermissionDefinitionImpl(String permission, String description)
|
||||
{
|
||||
this(permission);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISPermissionDefinition#getDescription()
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
if(description != null)
|
||||
{
|
||||
return description;
|
||||
}
|
||||
else
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISPermissionDefinition#getPermission()
|
||||
*/
|
||||
public String getPermission()
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((permission == null) ? 0 : permission.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final CMISPermissionDefinitionImpl other = (CMISPermissionDefinitionImpl) obj;
|
||||
if (permission == null)
|
||||
{
|
||||
if (other.permission != null)
|
||||
return false;
|
||||
}
|
||||
else if (!permission.equals(other.permission))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.cmis.CMISPermissionMapping;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CMISPermissionMappingImpl implements CMISPermissionMapping
|
||||
{
|
||||
String key;
|
||||
|
||||
List<String> permissions;
|
||||
|
||||
CMISPermissionMappingImpl(String key, List<String> permissions)
|
||||
{
|
||||
this.key = key;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISPermissionMapping#getKey()
|
||||
*/
|
||||
public String getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISPermissionMapping#getPermissions()
|
||||
*/
|
||||
public List<String> getPermissions()
|
||||
{
|
||||
return permissions;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.acl;
|
||||
|
||||
import org.alfresco.cmis.CMISAllowedActionEnum;
|
||||
|
||||
/**
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface CMISPermissionMappingKey
|
||||
{
|
||||
/**
|
||||
* Get the allowed action enum.
|
||||
* @return the allowed action enum.
|
||||
*/
|
||||
public CMISAllowedActionEnum getAllowedActionEnum();
|
||||
|
||||
/**
|
||||
* Get the allowed action key type enum.
|
||||
* @return the allowed action key type enum.
|
||||
*/
|
||||
public CMISAllowedActionKeyTypeEnum getAllowedActionKeyTypeEnum();
|
||||
}
|
111
source/java/org/alfresco/cmis/changelog/CMISChangeEventImpl.java
Executable file
111
source/java/org/alfresco/cmis/changelog/CMISChangeEventImpl.java
Executable file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.changelog;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.alfresco.cmis.CMISChangeEvent;
|
||||
import org.alfresco.cmis.CMISChangeType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* CMISChangeEvent Implementation
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public class CMISChangeEventImpl implements CMISChangeEvent
|
||||
{
|
||||
private NodeRef node;
|
||||
private CMISChangeType changeType;
|
||||
private Date changeTime;
|
||||
|
||||
/**
|
||||
* Construct a CMISChangeEvent using fields
|
||||
*
|
||||
* @param changeType change type
|
||||
* @param node node reference
|
||||
* @param changeTime change time
|
||||
*/
|
||||
public CMISChangeEventImpl(CMISChangeType changeType, NodeRef node, Date changeTime)
|
||||
{
|
||||
this.changeType = changeType;
|
||||
this.node = node;
|
||||
this.changeTime = changeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeEvent#getChangeType()
|
||||
*/
|
||||
public CMISChangeType getChangeType()
|
||||
{
|
||||
return changeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeEvent#getNode()
|
||||
*/
|
||||
public NodeRef getNode()
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeEvent#getChangeTime()
|
||||
*/
|
||||
public Date getChangeTime()
|
||||
{
|
||||
return changeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (!(obj instanceof CMISChangeEvent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
CMISChangeEvent converted = (CMISChangeEvent) obj;
|
||||
return same(node, converted.getNode()) && same(changeType, converted.getChangeType()) && same(changeTime, converted.getChangeTime());
|
||||
}
|
||||
|
||||
private boolean same(Object left, Object right)
|
||||
{
|
||||
return (null == left) ? (null == right) : (left.equals(right));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = (null != node) ? (node.hashCode()) : (31);
|
||||
return result * 37 + (null != changeType ? changeType.hashCode() : 31) + (null != changeTime ? changeTime.hashCode() : 31);
|
||||
}
|
||||
|
||||
}
|
126
source/java/org/alfresco/cmis/changelog/CMISChangeLogDataExtractor.java
Executable file
126
source/java/org/alfresco/cmis/changelog/CMISChangeLogDataExtractor.java
Executable file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing
|
||||
*/
|
||||
package org.alfresco.cmis.changelog;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.repo.audit.extractor.AbstractDataExtractor;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* An extractor that allows to filter data using the following rule:
|
||||
* Audit records should only be created for items in the CMIS domain model.
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public class CMISChangeLogDataExtractor extends AbstractDataExtractor
|
||||
{
|
||||
private CMISServices cmisService;
|
||||
private FileFolderService fileFolderService;
|
||||
|
||||
/**
|
||||
* Extracts the NodeRef from auditing data
|
||||
*
|
||||
* @see org.alfresco.repo.audit.extractor.DataExtractor.extractData(java.io.Serializable)
|
||||
*/
|
||||
public Serializable extractData(Serializable value) throws Throwable
|
||||
{
|
||||
return getNodeRef(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns <tt>true</tt> if items in the CMIS domain model
|
||||
* @see org.alfresco.repo.audit.extractor.DataExtractor.isSupported(java.io.Serializable)
|
||||
*/
|
||||
public boolean isSupported(Serializable data)
|
||||
{
|
||||
boolean result = false;
|
||||
if (data != null)
|
||||
{
|
||||
NodeRef nodeRef = getNodeRef(data);
|
||||
if (nodeRef != null)
|
||||
{
|
||||
if (!fileFolderService.exists(nodeRef))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
// Does the node represent a file or folder
|
||||
else if (fileFolderService.getFileInfo(nodeRef) != null)
|
||||
{
|
||||
// Is the node located within CMIS defaultRootStore
|
||||
if (cmisService.getDefaultRootStoreRef().equals(nodeRef.getStoreRef()))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the NodeRef from auditing data
|
||||
*
|
||||
* @param data audit data
|
||||
* @return Node Reference
|
||||
*/
|
||||
private NodeRef getNodeRef(Serializable data)
|
||||
{
|
||||
NodeRef nodeRef = null;
|
||||
if (data instanceof FileInfo)
|
||||
{
|
||||
nodeRef = ((FileInfo) data).getNodeRef();
|
||||
}
|
||||
else if (data instanceof NodeRef)
|
||||
{
|
||||
nodeRef = (NodeRef) data;
|
||||
}
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CMIS service
|
||||
*
|
||||
* @param cmisService CMIS service
|
||||
*/
|
||||
public void setCmisService(CMISServices cmisService)
|
||||
{
|
||||
this.cmisService = cmisService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the FileFolder service
|
||||
*
|
||||
* @param fileFolderService FileFolder service
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
}
|
106
source/java/org/alfresco/cmis/changelog/CMISChangeLogImpl.java
Executable file
106
source/java/org/alfresco/cmis/changelog/CMISChangeLogImpl.java
Executable file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.changelog;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.cmis.CMISChangeEvent;
|
||||
import org.alfresco.cmis.CMISChangeLog;
|
||||
|
||||
/**
|
||||
* CMISChangeLog Implementation
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public class CMISChangeLogImpl implements CMISChangeLog
|
||||
{
|
||||
private boolean hasMoreItems;
|
||||
private List<CMISChangeEvent> changeEvents = new LinkedList<CMISChangeEvent>();
|
||||
private String nextChangeToken;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLog#getChangeEvents()
|
||||
*/
|
||||
public List<CMISChangeEvent> getChangeEvents()
|
||||
{
|
||||
return changeEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the change events
|
||||
*
|
||||
* @param changeEvents list of change events
|
||||
*/
|
||||
protected void setChangeEvents(List<CMISChangeEvent> changeEvents)
|
||||
{
|
||||
this.changeEvents = changeEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLog#getEventCount()
|
||||
*/
|
||||
public Integer getEventCount()
|
||||
{
|
||||
return changeEvents.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLog#getNextChangeToken()
|
||||
*/
|
||||
public String getNextChangeToken()
|
||||
{
|
||||
return nextChangeToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the next ChangeToken
|
||||
*
|
||||
* @param nextChangeToken the next ChangeToken
|
||||
*/
|
||||
public void setNextChangeToken(String nextChangeToken)
|
||||
{
|
||||
this.nextChangeToken = nextChangeToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLog#hasMoreItems()
|
||||
*/
|
||||
public boolean hasMoreItems()
|
||||
{
|
||||
return hasMoreItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hasMoreItems value
|
||||
*
|
||||
* @param hasMoreItems hasMoreItems value
|
||||
*/
|
||||
protected void setHasMoreItems(boolean hasMoreItems)
|
||||
{
|
||||
this.hasMoreItems = hasMoreItems;
|
||||
}
|
||||
|
||||
}
|
338
source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceImpl.java
Executable file
338
source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceImpl.java
Executable file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.changelog;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.cmis.CMISBaseObjectTypeIds;
|
||||
import org.alfresco.cmis.CMISCapabilityChanges;
|
||||
import org.alfresco.cmis.CMISChangeEvent;
|
||||
import org.alfresco.cmis.CMISChangeLog;
|
||||
import org.alfresco.cmis.CMISChangeLogService;
|
||||
import org.alfresco.cmis.CMISChangeType;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.audit.AuditQueryParameters;
|
||||
import org.alfresco.service.cmr.audit.AuditService;
|
||||
import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* ChangeLog Service Implementation
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public class CMISChangeLogServiceImpl implements CMISChangeLogService
|
||||
{
|
||||
private AuditService auditService;
|
||||
private String cmisAuditApplicationName;
|
||||
private List<CMISBaseObjectTypeIds> changesOnTypeCapability;
|
||||
|
||||
private static final String PATH_DELIMITER = "/";
|
||||
private static final int DEFAULT_RETURN_SIZE = 100;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getCapability()
|
||||
*/
|
||||
public CMISCapabilityChanges getCapability()
|
||||
{
|
||||
return (auditService.isAuditEnabled(cmisAuditApplicationName, PATH_DELIMITER + cmisAuditApplicationName)) ? (CMISCapabilityChanges.OBJECTIDSONLY)
|
||||
: (CMISCapabilityChanges.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getChangeLogEvents(java.lang.String, java.lang.Integer)
|
||||
*/
|
||||
public CMISChangeLog getChangeLogEvents(String changeLogToken, Integer maxItems)
|
||||
{
|
||||
if (!auditService.isAuditEnabled(cmisAuditApplicationName, ("/" + cmisAuditApplicationName)))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Auditing for " + cmisAuditApplicationName + " is disabled!");
|
||||
}
|
||||
CMISChangeLogImpl result = new CMISChangeLogImpl();
|
||||
final List<CMISChangeEvent> changeEvents = result.getChangeEvents();
|
||||
EntryIdCallback changeLogCollectingCallback = new EntryIdCallback(true)
|
||||
{
|
||||
@Override
|
||||
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
||||
{
|
||||
List<CMISChangeEvent> changeLogEvents = convertValuesMapToChangeLogEvents(values, time);
|
||||
changeEvents.addAll(changeLogEvents);
|
||||
return super.handleAuditEntry(entryId, user, time, values);
|
||||
}
|
||||
};
|
||||
Long from = changeLogToken != null ? Long.parseLong(changeLogToken) : null;
|
||||
AuditQueryParameters params = new AuditQueryParameters();
|
||||
params.setApplicationName(cmisAuditApplicationName);
|
||||
params.setForward(true);
|
||||
params.setFromId(from);
|
||||
|
||||
// Query one past the last item, so that we know what the next ID is
|
||||
int maxAmount = ((null == maxItems) || (0 == maxItems)) ? (0) : (maxItems + 1);
|
||||
auditService.auditQuery(changeLogCollectingCallback, params, maxAmount);
|
||||
|
||||
if ((0 != maxAmount) && (changeEvents.size() > maxItems))
|
||||
{
|
||||
changeEvents.remove(changeEvents.size() - 1);
|
||||
result.setNextChangeToken(changeLogCollectingCallback.getEntryId().toString());
|
||||
result.setHasMoreItems(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getChangesIncomplete()
|
||||
*/
|
||||
public boolean getChangesIncomplete()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getLastChangeLogToken()
|
||||
*/
|
||||
public String getLastChangeLogToken()
|
||||
{
|
||||
EntryIdCallback auditQueryCallback = new EntryIdCallback(false);
|
||||
AuditQueryParameters params = new AuditQueryParameters();
|
||||
params.setApplicationName(cmisAuditApplicationName);
|
||||
params.setForward(false);
|
||||
auditService.auditQuery(auditQueryCallback, params, 1);
|
||||
return auditQueryCallback.getEntryId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getPreviousPageChangeLogToken(java.lang.String, java.lang.Integer)
|
||||
*/
|
||||
public String getPreviousPageChangeLogToken(String currentPageToken, Integer maxItems)
|
||||
{
|
||||
if (currentPageToken == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
maxItems = maxItems == null ? DEFAULT_RETURN_SIZE : maxItems;
|
||||
EntryIdCallback auditQueryCallback = new EntryIdCallback(false);
|
||||
AuditQueryParameters params = new AuditQueryParameters();
|
||||
params.setApplicationName(cmisAuditApplicationName);
|
||||
params.setForward(false);
|
||||
params.setToId(Long.parseLong(currentPageToken));
|
||||
auditService.auditQuery(auditQueryCallback, params, maxItems);
|
||||
return auditQueryCallback.getEntryId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getLastPageChangeLogToken(java.lang.String, java.lang.Integer)
|
||||
*/
|
||||
public String getLastPageChangeLogToken(String currentPageToken, Integer maxItems)
|
||||
{
|
||||
maxItems = maxItems == null ? DEFAULT_RETURN_SIZE : maxItems;
|
||||
EntryIdCallback auditQueryCallback = new PageStartEntryIdCallback(maxItems);
|
||||
AuditQueryParameters params = new AuditQueryParameters();
|
||||
params.setApplicationName(cmisAuditApplicationName);
|
||||
if (currentPageToken != null)
|
||||
{
|
||||
params.setFromId(Long.parseLong(currentPageToken));
|
||||
}
|
||||
auditService.auditQuery(auditQueryCallback, params, -1);
|
||||
return auditQueryCallback.getEntryId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISChangeLogService#getChangesOnTypeCapability()
|
||||
*/
|
||||
public List<CMISBaseObjectTypeIds> getChangesOnTypeCapability()
|
||||
{
|
||||
if (null == changesOnTypeCapability)
|
||||
{
|
||||
changesOnTypeCapability = new LinkedList<CMISBaseObjectTypeIds>();
|
||||
}
|
||||
return changesOnTypeCapability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the AuditService.
|
||||
*
|
||||
* @param auditService AuditService
|
||||
*/
|
||||
public void setAuditService(AuditService auditService)
|
||||
{
|
||||
this.auditService = auditService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Audit Application Name.
|
||||
*
|
||||
* @param cmisAuditApplicationName Audit Application Name
|
||||
*/
|
||||
public void setCmisAuditApplicationName(String cmisAuditApplicationName)
|
||||
{
|
||||
this.cmisAuditApplicationName = cmisAuditApplicationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ChangesOnTypeCapability.
|
||||
*
|
||||
* @param changesOnTypeCapability list of CMISBaseObjectTypeIds
|
||||
*/
|
||||
public void setChangesOnTypeCapability(List<CMISBaseObjectTypeIds> changesOnTypeCapability)
|
||||
{
|
||||
this.changesOnTypeCapability = changesOnTypeCapability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts audit values map to list of CMISChangeEvents.
|
||||
*
|
||||
* @param values audit values map
|
||||
* @param time audit event time
|
||||
* @return list of CMISChangeEvent
|
||||
*/
|
||||
private List<CMISChangeEvent> convertValuesMapToChangeLogEvents(Map<String, Serializable> values, long time)
|
||||
{
|
||||
List<CMISChangeEvent> result = new ArrayList<CMISChangeEvent>();
|
||||
if (values != null && values.size() > 0)
|
||||
{
|
||||
for (Entry<String, Serializable> entry : values.entrySet())
|
||||
{
|
||||
if (entry.getKey() != null && entry.getValue() != null)
|
||||
{
|
||||
String path = entry.getKey();
|
||||
CMISChangeType changeType = getCMISChangeType(path);
|
||||
NodeRef nodeRef = entry.getValue() instanceof NodeRef ? (NodeRef) entry.getValue() : null;
|
||||
if (changeType != null && nodeRef != null)
|
||||
{
|
||||
result.add(new CMISChangeEventImpl(changeType, nodeRef, new Date(time)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets CMISChangeType by audit path.
|
||||
*
|
||||
* @param auditPath audit path
|
||||
* @return CMISChangeType
|
||||
*/
|
||||
private CMISChangeType getCMISChangeType(String auditPath)
|
||||
{
|
||||
CMISChangeType result = null;
|
||||
if (auditPath != null)
|
||||
{
|
||||
if (auditPath.startsWith(PATH_DELIMITER))
|
||||
{
|
||||
auditPath = auditPath.substring(PATH_DELIMITER.length());
|
||||
}
|
||||
if (auditPath.startsWith(cmisAuditApplicationName))
|
||||
{
|
||||
auditPath = auditPath.substring(cmisAuditApplicationName.length());
|
||||
}
|
||||
if (auditPath.startsWith(PATH_DELIMITER))
|
||||
{
|
||||
auditPath = auditPath.substring(PATH_DELIMITER.length());
|
||||
}
|
||||
auditPath = auditPath.toLowerCase();
|
||||
for (CMISChangeType changeType : CMISChangeType.values())
|
||||
{
|
||||
if (auditPath.startsWith(changeType.getLabel()))
|
||||
{
|
||||
result = changeType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private class EntryIdCallback implements AuditQueryCallback
|
||||
{
|
||||
private final boolean valuesRequired;
|
||||
private Long entryId;
|
||||
|
||||
public EntryIdCallback(boolean valuesRequired)
|
||||
{
|
||||
this.valuesRequired = valuesRequired;
|
||||
}
|
||||
|
||||
public String getEntryId()
|
||||
{
|
||||
return entryId == null ? null : entryId.toString();
|
||||
}
|
||||
|
||||
public boolean valuesRequired()
|
||||
{
|
||||
return this.valuesRequired;
|
||||
}
|
||||
|
||||
public final boolean handleAuditEntry(Long entryId, String applicationName, String user, long time, Map<String, Serializable> values)
|
||||
{
|
||||
if (applicationName.equals(CMISChangeLogServiceImpl.this.cmisAuditApplicationName))
|
||||
{
|
||||
return handleAuditEntry(entryId, user, time, values);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
||||
{
|
||||
this.entryId = entryId;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
|
||||
{
|
||||
throw new AlfrescoRuntimeException(errorMsg, error);
|
||||
}
|
||||
};
|
||||
|
||||
private class PageStartEntryIdCallback extends EntryIdCallback
|
||||
{
|
||||
private final int pageSize;
|
||||
private int indexWithinPage;
|
||||
|
||||
public PageStartEntryIdCallback(int pageSize)
|
||||
{
|
||||
super(false);
|
||||
this.pageSize = pageSize;
|
||||
this.indexWithinPage = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
||||
{
|
||||
if (++this.indexWithinPage == this.pageSize)
|
||||
{
|
||||
this.indexWithinPage = 0;
|
||||
return super.handleAuditEntry(entryId, user, time, values);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
419
source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java
Executable file
419
source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java
Executable file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.changelog;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.cmis.CMISCapabilityChanges;
|
||||
import org.alfresco.cmis.CMISChangeEvent;
|
||||
import org.alfresco.cmis.CMISChangeLog;
|
||||
import org.alfresco.cmis.CMISChangeLogService;
|
||||
import org.alfresco.cmis.CMISChangeType;
|
||||
import org.alfresco.cmis.mapping.BaseCMISTest;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.extensions.surf.util.Pair;
|
||||
|
||||
/**
|
||||
* Base tests for {@link CMISChangeLogServiceImpl}
|
||||
*
|
||||
* @author Dmitry Velichkevich
|
||||
*/
|
||||
public class CMISChangeLogServiceTest extends BaseCMISTest
|
||||
{
|
||||
private static final String CMIS_AUTHORITY = "cmis";
|
||||
private static final String CHANGE_PREFIX = "Changed";
|
||||
private static final String INVALID_CHANGE_TOKEN = "<Invalid Change Token>";
|
||||
private static final String[] NAME_PARTS = new String[] { "TestDocument (", ").txt", "TestFolder (", ")" };
|
||||
|
||||
private static int TOTAL_AMOUNT = 31;
|
||||
private static int CREATED_AMOUNT = 18;
|
||||
private static final int THE_HALFT_OF_CREATED_AMOUNT = CREATED_AMOUNT / 2;
|
||||
private static final Map<CMISChangeType, Integer> EXPECTED_AMOUNTS = new HashMap<CMISChangeType, Integer>();
|
||||
static
|
||||
{
|
||||
EXPECTED_AMOUNTS.put(CMISChangeType.CREATED, 5);
|
||||
EXPECTED_AMOUNTS.put(CMISChangeType.DELETED, 3);
|
||||
EXPECTED_AMOUNTS.put(CMISChangeType.SECURITY, 4);
|
||||
EXPECTED_AMOUNTS.put(CMISChangeType.UPDATED, 6);
|
||||
}
|
||||
|
||||
private ApplicationContextFactory auditSubsystem;
|
||||
private CMISChangeLogService changeLogService;
|
||||
|
||||
private int actualCount = 0;
|
||||
private Map<CMISChangeType, Integer> actualAmounts = new HashMap<CMISChangeType, Integer>();
|
||||
private List<NodeRef> created = null;
|
||||
private List<NodeRef> deleted = null;
|
||||
|
||||
private void disableAudit()
|
||||
{
|
||||
auditSubsystem.stop();
|
||||
auditSubsystem.setProperty("audit.enabled", "true");
|
||||
auditSubsystem.setProperty("audit.cmis.enabled", "false");
|
||||
}
|
||||
|
||||
private void enableAudit()
|
||||
{
|
||||
auditSubsystem.stop();
|
||||
auditSubsystem.setProperty("audit.enabled", "true");
|
||||
auditSubsystem.setProperty("audit.cmis.enabled", "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link CMISChangeLogServiceImpl} with disabled Auditing feature
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testServiceWithDisabledAuditing() throws Exception
|
||||
{
|
||||
disableAudit();
|
||||
String lastChangeLogToken = changeLogService.getLastChangeLogToken();
|
||||
createTestData(EXPECTED_AMOUNTS, false);
|
||||
assertEquals(CMISCapabilityChanges.NONE, changeLogService.getCapability());
|
||||
try
|
||||
{
|
||||
changeLogService.getChangeLogEvents(lastChangeLogToken, null);
|
||||
fail("Changes Logging was not enabled but no one Change Log Service method thrown exception");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assertTrue("Invalid exception type from Change Log Service method call with desabled Changes Logging", e instanceof AlfrescoRuntimeException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link CMISChangeLogServiceImpl} with enabled Auditing feature
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testEnabledAuditing() throws Exception
|
||||
{
|
||||
enableAudit();
|
||||
String logToken = changeLogService.getLastChangeLogToken();
|
||||
createTestData(EXPECTED_AMOUNTS, false);
|
||||
assertEquals(CMISCapabilityChanges.OBJECTIDSONLY, changeLogService.getCapability());
|
||||
CMISChangeLog changeLog = changeLogService.getChangeLogEvents(logToken, null);
|
||||
assertChangeLog(logToken, changeLog);
|
||||
assertChangeEvents(logToken, changeLog, null, FoldersAppearing.NOT_EXPECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates Change Log descriptor that was returned for some Change Log Token
|
||||
*
|
||||
* @param logToken {@link String} value that represents last Change Log Token
|
||||
* @param changeLog {@link CMISChangeLog} instance that represents Change Log descriptor
|
||||
*/
|
||||
private void assertChangeLog(String logToken, CMISChangeLog changeLog)
|
||||
{
|
||||
assertNotNull(("'" + logToken + "' Change Log Token has no descriptor"), changeLog);
|
||||
assertNotNull(("Event Etries for '" + logToken + "' Change Log Token are undefined"), changeLog.getChangeEvents());
|
||||
assertFalse(("Descriptor for '" + logToken + "' Change Log Token has no any Event Entry"), changeLog.getChangeEvents().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates test data which will represent Change Events of all possible types
|
||||
*
|
||||
* @param requiredAmounts {@link Map}<{@link CMISChangeType}, {@link Integer}> container instance that determines amount of Change Event for each Change Type
|
||||
* @return pair containing list of created node refs, and list of deleted node refs
|
||||
* @see CMISChangeType
|
||||
*/
|
||||
private Pair<List<NodeRef>, List<NodeRef>> createTestData(Map<CMISChangeType, Integer> requiredAmounts, boolean withFolders)
|
||||
{
|
||||
changeLogService.getLastChangeLogToken();
|
||||
created = new LinkedList<NodeRef>();
|
||||
deleted = new LinkedList<NodeRef>();
|
||||
Pair<List<NodeRef>, List<NodeRef>> result = new Pair<List<NodeRef>, List<NodeRef>>(created, deleted);
|
||||
NodeRef parentNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
SecureRandom randomizer = new SecureRandom();
|
||||
for (CMISChangeType key : requiredAmounts.keySet())
|
||||
{
|
||||
Integer amount = requiredAmounts.get(key);
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
boolean folder = withFolders && (0 == ((Math.abs(randomizer.nextInt()) % amount) % 2));
|
||||
QName objectType = (folder) ? (ContentModel.TYPE_FOLDER) : (ContentModel.TYPE_CONTENT);
|
||||
FileInfo object = fileFolderService.create(parentNodeRef, generateName(randomizer, folder), objectType);
|
||||
created.add(object.getNodeRef());
|
||||
addOneToAmount(actualAmounts, CMISChangeType.CREATED);
|
||||
switch (key)
|
||||
{
|
||||
case DELETED:
|
||||
{
|
||||
nodeService.deleteNode(object.getNodeRef());
|
||||
deleted.add(object.getNodeRef());
|
||||
addOneToAmount(actualAmounts, CMISChangeType.DELETED);
|
||||
break;
|
||||
}
|
||||
case SECURITY:
|
||||
{
|
||||
permissionService.setPermission(object.getNodeRef(), CMIS_AUTHORITY, PermissionService.EXECUTE_CONTENT, true);
|
||||
addOneToAmount(actualAmounts, CMISChangeType.SECURITY);
|
||||
break;
|
||||
}
|
||||
case UPDATED:
|
||||
{
|
||||
StringBuilder nameBuilder = new StringBuilder(CHANGE_PREFIX);
|
||||
nameBuilder.append(nodeService.getProperty(object.getNodeRef(), ContentModel.PROP_NAME));
|
||||
nodeService.setProperty(object.getNodeRef(), ContentModel.PROP_NAME, nameBuilder.toString());
|
||||
addOneToAmount(actualAmounts, CMISChangeType.UPDATED);
|
||||
}
|
||||
}
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes each element of created test data if element exist and current user has appropriate rights
|
||||
*
|
||||
* @param testData {@link Map}<{@link NodeRef}, {@link Map}<{@link QName}, {@link Serializable}>> container instance that contains test data
|
||||
*/
|
||||
private void deleteTestData()
|
||||
{
|
||||
if (created != null)
|
||||
{
|
||||
for (NodeRef object : created)
|
||||
{
|
||||
if (nodeService.exists(object) && (AccessStatus.ALLOWED == permissionService.hasPermission(object, PermissionService.DELETE)))
|
||||
{
|
||||
nodeService.deleteNode(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param folder {@link Boolean} value that determines which name should be generated (for Folder or Document Object)
|
||||
* @return {@link String} value that represents generated uniquely name for Document Object
|
||||
*/
|
||||
private String generateName(SecureRandom randomizer, boolean folder)
|
||||
{
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
int i = (folder) ? (2) : (0);
|
||||
nameBuilder.append(NAME_PARTS[i++]).append(Math.abs(randomizer.nextInt())).append(NAME_PARTS[i++]);
|
||||
return nameBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method validates Change Event entries according to created earlier Objects. According to <b>assertProperties</b> parameter this method may and may not check properties
|
||||
* of Change Event entry according to appropriate expected Object against Change Type
|
||||
*
|
||||
* @param expectedObjects {@link Map}<{@link NodeRef}, {@link Map}<{@link QName}, {@link Serializable}>> container instance that contains Ids and properties of
|
||||
* expected Objects
|
||||
* @param logToken {@link String} value that represents last Change Log Token
|
||||
* @param changeLog {@link CMISChangeLog} instance that represents Change Log descriptor for last Change Log Token
|
||||
* @param maxItems {@link Integer} value that determines high bound of Change Events amount
|
||||
* @see CMISChangeType
|
||||
*/
|
||||
private void assertChangeEvents(String logToken, CMISChangeLog changeLog, Integer maxItems, FoldersAppearing foldersAppearing)
|
||||
{
|
||||
Map<CMISChangeType, Integer> logAmounts = new HashMap<CMISChangeType, Integer>();
|
||||
boolean folderWasFound = false;
|
||||
for (CMISChangeEvent event : changeLog.getChangeEvents())
|
||||
{
|
||||
assertNotNull(("One of the Change Log Event Enries is undefined for '" + logToken + "' Change Log Token"), event);
|
||||
assertNotNull(("Change Event Entry Id of one of the Change Entries is undefined for '" + logToken + "' Change Log Token"), event.getNode());
|
||||
assertNotNull(("Change Event Change Type of one of the Change Entries is undefined for '" + logToken + "' Change Log Token"), event.getChangeType());
|
||||
assertTrue("Unexpected Object Id='" + event.getNode().toString() + "' from Change Log Token Entries list for '" + logToken + "' Change Log Token", created
|
||||
.contains(event.getNode()));
|
||||
if (!deleted.contains(event.getNode()))
|
||||
{
|
||||
folderWasFound = folderWasFound || fileFolderService.getFileInfo(event.getNode()).isFolder();
|
||||
assertTrue(
|
||||
("Object from Change Event Entries list is marked as '" + event.getChangeType().toString() + "' but does not exist for '" + logToken + "' Change Log Token"),
|
||||
nodeService.exists(event.getNode()));
|
||||
}
|
||||
else
|
||||
{
|
||||
assertTrue("Object has been deleted", deleted.contains(event.getNode()));
|
||||
assertFalse(("Object from Change Event Entries list is marked as 'DELETED' but it still exist for '" + logToken + "' Change Log Token"), nodeService.exists(event
|
||||
.getNode()));
|
||||
}
|
||||
addOneToAmount(logAmounts, event.getChangeType());
|
||||
}
|
||||
if (FoldersAppearing.MUST_APPEAR == foldersAppearing)
|
||||
{
|
||||
assertTrue("No one Folder Object was returned", folderWasFound);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FoldersAppearing.NOT_EXPECTED == foldersAppearing)
|
||||
{
|
||||
assertFalse("Some Folder Object was found", folderWasFound);
|
||||
}
|
||||
}
|
||||
if ((null == maxItems) || (maxItems >= TOTAL_AMOUNT))
|
||||
{
|
||||
for (CMISChangeType key : actualAmounts.keySet())
|
||||
{
|
||||
Integer actualAmount = actualAmounts.get(key);
|
||||
Integer logAmount = logAmounts.get(key);
|
||||
assertTrue(("Invalid Entries amount for '" + key.toString() + "' Change Type. Actual amount: " + actualAmount + ", but log amount: " + logAmount), actualAmount
|
||||
.equals(logAmount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum FoldersAppearing
|
||||
{
|
||||
NOT_EXPECTED, MAY_APPEAR, MUST_APPEAR
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which kind of Change was handled and increments appropriate amount to 1
|
||||
*
|
||||
* @param mappedAmounts {@link Map}>{@link CMISChangeType}, {@link Integer}< container instance that contains all accumulated amounts for each kind of Change
|
||||
* @param changeType {@link CMISChangeType} enum value that determines kind of Change
|
||||
*/
|
||||
private void addOneToAmount(Map<CMISChangeType, Integer> mappedAmounts, CMISChangeType changeType)
|
||||
{
|
||||
Integer amount = mappedAmounts.get(changeType);
|
||||
amount = (null == amount) ? (Integer.valueOf(1)) : (Integer.valueOf(amount.intValue() + 1));
|
||||
mappedAmounts.put(changeType, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link CMISChangeLogServiceImpl} with enabled Auditing feature for Max Items parameter
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testEnabledAuditingForMaxItems() throws Exception
|
||||
{
|
||||
enableAudit();
|
||||
String logToken = changeLogService.getLastChangeLogToken();
|
||||
createTestData(EXPECTED_AMOUNTS, false);
|
||||
assertEquals(CMISCapabilityChanges.OBJECTIDSONLY, changeLogService.getCapability());
|
||||
CMISChangeLog changeLog = changeLogService.getChangeLogEvents(logToken, THE_HALFT_OF_CREATED_AMOUNT);
|
||||
assertChangeLog(logToken, changeLog);
|
||||
assertChangeEvents(logToken, changeLog, THE_HALFT_OF_CREATED_AMOUNT, FoldersAppearing.NOT_EXPECTED);
|
||||
assertEquals(THE_HALFT_OF_CREATED_AMOUNT, changeLog.getChangeEvents().size());
|
||||
assertTrue("Not all Change Log Entries were requested but result set is indicating that no one more Entry is avilable", changeLog.hasMoreItems());
|
||||
changeLog = changeLogService.getChangeLogEvents(logToken, TOTAL_AMOUNT);
|
||||
assertChangeEvents(logToken, changeLog, TOTAL_AMOUNT, FoldersAppearing.NOT_EXPECTED);
|
||||
assertFalse("All Change Log Entries were requested but result set is indicating that some more Entry(s) are available", changeLog.hasMoreItems());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tests {@link CMISChangeLogServiceImpl} on receiving Change Event Entries for Invalid Change Log Token with enable and disabled Changes Logging
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testReceivingChangeEventsForInvalidChangeToken() throws Exception
|
||||
{
|
||||
enableAudit();
|
||||
try
|
||||
{
|
||||
changeLogService.getChangeLogEvents(INVALID_CHANGE_TOKEN, null);
|
||||
fail("Change Events were received normally for Invalid Change Log Token");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assertTrue("Invalid exception type from Change Log Service method call with enabled Changes Logging", e instanceof java.lang.NumberFormatException);
|
||||
}
|
||||
disableAudit();
|
||||
try
|
||||
{
|
||||
changeLogService.getChangeLogEvents(INVALID_CHANGE_TOKEN, null);
|
||||
fail("Changes Logging was not enabled but not one Change Log Service method thrown exception");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assertTrue("Invalid exception type from Change Log Service method call with desabled Changes Logging", e instanceof AlfrescoRuntimeException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tests {@link CMISChangeLogServiceImpl} on working with Change Event entries which could contain Folder Objects
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testReceivingOfChangeEventsExpectingFolders() throws Exception
|
||||
{
|
||||
enableAudit();
|
||||
String changeToken = changeLogService.getLastChangeLogToken();
|
||||
createTestData(EXPECTED_AMOUNTS, true);
|
||||
CMISChangeLog changeLogEvents = changeLogService.getChangeLogEvents(changeToken, null);
|
||||
assertChangeLog(changeToken, changeLogEvents);
|
||||
assertChangeEvents(changeToken, changeLogEvents, null, FoldersAppearing.MUST_APPEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tests {@link CMISChangeLogServiceImpl} on working with Change Event entries which could contain Folder Objects. Also this method tests behavior of Max Items
|
||||
* parameter for Folder Objects
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testReceivingOfChangeEventsExpectingFoldersAndBoundedByMaxItems() throws Exception
|
||||
{
|
||||
enableAudit();
|
||||
String changeToken = changeLogService.getLastChangeLogToken();
|
||||
createTestData(EXPECTED_AMOUNTS, true);
|
||||
CMISChangeLog changeLogEvents = changeLogService.getChangeLogEvents(changeToken, 15);
|
||||
assertTrue("Not all Change Event Entries were requested but result set indicates that no more Entry(s) available", changeLogEvents.hasMoreItems());
|
||||
assertChangeLog(changeToken, changeLogEvents);
|
||||
assertChangeEvents(changeToken, changeLogEvents, 15, FoldersAppearing.MAY_APPEAR);
|
||||
changeLogEvents = changeLogService.getChangeLogEvents(changeToken, TOTAL_AMOUNT);
|
||||
assertChangeLog(changeToken, changeLogEvents);
|
||||
assertChangeEvents(changeToken, changeLogEvents, TOTAL_AMOUNT, FoldersAppearing.MUST_APPEAR);
|
||||
assertFalse("All Change Event Entries were requested but results indicating that some more Entry(s) available", changeLogEvents.hasMoreItems());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext();
|
||||
changeLogService = (CMISChangeLogService) applicationContext.getBean("CMISChangeLogService");
|
||||
nodeService = (NodeService) applicationContext.getBean("NodeService");
|
||||
permissionService = (PermissionService) applicationContext.getBean("PermissionService");
|
||||
fileFolderService = (FileFolderService) applicationContext.getBean("FileFolderService");
|
||||
auditSubsystem = (ApplicationContextFactory) applicationContext.getBean("Audit");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
deleteTestData();
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
@@ -78,7 +78,7 @@ public abstract class CMISAbstractTypeDefinition implements CMISTypeDefinition,
|
||||
protected Boolean fullTextIndexed = null;
|
||||
protected Boolean controllablePolicy = null;
|
||||
protected Boolean controllableACL = null;
|
||||
protected Boolean includeInSuperTypeQuery = null;
|
||||
protected Boolean includedInSuperTypeQuery = null;
|
||||
protected Collection<CMISTypeId> subTypeIds = null;
|
||||
protected Collection<CMISTypeDefinition> subTypes = null;
|
||||
protected Map<String, CMISPropertyDefinition> properties = null;
|
||||
@@ -103,7 +103,7 @@ public abstract class CMISAbstractTypeDefinition implements CMISTypeDefinition,
|
||||
if (fullTextIndexed == null) throw new IllegalStateException("fullTextIndexed not specified; objectTypeId=" + objectTypeId);
|
||||
if (controllablePolicy == null) throw new IllegalStateException("controllablePolicy not specified; objectTypeId=" + objectTypeId);
|
||||
if (controllableACL == null) throw new IllegalStateException("controllablePolicy not specified; objectTypeId=" + objectTypeId);
|
||||
if (includeInSuperTypeQuery == null) throw new IllegalStateException("includeInSuperTypeQuery not specified; objectTypeId=" + objectTypeId);
|
||||
if (includedInSuperTypeQuery == null) throw new IllegalStateException("includedInSuperTypeQuery not specified; objectTypeId=" + objectTypeId);
|
||||
if (subTypeIds == null) throw new IllegalStateException("subTypeIds not specified; objectTypeId=" + objectTypeId);
|
||||
if (subTypes == null) throw new IllegalStateException("subTypes not specified; objectTypeId=" + objectTypeId);
|
||||
if (properties == null) throw new IllegalStateException("properties not specified; objectTypeId=" + objectTypeId);
|
||||
@@ -413,11 +413,11 @@ public abstract class CMISAbstractTypeDefinition implements CMISTypeDefinition,
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.dictionary.CMISTypeDefinition#isIncludeInSuperTypeQuery()
|
||||
* @see org.alfresco.cmis.dictionary.CMISTypeDefinition#isIncludedInSuperTypeQuery()
|
||||
*/
|
||||
public boolean isIncludeInSuperTypeQuery()
|
||||
public boolean isIncludedInSuperTypeQuery()
|
||||
{
|
||||
return includeInSuperTypeQuery;
|
||||
return includedInSuperTypeQuery;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -42,6 +42,7 @@ import org.alfresco.cmis.mapping.CMISMapping;
|
||||
import org.alfresco.repo.dictionary.IndexTokenisationMode;
|
||||
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
|
||||
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.DateAnalyser;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.DoubleAnalyser;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.FloatAnalyser;
|
||||
@@ -51,6 +52,7 @@ import org.alfresco.repo.search.impl.lucene.analysis.PathAnalyser;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.VerbatimAnalyser;
|
||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
|
||||
/**
|
||||
@@ -64,22 +66,36 @@ public class CMISBasePropertyDefinition implements CMISPropertyDefinition, Seria
|
||||
|
||||
// Properties of Property
|
||||
private CMISTypeDefinition typeDef;
|
||||
private CMISPropertyId propertyId;
|
||||
private String queryName;
|
||||
private String displayName;
|
||||
private String description;
|
||||
private CMISDataTypeEnum propertyType;
|
||||
private CMISCardinalityEnum cardinality;
|
||||
private int maximumLength = -1;
|
||||
private Collection<CMISChoice> choices = new HashSet<CMISChoice>();
|
||||
private boolean isOpenChoice = false;
|
||||
private boolean required;
|
||||
private String defaultValue;
|
||||
private CMISUpdatabilityEnum updatability;
|
||||
private boolean queryable;
|
||||
private boolean orderable;
|
||||
private AbstractProperty propertyAccessor;
|
||||
|
||||
private CMISPropertyId propertyId;
|
||||
|
||||
private String queryName;
|
||||
|
||||
private String displayName;
|
||||
|
||||
private String description;
|
||||
|
||||
private CMISDataTypeEnum propertyType;
|
||||
|
||||
private CMISCardinalityEnum cardinality;
|
||||
|
||||
private int maximumLength = -1;
|
||||
|
||||
private Collection<CMISChoice> choices = new HashSet<CMISChoice>();
|
||||
|
||||
private boolean isOpenChoice = false;
|
||||
|
||||
private boolean required;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private CMISUpdatabilityEnum updatability;
|
||||
|
||||
private boolean queryable;
|
||||
|
||||
private boolean orderable;
|
||||
|
||||
private AbstractProperty propertyAccessor;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
@@ -122,6 +138,8 @@ public class CMISBasePropertyDefinition implements CMISPropertyDefinition, Seria
|
||||
updatability = propDef.isProtected() ? CMISUpdatabilityEnum.READ_ONLY : CMISUpdatabilityEnum.READ_AND_WRITE;
|
||||
queryable = propDef.isIndexed();
|
||||
if (queryable)
|
||||
{
|
||||
if (cardinality == CMISCardinalityEnum.SINGLE_VALUED)
|
||||
{
|
||||
IndexTokenisationMode indexTokenisationMode = IndexTokenisationMode.TRUE;
|
||||
if (propDef.getIndexTokenisationMode() != null)
|
||||
@@ -137,7 +155,12 @@ public class CMISBasePropertyDefinition implements CMISPropertyDefinition, Seria
|
||||
case TRUE:
|
||||
default:
|
||||
String analyserClassName = propDef.getDataType().getAnalyserClassName();
|
||||
if (analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName())
|
||||
if(propDef.getDataType().getName().equals(DataTypeDefinition.BOOLEAN))
|
||||
{
|
||||
orderable = true;
|
||||
}
|
||||
else if (analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName())
|
||||
|| analyserClassName.equals(DateAnalyser.class.getCanonicalName())
|
||||
|| analyserClassName.equals(DoubleAnalyser.class.getCanonicalName()) || analyserClassName.equals(FloatAnalyser.class.getCanonicalName())
|
||||
|| analyserClassName.equals(IntegerAnalyser.class.getCanonicalName()) || analyserClassName.equals(LongAnalyser.class.getCanonicalName())
|
||||
|| analyserClassName.equals(PathAnalyser.class.getCanonicalName()) || analyserClassName.equals(VerbatimAnalyser.class.getCanonicalName()))
|
||||
@@ -154,6 +177,11 @@ public class CMISBasePropertyDefinition implements CMISPropertyDefinition, Seria
|
||||
{
|
||||
orderable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orderable = false;
|
||||
}
|
||||
propertyAccessor = cmisMapping.getPropertyAccessor(propertyId);
|
||||
}
|
||||
|
||||
@@ -327,7 +355,6 @@ public class CMISBasePropertyDefinition implements CMISPropertyDefinition, Seria
|
||||
return propertyAccessor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
|
@@ -91,8 +91,8 @@ public class CMISDocumentTypeDefinition extends CMISAbstractTypeDefinition
|
||||
queryable = true;
|
||||
fullTextIndexed = true;
|
||||
controllablePolicy = false;
|
||||
controllableACL = false;
|
||||
includeInSuperTypeQuery = true;
|
||||
controllableACL = true;
|
||||
includedInSuperTypeQuery = cmisClassDef.getIncludedInSuperTypeQuery();
|
||||
|
||||
actionEvaluators = cmisMapping.getActionEvaluators(objectTypeId.getScope());
|
||||
|
||||
@@ -160,7 +160,7 @@ public class CMISDocumentTypeDefinition extends CMISAbstractTypeDefinition
|
||||
builder.append("Creatable=").append(isCreatable()).append(", ");
|
||||
builder.append("Queryable=").append(isQueryable()).append(", ");
|
||||
builder.append("FullTextIndexed=").append(isFullTextIndexed()).append(", ");
|
||||
builder.append("IncludeInSuperTypeQuery=").append(isIncludeInSuperTypeQuery()).append(", ");
|
||||
builder.append("IncludedInSuperTypeQuery=").append(isIncludedInSuperTypeQuery()).append(", ");
|
||||
builder.append("ControllablePolicy=").append(isControllablePolicy()).append(", ");
|
||||
builder.append("ControllableACL=").append(isControllableACL()).append(", ");
|
||||
builder.append("Fileable=").append(isFileable()).append(", ");
|
||||
|
@@ -81,8 +81,8 @@ public class CMISFolderTypeDefinition extends CMISAbstractTypeDefinition
|
||||
queryable = true;
|
||||
fullTextIndexed = true;
|
||||
controllablePolicy = false;
|
||||
controllableACL = false;
|
||||
includeInSuperTypeQuery = true;
|
||||
controllableACL = true;
|
||||
includedInSuperTypeQuery = cmisClassDef.getIncludedInSuperTypeQuery();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -104,7 +104,7 @@ public class CMISFolderTypeDefinition extends CMISAbstractTypeDefinition
|
||||
builder.append("Creatable=").append(isCreatable()).append(", ");
|
||||
builder.append("Queryable=").append(isQueryable()).append(", ");
|
||||
builder.append("FullTextIndexed=").append(isFullTextIndexed()).append(", ");
|
||||
builder.append("IncludeInSuperTypeQuery=").append(isIncludeInSuperTypeQuery()).append(", ");
|
||||
builder.append("IncludedInSuperTypeQuery=").append(isIncludedInSuperTypeQuery()).append(", ");
|
||||
builder.append("ControllablePolicy=").append(isControllablePolicy()).append(", ");
|
||||
builder.append("ControllableACL=").append(isControllableACL()).append(", ");
|
||||
builder.append("SubTypes=").append(getSubTypes(false).size()).append(", ");
|
||||
|
@@ -77,7 +77,7 @@ public class CMISObjectTypeDefinition extends CMISAbstractTypeDefinition
|
||||
creatable = false;
|
||||
queryable = false;
|
||||
fullTextIndexed = false;
|
||||
includeInSuperTypeQuery = false;
|
||||
includedInSuperTypeQuery = cmisClassDef.getIncludedInSuperTypeQuery();
|
||||
controllablePolicy = false;
|
||||
controllableACL = false;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class CMISObjectTypeDefinition extends CMISAbstractTypeDefinition
|
||||
builder.append("Creatable=").append(isCreatable()).append(", ");
|
||||
builder.append("Queryable=").append(isQueryable()).append(", ");
|
||||
builder.append("Controllable=").append(isControllablePolicy()).append(", ");
|
||||
builder.append("IncludeInSuperTypeQuery=").append(isIncludeInSuperTypeQuery()).append(", ");
|
||||
builder.append("IncludedInSuperTypeQuery=").append(isIncludedInSuperTypeQuery()).append(", ");
|
||||
builder.append("SubTypes=").append(getSubTypes(false).size()).append(", ");
|
||||
builder.append("Properties=").append(getPropertyDefinitions().size());
|
||||
builder.append("]");
|
||||
|
@@ -83,7 +83,7 @@ public class CMISPolicyTypeDefinition extends CMISAbstractTypeDefinition
|
||||
|
||||
creatable = false;
|
||||
queryable = true;
|
||||
includeInSuperTypeQuery = true;
|
||||
includedInSuperTypeQuery = cmisClassDef.getIncludedInSuperTypeQuery();
|
||||
fullTextIndexed = true;
|
||||
controllablePolicy = false;
|
||||
controllableACL = false;
|
||||
@@ -147,7 +147,7 @@ public class CMISPolicyTypeDefinition extends CMISAbstractTypeDefinition
|
||||
builder.append("Creatable=").append(isCreatable()).append(", ");
|
||||
builder.append("Queryable=").append(isQueryable()).append(", ");
|
||||
builder.append("Controllable=").append(isControllablePolicy()).append(", ");
|
||||
builder.append("IncludeInSuperTypeQuery=").append(isIncludeInSuperTypeQuery()).append(", ");
|
||||
builder.append("IncludedInSuperTypeQuery=").append(isIncludedInSuperTypeQuery()).append(", ");
|
||||
builder.append("SubTypes=").append(getSubTypes(false).size()).append(", ");
|
||||
builder.append("Properties=").append(getPropertyDefinitions().size());
|
||||
builder.append("]");
|
||||
|
@@ -80,7 +80,7 @@ public class CMISRelationshipTypeDefinition extends CMISAbstractTypeDefinition
|
||||
|
||||
queryable = false;
|
||||
fullTextIndexed = false;
|
||||
includeInSuperTypeQuery = true;
|
||||
includedInSuperTypeQuery = true;
|
||||
controllablePolicy = false;
|
||||
controllableACL = false;
|
||||
|
||||
@@ -247,7 +247,7 @@ public class CMISRelationshipTypeDefinition extends CMISAbstractTypeDefinition
|
||||
builder.append("Creatable=").append(isCreatable()).append(", ");
|
||||
builder.append("Queryable=").append(isQueryable()).append(", ");
|
||||
builder.append("Controllable=").append(isControllablePolicy()).append(", ");
|
||||
builder.append("IncludeInSuperTypeQuery=").append(isIncludeInSuperTypeQuery()).append(", ");
|
||||
builder.append("IncludedInSuperTypeQuery=").append(isIncludedInSuperTypeQuery()).append(", ");
|
||||
builder.append("AllowedSourceTypes=[");
|
||||
for (CMISTypeDefinition type : getAllowedSourceTypes())
|
||||
{
|
||||
|
@@ -139,7 +139,7 @@ public abstract class AbstractProperty implements CMISPropertyAccessor, CMISProp
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@@ -239,7 +239,7 @@ public abstract class AbstractSimpleProperty extends AbstractProperty
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.property.PropertyLuceneBuilder#getLuceneSortField()
|
||||
*/
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
return getLuceneFieldName();
|
||||
}
|
||||
|
@@ -31,12 +31,17 @@ import javax.transaction.UserTransaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlService;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISQueryService;
|
||||
import org.alfresco.cmis.CMISRenditionService;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.NamespaceDAOImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
|
||||
import org.alfresco.repo.security.permissions.impl.ModelDAO;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
@@ -47,6 +52,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
@@ -69,6 +75,10 @@ public abstract class BaseCMISTest extends TestCase
|
||||
|
||||
protected CMISDictionaryService cmisDictionaryService;
|
||||
|
||||
protected CMISRenditionService cmisRenditionService;
|
||||
|
||||
protected CMISAccessControlService cmisAccessControlService;
|
||||
|
||||
protected DictionaryService dictionaryService;
|
||||
|
||||
protected TransactionService transactionService;
|
||||
@@ -99,6 +109,14 @@ public abstract class BaseCMISTest extends TestCase
|
||||
|
||||
protected PermissionService permissionService;
|
||||
|
||||
protected ThumbnailService thumbnailService;
|
||||
|
||||
protected ModelDAO permissionModelDao;
|
||||
|
||||
protected DictionaryDAO dictionaryDAO;
|
||||
|
||||
protected NamespaceDAOImpl namespaceDao;
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||
@@ -107,6 +125,8 @@ public abstract class BaseCMISTest extends TestCase
|
||||
cmisMapping = (CMISMapping) ctx.getBean("CMISMapping");
|
||||
cmisQueryService = (CMISQueryService) ctx.getBean("CMISQueryService");
|
||||
cmisService = (CMISServices) ctx.getBean("CMISService");
|
||||
cmisRenditionService = (CMISRenditionService) ctx.getBean("CMISRenditionService");
|
||||
cmisAccessControlService = (CMISAccessControlService) ctx.getBean("CMISAccessControlService");
|
||||
dictionaryService = (DictionaryService) ctx.getBean("dictionaryService");
|
||||
nodeService = (NodeService) ctx.getBean("nodeService");
|
||||
fileFolderService = (FileFolderService) ctx.getBean("fileFolderService");
|
||||
@@ -124,6 +144,13 @@ public abstract class BaseCMISTest extends TestCase
|
||||
authenticationService = (MutableAuthenticationService) ctx.getBean("authenticationService");
|
||||
authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao");
|
||||
|
||||
thumbnailService = (ThumbnailService) ctx.getBean("thumbnailService");
|
||||
|
||||
permissionModelDao = (ModelDAO) ctx.getBean("permissionsModelDAO");
|
||||
|
||||
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
|
||||
namespaceDao = (NamespaceDAOImpl) ctx.getBean("namespaceDAO");
|
||||
|
||||
testTX = transactionService.getUserTransaction();
|
||||
testTX.begin();
|
||||
this.authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
@@ -26,9 +26,13 @@ package org.alfresco.cmis.mapping;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.cmis.CMISAccessControlFormatEnum;
|
||||
import org.alfresco.cmis.CMISAccessControlService;
|
||||
import org.alfresco.cmis.CMISActionEvaluator;
|
||||
import org.alfresco.cmis.CMISAllowedActionEnum;
|
||||
import org.alfresco.cmis.CMISDataTypeEnum;
|
||||
@@ -65,7 +69,7 @@ public class CMISMapping implements InitializingBean
|
||||
* The Alfresco CMIS Namespace
|
||||
*/
|
||||
public static String CMIS_MODEL_NS = "cmis";
|
||||
public static String CMIS_MODEL_URI = "http://www.alfresco.org/model/cmis/1.0/cd04";
|
||||
public static String CMIS_MODEL_URI = "http://www.alfresco.org/model/cmis/1.0/cd07";
|
||||
|
||||
/**
|
||||
* The Alfresco CMIS Model name.
|
||||
@@ -108,6 +112,10 @@ public class CMISMapping implements InitializingBean
|
||||
private Map<CMISScope, Map<CMISAllowedActionEnum, CMISActionEvaluator>> actionEvaluators = new HashMap<CMISScope, Map<CMISAllowedActionEnum, CMISActionEvaluator>>();
|
||||
|
||||
|
||||
private Set<String> cmisRead = new HashSet<String>();
|
||||
private Set<String> cmisWrite = new HashSet<String>();
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
@@ -197,6 +205,9 @@ public class CMISMapping implements InitializingBean
|
||||
// Action Evaluator Mappings
|
||||
//
|
||||
|
||||
// NOTE: The order of evaluators is important - they must be in the order as specified in CMIS-Core.xsd
|
||||
// so that schema validation passes
|
||||
|
||||
registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_DELETE_OBJECT, PermissionService.DELETE_NODE));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_UPDATE_PROPERTIES, PermissionService.WRITE_PROPERTIES));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_PROPERTIES, PermissionService.READ_PROPERTIES));
|
||||
@@ -219,8 +230,8 @@ public class CMISMapping implements InitializingBean
|
||||
registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_REMOVE_POLICY, false));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_RELATIONSHIP, true));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_RENDITIONS, true));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_ACL, false));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_ACL, false));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_ACL, PermissionService.READ_PERMISSIONS));
|
||||
registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_ACL, PermissionService.CHANGE_PERMISSIONS));
|
||||
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_DELETE_OBJECT, PermissionService.DELETE_NODE));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_UPDATE_PROPERTIES, PermissionService.WRITE_PROPERTIES));
|
||||
@@ -239,9 +250,9 @@ public class CMISMapping implements InitializingBean
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_DOCUMENT, PermissionService.CREATE_CHILDREN));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_FOLDER, PermissionService.CREATE_CHILDREN));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_RELATIONSHIP, PermissionService.CREATE_ASSOCIATIONS));
|
||||
registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_POLICY, false));
|
||||
registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_ACL, false));
|
||||
registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_ACL, false));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_DELETE_TREE, PermissionService.DELETE_NODE));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_ACL, PermissionService.READ_PERMISSIONS));
|
||||
registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_ACL, PermissionService.CHANGE_PERMISSIONS));
|
||||
|
||||
registerEvaluator(CMISScope.RELATIONSHIP, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_DELETE_OBJECT, true));
|
||||
registerEvaluator(CMISScope.RELATIONSHIP, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_UPDATE_PROPERTIES, false));
|
||||
@@ -259,6 +270,15 @@ public class CMISMapping implements InitializingBean
|
||||
registerEvaluator(CMISScope.POLICY, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_OBJECT_RELATIONSHIPS, false));
|
||||
registerEvaluator(CMISScope.POLICY, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_ACL, false));
|
||||
registerEvaluator(CMISScope.POLICY, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_ACL, false));
|
||||
|
||||
cmisRead.add(PermissionService.READ_PROPERTIES);
|
||||
cmisRead.add(PermissionService.READ_CONTENT);
|
||||
cmisRead.add(PermissionService.READ);
|
||||
|
||||
cmisWrite.add(PermissionService.WRITE_PROPERTIES);
|
||||
cmisWrite.add(PermissionService.WRITE_CONTENT);
|
||||
cmisWrite.add(PermissionService.WRITE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -770,4 +790,54 @@ public class CMISMapping implements InitializingBean
|
||||
logger.debug("Registered Action Evaluator: scope=" + scope + ", evaluator=" + evaluator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param permission
|
||||
* @param format
|
||||
* @return
|
||||
*/
|
||||
public String getReportedPermission(String permission, CMISAccessControlFormatEnum format)
|
||||
{
|
||||
if(format == CMISAccessControlFormatEnum.REPOSITORY_SPECIFIC_PERMISSIONS)
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cmisRead.contains(permission))
|
||||
{
|
||||
return CMISAccessControlService.CMIS_READ_PERMISSION;
|
||||
}
|
||||
else if(cmisWrite.contains(permission))
|
||||
{
|
||||
return CMISAccessControlService.CMIS_WRITE_PERMISSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CMISAccessControlService.CMIS_ALL_PERMISSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSetPermission(String permission)
|
||||
{
|
||||
if(permission.equals(CMISAccessControlService.CMIS_READ_PERMISSION))
|
||||
{
|
||||
return PermissionService.READ;
|
||||
}
|
||||
else if(permission.equals(CMISAccessControlService.CMIS_WRITE_PERMISSION))
|
||||
{
|
||||
return PermissionService.WRITE;
|
||||
}
|
||||
else if(permission.equals(CMISAccessControlService.CMIS_ALL_PERMISSION))
|
||||
{
|
||||
return PermissionService.ALL_PERMISSIONS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -105,7 +105,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
}
|
||||
@@ -139,7 +138,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -191,7 +189,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -237,7 +234,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -272,7 +268,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -317,7 +312,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -349,7 +343,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -394,7 +387,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -426,7 +418,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -461,7 +452,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -493,7 +483,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -538,7 +527,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -570,7 +558,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -615,7 +602,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -650,7 +636,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -695,7 +680,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
@@ -730,7 +714,6 @@ public class CMISPropertyServiceTest extends BaseCMISTest
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L);
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream");
|
||||
assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent");
|
||||
assertNotNull(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_ID));
|
||||
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID));
|
||||
assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS));
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,7 +18,7 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
@@ -27,14 +27,18 @@ package org.alfresco.cmis.mapping;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.cmis.CMISDictionaryModel;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISPropertyDefinition;
|
||||
import org.alfresco.cmis.CMISRelationshipDirectionEnum;
|
||||
import org.alfresco.cmis.CMISRendition;
|
||||
import org.alfresco.cmis.CMISRenditionService;
|
||||
import org.alfresco.cmis.CMISScope;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.cmis.CMISTypeDefinition;
|
||||
@@ -111,6 +115,7 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
private NodeService nodeService;
|
||||
private TenantAdminService tenantAdminService;
|
||||
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
|
||||
private CMISRenditionService cmisRenditionService;
|
||||
|
||||
// CMIS supported version
|
||||
private String cmisVersion = "[undefined]";
|
||||
@@ -222,6 +227,17 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cmis rendition service.
|
||||
*
|
||||
* @param cmisRenditionService
|
||||
* the cmis rendition service
|
||||
*/
|
||||
public void setCMISRenditionService(CMISRenditionService cmisRenditionService)
|
||||
{
|
||||
this.cmisRenditionService = cmisRenditionService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@@ -377,6 +393,30 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getRenditions(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
|
||||
*/
|
||||
public Map<String, Object> getRenditions(NodeRef nodeRef, String renditionFilter)
|
||||
{
|
||||
Map<String, Object> result = new TreeMap<String, Object>();
|
||||
List<CMISRendition> renditions = cmisRenditionService.getRenditions(nodeRef, renditionFilter);
|
||||
if (renditions == null)
|
||||
{
|
||||
renditions = Collections.emptyList();
|
||||
}
|
||||
result.put("node", nodeRef);
|
||||
result.put("renditionFilter", renditionFilter); // Record rendition filter to aid recursion on node maps
|
||||
result.put("renditions", renditions);
|
||||
List<NodeRef> renditionNodes = new ArrayList<NodeRef>(renditions.size());
|
||||
for (CMISRendition rendition : renditions)
|
||||
{
|
||||
renditionNodes.add(rendition.getNodeRef());
|
||||
}
|
||||
result.put("renditionNodes", renditionNodes);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISServices#getChildren(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.cmis.CMISTypesFilterEnum)
|
||||
|
@@ -27,11 +27,14 @@ package org.alfresco.cmis.mapping;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.alfresco.cmis.CMISDictionaryModel;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
|
||||
/**
|
||||
* Accessor for CMIS content stream length property
|
||||
* Accessor for CMIS content stream property id
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
@@ -53,7 +56,13 @@ public class ContentStreamIdProperty extends AbstractProperty
|
||||
*/
|
||||
public Serializable getValue(NodeRef nodeRef)
|
||||
{
|
||||
return "cm:content";
|
||||
Serializable sValue = getServiceRegistry().getNodeService().getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
if (sValue != null)
|
||||
{
|
||||
ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, sValue);
|
||||
return contentData.getContentUrl();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,7 +25,15 @@
|
||||
package org.alfresco.cmis.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.alfresco.repo.search.MLAnalysisMode;
|
||||
import org.alfresco.repo.search.SearcherException;
|
||||
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
|
||||
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -33,6 +41,8 @@ import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.lucene.index.IndexReader.FieldOption;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* A simple 1-1 property mapping from a CMIS property name to an alfresco property
|
||||
@@ -41,6 +51,96 @@ import org.alfresco.service.namespace.QName;
|
||||
*/
|
||||
public class DirectProperty extends AbstractSimpleProperty
|
||||
{
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.mapping.AbstractSimpleProperty#getLuceneSortField()
|
||||
*/
|
||||
@Override
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
|
||||
String field = getLuceneFieldName();
|
||||
// need to find the real field to use
|
||||
Locale sortLocale = null;
|
||||
|
||||
PropertyDefinition propertyDef = getServiceRegistry().getDictionaryService().getProperty(QName.createQName(field.substring(1)));
|
||||
|
||||
if (propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
|
||||
{
|
||||
throw new SearcherException("Order on content properties is not curently supported");
|
||||
}
|
||||
else if ((propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) || (propertyDef.getDataType().getName().equals(DataTypeDefinition.TEXT)))
|
||||
{
|
||||
List<Locale> locales = lqp.getSearchParameters().getLocales();
|
||||
if (((locales == null) || (locales.size() == 0)))
|
||||
{
|
||||
locales = Collections.singletonList(I18NUtil.getLocale());
|
||||
}
|
||||
|
||||
if (locales.size() > 1)
|
||||
{
|
||||
throw new SearcherException("Order on text/mltext properties with more than one locale is not curently supported");
|
||||
}
|
||||
|
||||
sortLocale = locales.get(0);
|
||||
// find best field match
|
||||
|
||||
HashSet<String> allowableLocales = new HashSet<String>();
|
||||
MLAnalysisMode analysisMode = lqp.getConfig().getDefaultMLSearchAnalysisMode();
|
||||
for (Locale l : MLAnalysisMode.getLocales(analysisMode, sortLocale, false))
|
||||
{
|
||||
allowableLocales.add(l.toString());
|
||||
}
|
||||
|
||||
String sortField = field;
|
||||
|
||||
for (Object current : lqp.getIndexReader().getFieldNames(FieldOption.INDEXED))
|
||||
{
|
||||
String currentString = (String) current;
|
||||
if (currentString.startsWith(field) && currentString.endsWith(".sort"))
|
||||
{
|
||||
String fieldLocale = currentString.substring(field.length() + 1, currentString.length() - 5);
|
||||
if (allowableLocales.contains(fieldLocale))
|
||||
{
|
||||
if (fieldLocale.equals(sortLocale.toString()))
|
||||
{
|
||||
sortField = currentString;
|
||||
break;
|
||||
}
|
||||
else if (sortLocale.toString().startsWith(fieldLocale))
|
||||
{
|
||||
if (sortField.equals(field) || (currentString.length() < sortField.length()))
|
||||
{
|
||||
sortField = currentString;
|
||||
}
|
||||
}
|
||||
else if (fieldLocale.startsWith(sortLocale.toString()))
|
||||
{
|
||||
if (sortField.equals(field) || (currentString.length() < sortField.length()))
|
||||
{
|
||||
sortField = currentString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field = sortField;
|
||||
|
||||
}
|
||||
else if (propertyDef.getDataType().getName().equals(DataTypeDefinition.DATETIME))
|
||||
{
|
||||
DataTypeDefinition dataType = propertyDef.getDataType();
|
||||
String analyserClassName = dataType.getAnalyserClassName();
|
||||
if (analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName()))
|
||||
{
|
||||
field = field + ".sort";
|
||||
}
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
private QName alfrescoName;
|
||||
|
||||
/**
|
||||
@@ -58,7 +158,6 @@ public class DirectProperty extends AbstractSimpleProperty
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.property.AbstractPropertyAccessor#getMappedProperty()
|
||||
*/
|
||||
public QName getMappedProperty()
|
||||
@@ -68,7 +167,6 @@ public class DirectProperty extends AbstractSimpleProperty
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.property.PropertyAccessor#getValue(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public Serializable getValue(NodeRef nodeRef)
|
||||
@@ -112,6 +210,4 @@ public class DirectProperty extends AbstractSimpleProperty
|
||||
return pd.getDataType();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@@ -313,7 +313,7 @@ public class FixedValueProperty extends AbstractProperty
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.property.PropertyLuceneBuilder#getLuceneSortField()
|
||||
*/
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@@ -69,6 +69,8 @@ public class ObjectIdProperty extends AbstractProperty
|
||||
* @see org.alfresco.cmis.mapping.AbstractProperty#getValue(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public Serializable getValue(NodeRef nodeRef)
|
||||
{
|
||||
if (!getServiceRegistry().getNodeService().hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
if (getServiceRegistry().getNodeService().hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
|
||||
{
|
||||
@@ -83,6 +85,7 @@ public class ObjectIdProperty extends AbstractProperty
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodeRef.toString();
|
||||
}
|
||||
@@ -270,7 +273,7 @@ public class ObjectIdProperty extends AbstractProperty
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.property.NamedPropertyAccessor#getLuceneSortField(java.lang.String)
|
||||
*/
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
return getLuceneFieldName();
|
||||
}
|
||||
|
@@ -266,7 +266,7 @@ public class ObjectTypeIdProperty extends AbstractProperty
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.property.PropertyLuceneBuilder#getLuceneSortField()
|
||||
*/
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
return getLuceneFieldName();
|
||||
}
|
||||
|
@@ -222,7 +222,7 @@ public class ParentProperty extends AbstractProperty
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.property.PropertyLuceneBuilder#getLuceneSortField()
|
||||
*/
|
||||
public String getLuceneSortField()
|
||||
public String getLuceneSortField(LuceneQueryParser lqp)
|
||||
{
|
||||
return getLuceneFieldName();
|
||||
}
|
||||
|
273
source/java/org/alfresco/cmis/renditions/CMISRenditionImpl.java
Executable file
273
source/java/org/alfresco/cmis/renditions/CMISRenditionImpl.java
Executable file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.renditions;
|
||||
|
||||
import org.alfresco.cmis.CMISRendition;
|
||||
import org.alfresco.cmis.CMISRenditionKind;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* CMIS Rendition Implementation
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public class CMISRenditionImpl implements CMISRendition
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private String streamId;
|
||||
private String mimeType;
|
||||
private CMISRenditionKind kind;
|
||||
private Integer height;
|
||||
private Integer width;
|
||||
private String title;
|
||||
private Integer length;
|
||||
private String renditionDocumentId;
|
||||
|
||||
/**
|
||||
* Construct a CmisRendition using fields
|
||||
*
|
||||
* @param nodeRef the rendition node reference
|
||||
* @param streamId rendition stream id
|
||||
* @param mimeType the MIME type of the rendition stream
|
||||
* @param kind a categorization String associated with the rendition
|
||||
* @param height the height of image
|
||||
* @param width the width of image
|
||||
* @param title rendition title
|
||||
* @param length the length of the rendition stream in bytes
|
||||
* @param renditionDocumentId the rendition document id
|
||||
*/
|
||||
public CMISRenditionImpl(NodeRef nodeRef, String streamId, String mimeType, CMISRenditionKind kind, Integer height, Integer width, String title, Integer length, String renditionDocumentId)
|
||||
{
|
||||
super();
|
||||
this.nodeRef = nodeRef;
|
||||
this.streamId = streamId;
|
||||
this.mimeType = mimeType;
|
||||
this.kind = kind;
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.title = title;
|
||||
this.length = length;
|
||||
this.renditionDocumentId = renditionDocumentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public CMISRenditionImpl()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getStreamId()
|
||||
*/
|
||||
public String getStreamId()
|
||||
{
|
||||
return streamId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rendition stream id
|
||||
*
|
||||
* @param streamId rendition stream id
|
||||
*/
|
||||
public void setStreamId(String streamId)
|
||||
{
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getMimeType()
|
||||
*/
|
||||
public String getMimeType()
|
||||
{
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MIME type of the rendition stream
|
||||
*
|
||||
* @param mimeType the MIME type of the rendition stream
|
||||
*/
|
||||
public void setMimeType(String mimeType)
|
||||
{
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getKind()
|
||||
*/
|
||||
public CMISRenditionKind getKind()
|
||||
{
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rendition kind
|
||||
*
|
||||
* @param kind rendition kind
|
||||
*/
|
||||
public void setKind(CMISRenditionKind kind)
|
||||
{
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getHeight()
|
||||
*/
|
||||
public Integer getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of image
|
||||
*
|
||||
* @param height the height of image
|
||||
*/
|
||||
public void setHeight(Integer height)
|
||||
{
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getWidth()
|
||||
*/
|
||||
public Integer getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of image
|
||||
*
|
||||
* @param width the width of image
|
||||
*/
|
||||
public void setWidth(Integer width)
|
||||
{
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getTitle()
|
||||
*/
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of rendition
|
||||
*
|
||||
* @param title the title
|
||||
*/
|
||||
public void setTitle(String title)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getLength()
|
||||
*/
|
||||
public Integer getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of the rendition stream in bytes
|
||||
*
|
||||
* @param length length of the rendition stream in bytes
|
||||
*/
|
||||
public void setLength(Integer length)
|
||||
{
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRendition#getRenditionDocumentId()
|
||||
*/
|
||||
public String getRenditionDocumentId()
|
||||
{
|
||||
return renditionDocumentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rendition document id
|
||||
*
|
||||
* @param renditionDocumentId the rendition document id
|
||||
*/
|
||||
public void setRenditionDocumentId(String renditionDocumentId)
|
||||
{
|
||||
this.renditionDocumentId = renditionDocumentId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.cmis.CMISRendition#getNodeRef()
|
||||
*/
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return this.nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeRef
|
||||
* the nodeRef to set
|
||||
*/
|
||||
public void setNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof CMISRendition)
|
||||
{
|
||||
CMISRendition that = (CMISRendition) obj;
|
||||
return (this.getStreamId() != null && that.getStreamId() != null && this.getStreamId().equals(that.getStreamId()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return this.getStreamId() != null ? this.getStreamId().hashCode() : 0x01;
|
||||
}
|
||||
|
||||
}
|
517
source/java/org/alfresco/cmis/renditions/CMISRenditionServiceImpl.java
Executable file
517
source/java/org/alfresco/cmis/renditions/CMISRenditionServiceImpl.java
Executable file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.renditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.cmis.CMISRendition;
|
||||
import org.alfresco.cmis.CMISRenditionKind;
|
||||
import org.alfresco.cmis.CMISRenditionService;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
|
||||
/**
|
||||
* Rendition Service Implementation
|
||||
*
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public class CMISRenditionServiceImpl implements CMISRenditionService
|
||||
{
|
||||
|
||||
/** Rendition filter constants */
|
||||
private static final String FILTER_WILDCARD = "*";
|
||||
private static final String FILTER_NONE = "cmis:none";
|
||||
private static final String FILTER_DELIMITER = ",";
|
||||
private static final String SUBTYPES_POSTFIX = "/*";
|
||||
private static final String SUBTYPES_DELIMITER = "/";
|
||||
|
||||
/** Service dependencies */
|
||||
private ThumbnailService thumbnailService;
|
||||
private NodeService nodeService;
|
||||
|
||||
/** Kind to thumbnail mapping */
|
||||
private Map<String, List<String>> kindToThumbnailNames = new HashMap<String, List<String>>();
|
||||
private Map<String, CMISRenditionKind> thumbnailNamesToKind = new HashMap<String, CMISRenditionKind>();
|
||||
|
||||
/** Custom renditions */
|
||||
private CustomRenditionsCache customRenditionsCache;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.cmis.CMISRenditionService#getRenditions(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
|
||||
*/
|
||||
public List<CMISRendition> getRenditions(NodeRef node, String renditionFilter)
|
||||
{
|
||||
Collection<CMISRendition> result = null;
|
||||
ThumbnailFilter thumbnailFilter = getThumbnailFilter(renditionFilter);
|
||||
if (thumbnailFilter != null)
|
||||
{
|
||||
result = getRenditions(node, thumbnailFilter);
|
||||
}
|
||||
return result != null ? new ArrayList<CMISRendition>(result) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get renditions for a document.
|
||||
*
|
||||
* @param node node reference of document
|
||||
* @param thumbnailFilter thumbnail filter
|
||||
* @return set of renditions
|
||||
*/
|
||||
private Set<CMISRendition> getRenditions(NodeRef node, ThumbnailFilter thumbnailFilter)
|
||||
{
|
||||
Set<CMISRendition> result = new HashSet<CMISRendition>();
|
||||
if (thumbnailFilter.isAny())
|
||||
{
|
||||
result.addAll(getAllRenditions(node));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (String thumbnailName : thumbnailFilter.getThumbnailNames())
|
||||
{
|
||||
CMISRendition rendition = getRenditionByThumbnailName(node, thumbnailName);
|
||||
if (rendition != null)
|
||||
{
|
||||
result.add(rendition);
|
||||
}
|
||||
}
|
||||
for (String mimetype : thumbnailFilter.getMimetypes())
|
||||
{
|
||||
result.addAll(getRenditionByMimetype(node, mimetype));
|
||||
}
|
||||
}
|
||||
result.addAll(getCustomRenditions(thumbnailFilter));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rendition by thumbnail name.
|
||||
*
|
||||
* @param node node reference of document
|
||||
* @param thumbnailName thumbnail name
|
||||
* @return rendition
|
||||
*/
|
||||
private CMISRendition getRenditionByThumbnailName(NodeRef node, String thumbnailName)
|
||||
{
|
||||
CMISRendition result = null;
|
||||
|
||||
NodeRef thumbnailNode = thumbnailService.getThumbnailByName(node, ContentModel.PROP_CONTENT, thumbnailName);
|
||||
|
||||
if (thumbnailNode != null)
|
||||
{
|
||||
result = getRendition(thumbnailNode, node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rendition by mimetype.
|
||||
*
|
||||
* @param node node reference of document
|
||||
* @param mimetype rendition mimetype
|
||||
* @return list of renditions
|
||||
*/
|
||||
private List<CMISRendition> getRenditionByMimetype(NodeRef node, String mimetype)
|
||||
{
|
||||
List<CMISRendition> result = new ArrayList<CMISRendition>();
|
||||
|
||||
List<NodeRef> thumbnails = thumbnailService.getThumbnails(node, ContentModel.PROP_CONTENT, mimetype, null);
|
||||
|
||||
if (thumbnails != null)
|
||||
{
|
||||
for (NodeRef thumbnailNode : thumbnails)
|
||||
{
|
||||
CMISRendition rendition = getRendition(thumbnailNode, node);
|
||||
if (rendition != null)
|
||||
{
|
||||
result.add(rendition);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the rendition filter to thumbnail filter.
|
||||
*
|
||||
* @param renditionFilter rendition filter
|
||||
* @return thumbnail filter
|
||||
*/
|
||||
private ThumbnailFilter getThumbnailFilter(String renditionFilter)
|
||||
{
|
||||
ThumbnailFilter result = null;
|
||||
if (renditionFilter != null && !renditionFilter.equals(FILTER_NONE))
|
||||
{
|
||||
result = new ThumbnailFilter();
|
||||
if (renditionFilter.equals(FILTER_WILDCARD))
|
||||
{
|
||||
result.setAny(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] filterElements = renditionFilter.split(FILTER_DELIMITER);
|
||||
if (filterElements == null || filterElements.length < 1)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Invalid rendition filter");
|
||||
}
|
||||
for (String filterElement : filterElements)
|
||||
{
|
||||
filterElement = filterElement.trim();
|
||||
if (isRenditionKind(filterElement))
|
||||
{
|
||||
CMISRenditionKind kind = null;
|
||||
for (CMISRenditionKind renditionKind : CMISRenditionKind.values())
|
||||
{
|
||||
if (renditionKind.getLabel().equals(filterElement))
|
||||
{
|
||||
kind = renditionKind;
|
||||
}
|
||||
}
|
||||
result.getKinds().add(kind);
|
||||
List<String> thumbnails = kindToThumbnailNames.get(filterElement);
|
||||
if (thumbnails != null)
|
||||
{
|
||||
result.getThumbnailNames().addAll(thumbnails);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.getMimetypes().add(filterElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thumbnail definition.
|
||||
*
|
||||
* @param thumbnailName thumbnail name
|
||||
* @return thumbnail definition
|
||||
*/
|
||||
private ThumbnailDefinition getThumbnailDefinition(String thumbnailName)
|
||||
{
|
||||
return thumbnailService.getThumbnailRegistry().getThumbnailDefinition(thumbnailName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image attributes of thumbnail.
|
||||
*
|
||||
* @param thumbnailName thumbnail name
|
||||
* @return image attributes
|
||||
*/
|
||||
private ImageResizeOptions getImageAttributes(String thumbnailName)
|
||||
{
|
||||
ThumbnailDefinition thumbnailDefinition = getThumbnailDefinition(thumbnailName);
|
||||
if (thumbnailDefinition != null && thumbnailDefinition.getTransformationOptions() != null
|
||||
&& thumbnailDefinition.getTransformationOptions() instanceof ImageTransformationOptions)
|
||||
{
|
||||
return ((ImageTransformationOptions) thumbnailDefinition.getTransformationOptions()).getResizeOptions();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filterElement filter element
|
||||
* @return true if filter element is rendition kind
|
||||
*/
|
||||
private boolean isRenditionKind(String filterElement)
|
||||
{
|
||||
boolean result = false;
|
||||
for (CMISRenditionKind renditionKind : CMISRenditionKind.values())
|
||||
{
|
||||
if (renditionKind.getLabel().equals(filterElement))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create CMISRendition by thumbnailNode and documentNode.
|
||||
*
|
||||
* @param thumbnailNode thumbnail node reference
|
||||
* @param documentNode document node reference
|
||||
* @return CMISRendition
|
||||
*/
|
||||
private CMISRendition getRendition(NodeRef thumbnailNode, NodeRef documentNode)
|
||||
{
|
||||
CMISRenditionImpl rendition = null;
|
||||
|
||||
String thumbnailName = (String) nodeService.getProperty(thumbnailNode, ContentModel.PROP_THUMBNAIL_NAME);
|
||||
CMISRenditionKind kind = thumbnailNamesToKind.get(thumbnailName);
|
||||
if (thumbnailName != null && kind != null)
|
||||
{
|
||||
rendition = new CMISRenditionImpl();
|
||||
ContentData contentData = (ContentData) nodeService.getProperty(thumbnailNode, ContentModel.PROP_CONTENT);
|
||||
rendition.setNodeRef(thumbnailNode);
|
||||
rendition.setStreamId(thumbnailNode.toString());
|
||||
rendition.setRenditionDocumentId(documentNode.toString());
|
||||
rendition.setTitle(thumbnailName);
|
||||
rendition.setKind(kind);
|
||||
rendition.setMimeType(contentData.getMimetype());
|
||||
rendition.setLength((int) contentData.getSize());
|
||||
|
||||
ImageResizeOptions imageAttributes = getImageAttributes(thumbnailName);
|
||||
if (imageAttributes != null)
|
||||
{
|
||||
rendition.setWidth(imageAttributes.getWidth());
|
||||
rendition.setHeight(imageAttributes.getHeight());
|
||||
}
|
||||
}
|
||||
return rendition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom renditions.
|
||||
*
|
||||
* @param thumbnailFilter thumbnail filter
|
||||
* @return list of renditions
|
||||
*/
|
||||
private List<CMISRendition> getCustomRenditions(ThumbnailFilter filter)
|
||||
{
|
||||
List<CMISRendition> result = new ArrayList<CMISRendition>();
|
||||
if (customRenditionsCache != null)
|
||||
{
|
||||
if (filter.isAny())
|
||||
{
|
||||
result.addAll(customRenditionsCache.getAllRenditions());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (CMISRenditionKind kind : filter.getKinds())
|
||||
{
|
||||
List<CMISRendition> renditions = customRenditionsCache.getRenditionsByKind(kind);
|
||||
if (renditions != null)
|
||||
{
|
||||
result.addAll(renditions);
|
||||
}
|
||||
}
|
||||
for (String mimetype : filter.getMimetypes())
|
||||
{
|
||||
List<CMISRendition> renditions = customRenditionsCache.getRenditionsByMimeType(mimetype);
|
||||
if (renditions != null)
|
||||
{
|
||||
result.addAll(renditions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all renditions for a document.
|
||||
*
|
||||
* @param node document node ref
|
||||
* @return list of renditions
|
||||
*/
|
||||
private List<CMISRendition> getAllRenditions(NodeRef node)
|
||||
{
|
||||
return getRenditionByMimetype(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rendition kind mapping.
|
||||
*
|
||||
* @param RenditionKind to Thumbnail Definition mapping
|
||||
*/
|
||||
public void setRenditionKindMapping(Map<String, List<String>> renditionKinds)
|
||||
{
|
||||
this.kindToThumbnailNames = renditionKinds;
|
||||
for (Entry<String, List<String>> entry : renditionKinds.entrySet())
|
||||
{
|
||||
CMISRenditionKind kind = null;
|
||||
for (CMISRenditionKind renditionKind : CMISRenditionKind.values())
|
||||
{
|
||||
if (renditionKind.getLabel().equals(entry.getKey()))
|
||||
{
|
||||
kind = renditionKind;
|
||||
}
|
||||
}
|
||||
for (String thumbnailName : entry.getValue())
|
||||
{
|
||||
thumbnailNamesToKind.put(thumbnailName, kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom renditions.
|
||||
*
|
||||
* @param renditions list of renditions
|
||||
*/
|
||||
public void setCustomRenditions(List<CMISRendition> renditions)
|
||||
{
|
||||
this.customRenditionsCache = new CustomRenditionsCache(renditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the NodeService.
|
||||
*
|
||||
* @param nodeService NodeService
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ThumbnailService.
|
||||
*
|
||||
* @param thumbnailService thumbnailService
|
||||
*/
|
||||
public void setThumbnailService(ThumbnailService thumbnailService)
|
||||
{
|
||||
this.thumbnailService = thumbnailService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache that aggregates renditions informaition to allow fast searching by kind and mimetype
|
||||
*/
|
||||
private class CustomRenditionsCache
|
||||
{
|
||||
private Map<CMISRenditionKind, List<CMISRendition>> renditionsByKind;
|
||||
private Map<String, List<CMISRendition>> renditionsByMimeType;
|
||||
private Map<String, List<CMISRendition>> renditionsByBaseMimeType;
|
||||
private List<CMISRendition> allRenditions;
|
||||
|
||||
public CustomRenditionsCache(List<CMISRendition> renditions)
|
||||
{
|
||||
allRenditions = renditions;
|
||||
renditionsByKind = new HashMap<CMISRenditionKind, List<CMISRendition>>(renditions.size());
|
||||
renditionsByMimeType = new HashMap<String, List<CMISRendition>>(renditions.size());
|
||||
renditionsByBaseMimeType = new HashMap<String, List<CMISRendition>>(renditions.size());
|
||||
for (CMISRendition rendition : renditions)
|
||||
{
|
||||
String baseType = getBaseType(rendition.getMimeType());
|
||||
if (!renditionsByKind.containsKey(rendition.getKind()))
|
||||
{
|
||||
renditionsByKind.put(rendition.getKind(), new ArrayList<CMISRendition>(1));
|
||||
}
|
||||
if (!renditionsByMimeType.containsKey(rendition.getMimeType()))
|
||||
{
|
||||
renditionsByMimeType.put(rendition.getMimeType(), new ArrayList<CMISRendition>(1));
|
||||
}
|
||||
if (!renditionsByBaseMimeType.containsKey(baseType))
|
||||
{
|
||||
renditionsByBaseMimeType.put(baseType, new ArrayList<CMISRendition>(1));
|
||||
}
|
||||
renditionsByKind.get(rendition.getKind()).add(rendition);
|
||||
renditionsByMimeType.get(rendition.getMimeType()).add(rendition);
|
||||
renditionsByBaseMimeType.get(baseType).add(rendition);
|
||||
}
|
||||
}
|
||||
|
||||
public List<CMISRendition> getRenditionsByKind(CMISRenditionKind kind)
|
||||
{
|
||||
return renditionsByKind.get(kind);
|
||||
}
|
||||
|
||||
public List<CMISRendition> getRenditionsByMimeType(String mimetype)
|
||||
{
|
||||
if (mimetype.endsWith(SUBTYPES_POSTFIX))
|
||||
{
|
||||
String baseMimetype = mimetype.substring(0, mimetype.length() - SUBTYPES_POSTFIX.length());
|
||||
return renditionsByBaseMimeType.get(baseMimetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
return renditionsByMimeType.get(mimetype);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<CMISRendition> getAllRenditions()
|
||||
{
|
||||
return allRenditions;
|
||||
}
|
||||
|
||||
private String getBaseType(String mimetype)
|
||||
{
|
||||
String baseMymetype = mimetype;
|
||||
int subTypeIndex = mimetype.indexOf(SUBTYPES_DELIMITER);
|
||||
if (subTypeIndex > 0 || subTypeIndex < mimetype.length())
|
||||
{
|
||||
baseMymetype = mimetype.substring(0, subTypeIndex);
|
||||
}
|
||||
return baseMymetype;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsed RenditionFilter
|
||||
*/
|
||||
private class ThumbnailFilter
|
||||
{
|
||||
private List<CMISRenditionKind> kinds = new ArrayList<CMISRenditionKind>();
|
||||
|
||||
private List<String> thumbnailNames = new ArrayList<String>();
|
||||
|
||||
private List<String> mimetypes = new ArrayList<String>();
|
||||
|
||||
private boolean any = false;
|
||||
|
||||
public List<String> getThumbnailNames()
|
||||
{
|
||||
return thumbnailNames;
|
||||
}
|
||||
|
||||
public List<String> getMimetypes()
|
||||
{
|
||||
return mimetypes;
|
||||
}
|
||||
|
||||
public List<CMISRenditionKind> getKinds()
|
||||
{
|
||||
return kinds;
|
||||
}
|
||||
|
||||
public boolean isAny()
|
||||
{
|
||||
return any;
|
||||
}
|
||||
|
||||
public void setAny(boolean any)
|
||||
{
|
||||
this.any = any;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
370
source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java
Executable file
370
source/java/org/alfresco/cmis/renditions/CMISRenditionServiceTest.java
Executable file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.cmis.renditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.cmis.CMISRendition;
|
||||
import org.alfresco.cmis.CMISRenditionKind;
|
||||
import org.alfresco.cmis.mapping.BaseCMISTest;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* @author Stas Sokolovsky
|
||||
*/
|
||||
public class CMISRenditionServiceTest extends BaseCMISTest
|
||||
{
|
||||
private static final String[] THUMBNAIL_NAMES = new String[] { "doclib", "webpreview", "imgpreview" };
|
||||
private static final CMISRenditionKind[] THUMBNAIL_KINDS = new CMISRenditionKind[] { CMISRenditionKind.THUMBNAIL, CMISRenditionKind.WEB_PREVIEW, CMISRenditionKind.WEB_PREVIEW };
|
||||
|
||||
private NodeRef document;
|
||||
private List<CMISRendition> documentRenditions = new ArrayList<CMISRendition>();
|
||||
private CMISRendition icon16Rendition = new CMISRenditionImpl(null, "alf:icon16", "image/gif", CMISRenditionKind.ICON16, 16, 16, null, null, null);
|
||||
private CMISRendition icon32Rendition = new CMISRenditionImpl(null, "alf:icon32", "image/gif", CMISRenditionKind.ICON32, 32, 32, null, null, null);
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
String documentName = "TestDocument" + System.currentTimeMillis();
|
||||
document = createDocument(documentName, "Test Content", MimetypeMap.MIMETYPE_PDF);
|
||||
|
||||
documentRenditions = new ArrayList<CMISRendition>();
|
||||
for (int i = 0; i < THUMBNAIL_NAMES.length; ++i)
|
||||
{
|
||||
documentRenditions.add(createRendition(document, THUMBNAIL_NAMES[i], THUMBNAIL_KINDS[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetAllRenditions()
|
||||
{
|
||||
List<CMISRendition> receivedRenditions = cmisRenditionService.getRenditions(document, "*");
|
||||
|
||||
List<CMISRendition> expectedRenditions = new ArrayList<CMISRendition>();
|
||||
expectedRenditions.addAll(documentRenditions);
|
||||
expectedRenditions.add(icon16Rendition);
|
||||
expectedRenditions.add(icon32Rendition);
|
||||
|
||||
assertRendiions(receivedRenditions, expectedRenditions);
|
||||
}
|
||||
|
||||
public void testGetRenditionsByKind()
|
||||
{
|
||||
testGetRenditionsByKind(CMISRenditionKind.THUMBNAIL);
|
||||
testGetRenditionsByKind(CMISRenditionKind.WEB_PREVIEW);
|
||||
testGetRenditionsByKind(CMISRenditionKind.ICON16);
|
||||
testGetRenditionsByKind(CMISRenditionKind.ICON32);
|
||||
|
||||
testGetRenditionsByKind(CMISRenditionKind.WEB_PREVIEW, CMISRenditionKind.ICON32);
|
||||
testGetRenditionsByKind(CMISRenditionKind.THUMBNAIL, CMISRenditionKind.WEB_PREVIEW, CMISRenditionKind.ICON16, CMISRenditionKind.ICON32);
|
||||
}
|
||||
|
||||
public void testGetRenditionsByMimetype()
|
||||
{
|
||||
for (CMISRendition rendition : documentRenditions)
|
||||
{
|
||||
testGetRenditionsByMimetype(rendition.getMimeType());
|
||||
}
|
||||
testGetRenditionsByMimetype(icon16Rendition.getMimeType());
|
||||
testGetRenditionsByMimetype(icon32Rendition.getMimeType());
|
||||
|
||||
String[] mimetypes = getDifferentMimetypes();
|
||||
testGetRenditionsByMimetype(mimetypes);
|
||||
}
|
||||
|
||||
public void testEmptyFilter()
|
||||
{
|
||||
List<CMISRendition> receivedRenditions = cmisRenditionService.getRenditions(document, null);
|
||||
assertTrue(receivedRenditions == null || receivedRenditions.size() == 0);
|
||||
|
||||
receivedRenditions = cmisRenditionService.getRenditions(document, "cmis:none");
|
||||
assertTrue(receivedRenditions == null || receivedRenditions.size() == 0);
|
||||
}
|
||||
|
||||
public void testRenditionsByBaseMimetype()
|
||||
{
|
||||
String[] mimetypes = getDifferentMimetypes();
|
||||
List<String> baseMimetypeFilters = new ArrayList<String>();
|
||||
for (String mimetype : mimetypes)
|
||||
{
|
||||
String baseMimetype = getBaseType(mimetype);
|
||||
String filter = baseMimetype + "/*";
|
||||
baseMimetypeFilters.add(filter);
|
||||
|
||||
testGetRenditionsByMimetype(filter);
|
||||
}
|
||||
|
||||
testGetRenditionsByMimetype(baseMimetypeFilters.toArray(new String[0]));
|
||||
}
|
||||
|
||||
public void testMixedFilter()
|
||||
{
|
||||
String[] mimetypes = getDifferentMimetypes();
|
||||
testGetRenditions(THUMBNAIL_KINDS, mimetypes);
|
||||
}
|
||||
|
||||
private void testGetRenditionsByMimetype(String... mimetypes)
|
||||
{
|
||||
testGetRenditions(null, mimetypes);
|
||||
}
|
||||
|
||||
private void testGetRenditionsByKind(CMISRenditionKind... kinds)
|
||||
{
|
||||
testGetRenditions(kinds, null);
|
||||
}
|
||||
|
||||
private void testGetRenditions(CMISRenditionKind[] kinds, String[] mimetypes)
|
||||
{
|
||||
String filter = createFilter(kinds, mimetypes);
|
||||
List<CMISRendition> receivedRenditions = cmisRenditionService.getRenditions(document, filter);
|
||||
|
||||
List<CMISRendition> expectedRenditions = new ArrayList<CMISRendition>();
|
||||
if (kinds != null)
|
||||
{
|
||||
for (CMISRenditionKind kind : kinds)
|
||||
{
|
||||
expectedRenditions.addAll(getRenditionsByKind(kind));
|
||||
}
|
||||
}
|
||||
if (mimetypes != null)
|
||||
{
|
||||
for (String mimetype : mimetypes)
|
||||
{
|
||||
expectedRenditions.addAll(getRenditionsByMimetype(mimetype));
|
||||
}
|
||||
}
|
||||
|
||||
assertRendiions(receivedRenditions, expectedRenditions);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
fileFolderService.delete(document);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private CMISRendition createRendition(NodeRef nodeRef, String thumbnailName, CMISRenditionKind kind)
|
||||
{
|
||||
ThumbnailDefinition details = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(thumbnailName);
|
||||
NodeRef thumbnailNodeRef = thumbnailService.createThumbnail(nodeRef, ContentModel.PROP_CONTENT, details.getMimetype(), details.getTransformationOptions(), details
|
||||
.getName());
|
||||
|
||||
CMISRenditionImpl rendition = new CMISRenditionImpl();
|
||||
rendition.setStreamId(thumbnailNodeRef.toString());
|
||||
rendition.setKind(kind);
|
||||
rendition.setMimeType(details.getMimetype());
|
||||
if (details.getTransformationOptions() instanceof ImageTransformationOptions)
|
||||
{
|
||||
ImageTransformationOptions imageOptions = (ImageTransformationOptions) details.getTransformationOptions();
|
||||
rendition.setWidth(imageOptions.getResizeOptions().getWidth());
|
||||
rendition.setHeight(imageOptions.getResizeOptions().getHeight());
|
||||
}
|
||||
|
||||
return rendition;
|
||||
}
|
||||
|
||||
private NodeRef createDocument(String documentName, String documentContent, String mimetype)
|
||||
{
|
||||
NodeRef textDocument = fileFolderService.create(rootNodeRef, "TEXT" + documentName, ContentModel.TYPE_CONTENT).getNodeRef();
|
||||
ContentWriter contentWriter = fileFolderService.getWriter(textDocument);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||
contentWriter.setLocale(Locale.ENGLISH);
|
||||
contentWriter.putContent(documentContent);
|
||||
ContentReader contentReader = fileFolderService.getReader(textDocument);
|
||||
|
||||
NodeRef document = fileFolderService.create(rootNodeRef, documentName, ContentModel.TYPE_CONTENT).getNodeRef();
|
||||
contentWriter = fileFolderService.getWriter(document);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(mimetype);
|
||||
contentWriter.setLocale(Locale.ENGLISH);
|
||||
|
||||
if (contentService.isTransformable(contentReader, contentWriter))
|
||||
{
|
||||
contentService.transform(contentReader, contentWriter);
|
||||
}
|
||||
|
||||
fileFolderService.delete(textDocument);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private void assertRendiions(List<CMISRendition> receivedRenditions, List<CMISRendition> expectedRenditions)
|
||||
{
|
||||
assertNotNull(receivedRenditions);
|
||||
expectedRenditions = removeReplication(expectedRenditions);
|
||||
assertTrue(receivedRenditions.size() == expectedRenditions.size());
|
||||
|
||||
for (CMISRendition rendition : receivedRenditions)
|
||||
{
|
||||
assertNotNull(rendition);
|
||||
assertNotNull(rendition.getStreamId());
|
||||
}
|
||||
|
||||
Collections.sort(receivedRenditions, renditionsComparator);
|
||||
Collections.sort(expectedRenditions, renditionsComparator);
|
||||
|
||||
for (int i = 0; i < expectedRenditions.size(); ++i)
|
||||
{
|
||||
assertRendition(receivedRenditions.get(i), expectedRenditions.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertRendition(CMISRendition receivedRendition, CMISRendition expectedRendition)
|
||||
{
|
||||
assertEquals(expectedRendition.getStreamId(), receivedRendition.getStreamId());
|
||||
assertEquals(expectedRendition.getKind(), receivedRendition.getKind());
|
||||
assertEquals(expectedRendition.getMimeType(), receivedRendition.getMimeType());
|
||||
assertEquals(expectedRendition.getWidth(), receivedRendition.getWidth());
|
||||
assertEquals(expectedRendition.getHeight(), receivedRendition.getHeight());
|
||||
}
|
||||
|
||||
private List<CMISRendition> removeReplication(List<CMISRendition> renditions)
|
||||
{
|
||||
return new ArrayList<CMISRendition>(new HashSet<CMISRendition>(renditions));
|
||||
}
|
||||
|
||||
private Comparator<CMISRendition> renditionsComparator = new Comparator<CMISRendition>()
|
||||
{
|
||||
public int compare(CMISRendition rendition1, CMISRendition rendition2)
|
||||
{
|
||||
return rendition1.getStreamId().compareTo(rendition2.getStreamId());
|
||||
}
|
||||
};
|
||||
|
||||
private List<CMISRendition> getRenditionsByKind(CMISRenditionKind kind)
|
||||
{
|
||||
return getRenditions(kind, null);
|
||||
}
|
||||
|
||||
private List<CMISRendition> getRenditionsByMimetype(String mimetype)
|
||||
{
|
||||
return getRenditions(null, mimetype);
|
||||
}
|
||||
|
||||
private List<CMISRendition> getRenditions(CMISRenditionKind kind, String mimetype)
|
||||
{
|
||||
List<CMISRendition> result = new ArrayList<CMISRendition>();
|
||||
|
||||
List<CMISRendition> allRenditions = new ArrayList<CMISRendition>(documentRenditions);
|
||||
allRenditions.add(icon16Rendition);
|
||||
allRenditions.add(icon32Rendition);
|
||||
for (CMISRendition rendition : allRenditions)
|
||||
{
|
||||
if (isRenditionSatisfyConditions(rendition, kind, mimetype))
|
||||
{
|
||||
result.add(rendition);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isRenditionSatisfyConditions(CMISRendition rendition, CMISRenditionKind kind, String mimetype)
|
||||
{
|
||||
if (kind != null)
|
||||
{
|
||||
if (!kind.equals(rendition.getKind()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mimetype != null)
|
||||
{
|
||||
if (mimetype.endsWith("/*"))
|
||||
{
|
||||
String baseMimetype = getBaseType(mimetype);
|
||||
if (!rendition.getMimeType().startsWith(baseMimetype))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!mimetype.equals(rendition.getMimeType()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String[] getDifferentMimetypes()
|
||||
{
|
||||
List<CMISRendition> allRenditions = new ArrayList<CMISRendition>(documentRenditions);
|
||||
allRenditions.add(icon16Rendition);
|
||||
allRenditions.add(icon32Rendition);
|
||||
Set<String> mimetypes = new HashSet<String>();
|
||||
for (CMISRendition rendition : allRenditions)
|
||||
{
|
||||
mimetypes.add(rendition.getMimeType());
|
||||
}
|
||||
return mimetypes.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private String getBaseType(String mimetype)
|
||||
{
|
||||
String baseMymetype = mimetype;
|
||||
int subTypeIndex = mimetype.indexOf("/");
|
||||
if (subTypeIndex > 0 || subTypeIndex < mimetype.length())
|
||||
{
|
||||
baseMymetype = mimetype.substring(0, subTypeIndex);
|
||||
}
|
||||
return baseMymetype;
|
||||
}
|
||||
|
||||
private String createFilter(CMISRenditionKind[] kinds, String[] mimetypes)
|
||||
{
|
||||
StringBuilder filter = new StringBuilder();
|
||||
if (kinds != null)
|
||||
{
|
||||
for (CMISRenditionKind kind : kinds)
|
||||
{
|
||||
filter.append(kind.getLabel());
|
||||
filter.append(",");
|
||||
}
|
||||
}
|
||||
if (mimetypes != null)
|
||||
{
|
||||
for (String mimetype : mimetypes)
|
||||
{
|
||||
filter.append(mimetype);
|
||||
filter.append(",");
|
||||
}
|
||||
}
|
||||
filter.delete(filter.length() - 1, filter.length());
|
||||
return filter.toString();
|
||||
}
|
||||
|
||||
}
|
297
source/java/org/alfresco/cmis/search/CMIS-query-test-model.xml
Normal file
297
source/java/org/alfresco/cmis/search/CMIS-query-test-model.xml
Normal file
@@ -0,0 +1,297 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- xsi:schemaLocation="http://www.alfresco.org/model/dictionary/1.0 ../../../../../../config/alfresco/model/modelSchema.xsd" -->
|
||||
<model name="test:cmis-query-test" xmlns="http://www.alfresco.org/model/dictionary/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<description>Test model the cmis query tests</description>
|
||||
<author>Alfresco</author>
|
||||
<published>2010-01-22</published>
|
||||
<version>0.1</version>
|
||||
|
||||
<imports>
|
||||
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
|
||||
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
|
||||
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/test/cmis-query-test" prefix="test"/>
|
||||
</namespaces>
|
||||
|
||||
<types>
|
||||
<type name="test:extendedContent">
|
||||
<title>Extended Content</title>
|
||||
<parent>cm:content</parent>
|
||||
<includedInSuperTypeQuery>true</includedInSuperTypeQuery>
|
||||
<properties>
|
||||
<!-- d:text -> String -->
|
||||
|
||||
<property name="test:singleTextBoth">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>both</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:singleTextUntokenised">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:singleTextTokenised">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<property name="test:multipleTextBoth">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>both</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleTextUntokenised">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleTextTokenised">
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:mltext -> String -->
|
||||
|
||||
<property name="test:singleMLTextBoth">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>both</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:singleMLTextUntokenised">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:singleMLTextTokenised">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<property name="test:multipleMLTextBoth">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>both</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleMLTextUntokenised">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleMLTextTokenised">
|
||||
<type>d:mltext</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:float -> Decimal -->
|
||||
|
||||
<property name="test:singleFloat">
|
||||
<type>d:float</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleFloat">
|
||||
<type>d:float</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true" >
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:double -> Decimal -->
|
||||
|
||||
<property name="test:singleDouble">
|
||||
<type>d:double</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleDouble">
|
||||
<type>d:double</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:int -> Integer -->
|
||||
|
||||
<property name="test:singleInteger">
|
||||
<type>d:int</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleInteger">
|
||||
<type>d:int</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:long -> Integer -->
|
||||
|
||||
<property name="test:singleLong">
|
||||
<type>d:long</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleLong">
|
||||
<type>d:long</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:boolean -> Boolean -->
|
||||
|
||||
<property name="test:singleBoolean">
|
||||
<type>d:boolean</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleBoolean">
|
||||
<type>d:boolean</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:date -> DateTime -->
|
||||
|
||||
<property name="test:singleDate">
|
||||
<type>d:date</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleDate">
|
||||
<type>d:date</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<!-- d:datetime -> DateTime -->
|
||||
|
||||
<property name="test:singleDatetime">
|
||||
<type>d:datetime</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>false</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
<property name="test:multipleDatetime">
|
||||
<type>d:datetime</type>
|
||||
<mandatory>false</mandatory>
|
||||
<multiple>true</multiple>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<tokenised>true</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="test:extendedFolder">
|
||||
<title>Extended Folder</title>
|
||||
<parent>cm:folder</parent>
|
||||
</type>
|
||||
</types>
|
||||
|
||||
</model>
|
@@ -29,13 +29,13 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.alfresco.cmis.CMISCardinalityEnum;
|
||||
import org.alfresco.cmis.CMISDataTypeEnum;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISJoinEnum;
|
||||
import org.alfresco.cmis.CMISPropertyDefinition;
|
||||
@@ -46,6 +46,8 @@ import org.alfresco.cmis.CMISTypeDefinition;
|
||||
import org.alfresco.cmis.CMISQueryOptions.CMISQueryMode;
|
||||
import org.alfresco.repo.search.impl.parsers.CMISLexer;
|
||||
import org.alfresco.repo.search.impl.parsers.CMISParser;
|
||||
import org.alfresco.repo.search.impl.parsers.FTSParser;
|
||||
import org.alfresco.repo.search.impl.parsers.FTSQueryException;
|
||||
import org.alfresco.repo.search.impl.parsers.FTSQueryParser;
|
||||
import org.alfresco.repo.search.impl.querymodel.Argument;
|
||||
import org.alfresco.repo.search.impl.querymodel.ArgumentDefinition;
|
||||
@@ -60,8 +62,10 @@ import org.alfresco.repo.search.impl.querymodel.LiteralArgument;
|
||||
import org.alfresco.repo.search.impl.querymodel.Order;
|
||||
import org.alfresco.repo.search.impl.querymodel.Ordering;
|
||||
import org.alfresco.repo.search.impl.querymodel.ParameterArgument;
|
||||
import org.alfresco.repo.search.impl.querymodel.PredicateMode;
|
||||
import org.alfresco.repo.search.impl.querymodel.PropertyArgument;
|
||||
import org.alfresco.repo.search.impl.querymodel.Query;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryModelException;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryModelFactory;
|
||||
import org.alfresco.repo.search.impl.querymodel.Selector;
|
||||
import org.alfresco.repo.search.impl.querymodel.SelectorArgument;
|
||||
@@ -97,6 +101,11 @@ import org.antlr.runtime.tree.CommonTree;
|
||||
*/
|
||||
public class CMISQueryParser
|
||||
{
|
||||
private enum EscapeMode
|
||||
{
|
||||
LITERAL, LIKE, CONTAINS;
|
||||
}
|
||||
|
||||
private CMISQueryOptions options;
|
||||
|
||||
private CMISDictionaryService cmisDictionaryService;
|
||||
@@ -105,20 +114,21 @@ public class CMISQueryParser
|
||||
|
||||
private CMISScope[] validScopes;
|
||||
|
||||
private static CMISScope[] STRICT_SCOPES = new CMISScope[] { CMISScope.DOCUMENT, CMISScope.FOLDER };
|
||||
private boolean hasScore = false;
|
||||
|
||||
private static CMISScope[] ALFRESCO_SCOPES = new CMISScope[] { CMISScope.DOCUMENT, CMISScope.FOLDER, CMISScope.POLICY };
|
||||
private boolean hasContains = false;
|
||||
|
||||
public CMISQueryParser(CMISQueryOptions options, CMISDictionaryService cmisDictionaryService, CMISJoinEnum joinSupport)
|
||||
{
|
||||
this.options = options;
|
||||
this.cmisDictionaryService = cmisDictionaryService;
|
||||
this.joinSupport = joinSupport;
|
||||
this.validScopes = (options.getQueryMode() == CMISQueryMode.CMS_STRICT) ? STRICT_SCOPES : ALFRESCO_SCOPES;
|
||||
this.validScopes = (options.getQueryMode() == CMISQueryMode.CMS_STRICT) ? CmisFunctionEvaluationContext.STRICT_SCOPES : CmisFunctionEvaluationContext.ALFRESCO_SCOPES;
|
||||
}
|
||||
|
||||
public Query parse(QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext)
|
||||
{
|
||||
|
||||
CMISParser parser = null;
|
||||
try
|
||||
{
|
||||
@@ -134,13 +144,17 @@ public class CMISQueryParser
|
||||
Map<String, Selector> selectors = source.getSelectors();
|
||||
ArrayList<Column> columns = buildColumns(queryNode, factory, selectors, options.getQuery());
|
||||
|
||||
HashSet<String> columnNames = new HashSet<String>();
|
||||
HashMap<String, Column> columnMap = new HashMap<String, Column>();
|
||||
for (Column column : columns)
|
||||
{
|
||||
if (!columnNames.add(column.getAlias()))
|
||||
if (columnMap.containsKey(column.getAlias()))
|
||||
{
|
||||
throw new CMISQueryException("Duplicate column alias for " + column.getAlias());
|
||||
}
|
||||
else
|
||||
{
|
||||
columnMap.put(column.getAlias(), column);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Ordering> orderings = buildOrderings(queryNode, factory, selectors, columns);
|
||||
@@ -149,7 +163,7 @@ public class CMISQueryParser
|
||||
CommonTree orNode = (CommonTree) queryNode.getFirstChildWithType(CMISParser.DISJUNCTION);
|
||||
if (orNode != null)
|
||||
{
|
||||
constraint = buildDisjunction(orNode, factory, functionEvaluationContext, selectors, columns);
|
||||
constraint = buildDisjunction(orNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
}
|
||||
|
||||
Query query = factory.createQuery(columns, source, constraint, orderings);
|
||||
@@ -157,6 +171,14 @@ public class CMISQueryParser
|
||||
// TODO: validate query and use of ID, function arguments matching
|
||||
// up etc
|
||||
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
if (hasScore && !hasContains)
|
||||
{
|
||||
throw new CMISQueryException("Function SCORE() used without matching CONTAINS() function");
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
catch (RecognitionException e)
|
||||
@@ -180,13 +202,13 @@ public class CMISQueryParser
|
||||
* @return
|
||||
*/
|
||||
private Constraint buildDisjunction(CommonTree orNode, QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext, Map<String, Selector> selectors,
|
||||
ArrayList<Column> columns)
|
||||
HashMap<String, Column> columnMap)
|
||||
{
|
||||
List<Constraint> constraints = new ArrayList<Constraint>(orNode.getChildCount());
|
||||
for (int i = 0; i < orNode.getChildCount(); i++)
|
||||
{
|
||||
CommonTree andNode = (CommonTree) orNode.getChild(i);
|
||||
Constraint constraint = buildConjunction(andNode, factory, functionEvaluationContext, selectors, columns);
|
||||
Constraint constraint = buildConjunction(andNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
constraints.add(constraint);
|
||||
}
|
||||
if (constraints.size() == 1)
|
||||
@@ -207,13 +229,13 @@ public class CMISQueryParser
|
||||
* @return
|
||||
*/
|
||||
private Constraint buildConjunction(CommonTree andNode, QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext, Map<String, Selector> selectors,
|
||||
ArrayList<Column> columns)
|
||||
HashMap<String, Column> columnMap)
|
||||
{
|
||||
List<Constraint> constraints = new ArrayList<Constraint>(andNode.getChildCount());
|
||||
for (int i = 0; i < andNode.getChildCount(); i++)
|
||||
{
|
||||
CommonTree notNode = (CommonTree) andNode.getChild(i);
|
||||
Constraint constraint = buildNegation(notNode, factory, functionEvaluationContext, selectors, columns);
|
||||
Constraint constraint = buildNegation(notNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
constraints.add(constraint);
|
||||
}
|
||||
if (constraints.size() == 1)
|
||||
@@ -234,17 +256,17 @@ public class CMISQueryParser
|
||||
* @return
|
||||
*/
|
||||
private Constraint buildNegation(CommonTree notNode, QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext, Map<String, Selector> selectors,
|
||||
ArrayList<Column> columns)
|
||||
HashMap<String, Column> columnMap)
|
||||
{
|
||||
if (notNode.getType() == CMISParser.NEGATION)
|
||||
{
|
||||
Constraint constraint = buildTest((CommonTree) notNode.getChild(0), factory, functionEvaluationContext, selectors, columns);
|
||||
Constraint constraint = buildTest((CommonTree) notNode.getChild(0), factory, functionEvaluationContext, selectors, columnMap);
|
||||
constraint.setOccur(Occur.EXCLUDE);
|
||||
return constraint;
|
||||
}
|
||||
else
|
||||
{
|
||||
return buildTest(notNode, factory, functionEvaluationContext, selectors, columns);
|
||||
return buildTest(notNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,15 +278,15 @@ public class CMISQueryParser
|
||||
* @return
|
||||
*/
|
||||
private Constraint buildTest(CommonTree testNode, QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext, Map<String, Selector> selectors,
|
||||
ArrayList<Column> columns)
|
||||
HashMap<String, Column> columnMap)
|
||||
{
|
||||
if (testNode.getType() == CMISParser.DISJUNCTION)
|
||||
{
|
||||
return buildDisjunction(testNode, factory, functionEvaluationContext, selectors, columns);
|
||||
return buildDisjunction(testNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
return buildPredicate(testNode, factory, functionEvaluationContext, selectors, columns);
|
||||
return buildPredicate(testNode, factory, functionEvaluationContext, selectors, columnMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +298,7 @@ public class CMISQueryParser
|
||||
* @return
|
||||
*/
|
||||
private Constraint buildPredicate(CommonTree predicateNode, QueryModelFactory factory, FunctionEvaluationContext functionEvaluationContext, Map<String, Selector> selectors,
|
||||
ArrayList<Column> columns)
|
||||
Map<String, Column> columnMap)
|
||||
{
|
||||
String functionName;
|
||||
Function function;
|
||||
@@ -290,11 +312,12 @@ public class CMISQueryParser
|
||||
function = factory.getFunction(functionName);
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Child.ARG_PARENT), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Child.ARG_PARENT), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
if (predicateNode.getChildCount() > 1)
|
||||
{
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Child.ARG_SELECTOR), factory, selectors);
|
||||
argNode = (CommonTree) predicateNode.getChild(1);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Child.ARG_SELECTOR), factory, selectors, columnMap, false);
|
||||
if (!arg.isQueryable())
|
||||
{
|
||||
throw new CMISQueryException("The property is not queryable: " + argNode.getText());
|
||||
@@ -303,6 +326,7 @@ public class CMISQueryParser
|
||||
}
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
case CMISParser.PRED_COMPARISON:
|
||||
|
||||
switch (predicateNode.getChild(2).getType())
|
||||
{
|
||||
case CMISParser.EQUALS:
|
||||
@@ -333,23 +357,28 @@ public class CMISQueryParser
|
||||
throw new CMISQueryException("Unknown comparison function " + predicateNode.getChild(2).getText());
|
||||
}
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(BaseComparison.ARG_MODE), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
argNode = (CommonTree) predicateNode.getChild(1);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(BaseComparison.ARG_LHS), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(BaseComparison.ARG_LHS), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
argNode = (CommonTree) predicateNode.getChild(3);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(BaseComparison.ARG_RHS), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(BaseComparison.ARG_RHS), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
checkPredicateConditionsForComparisons(function, functionArguments, functionEvaluationContext, columnMap);
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
case CMISParser.PRED_DESCENDANT:
|
||||
functionName = Descendant.NAME;
|
||||
function = factory.getFunction(functionName);
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Descendant.ARG_ANCESTOR), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Descendant.ARG_ANCESTOR), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
if (predicateNode.getChildCount() > 1)
|
||||
{
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Descendant.ARG_SELECTOR), factory, selectors);
|
||||
argNode = (CommonTree) predicateNode.getChild(1);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Descendant.ARG_SELECTOR), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
}
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
@@ -358,14 +387,23 @@ public class CMISQueryParser
|
||||
function = factory.getFunction(functionName);
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Exists.ARG_PROPERTY), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Exists.ARG_PROPERTY), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
arg = factory.createLiteralArgument(Exists.ARG_NOT, DataTypeDefinition.BOOLEAN, (predicateNode.getChildCount() > 1));
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
// Applies to both single valued and multi-valued properties - no checks required
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
case CMISParser.PRED_FTS:
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
if (hasContains)
|
||||
{
|
||||
throw new CMISQueryException("Only one CONTAINS() function can be included in a single query statement.");
|
||||
}
|
||||
}
|
||||
String ftsExpression = predicateNode.getChild(0).getText();
|
||||
FTSQueryParser ftsQueryParser = new FTSQueryParser();
|
||||
ftsExpression = ftsExpression.substring(1, ftsExpression.length() - 1);
|
||||
ftsExpression = unescape(ftsExpression, EscapeMode.CONTAINS);
|
||||
Selector selector;
|
||||
if (predicateNode.getChildCount() > 1)
|
||||
{
|
||||
@@ -399,42 +437,253 @@ public class CMISQueryParser
|
||||
defaultConnective = options.getDefaultFTSConnective();
|
||||
defaultFieldConnective = options.getDefaultFTSFieldConnective();
|
||||
}
|
||||
return ftsQueryParser.buildFTS(ftsExpression.substring(1, ftsExpression.length() - 1), factory, functionEvaluationContext, selector, columns, defaultConnective,
|
||||
defaultFieldConnective, null, options.getDefaultFieldName());
|
||||
FTSParser.Mode mode;
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
mode = FTSParser.Mode.CMIS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defaultConnective == Connective.AND)
|
||||
{
|
||||
mode = FTSParser.Mode.DEFAULT_CONJUNCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = FTSParser.Mode.DEFAULT_DISJUNCTION;
|
||||
}
|
||||
}
|
||||
Constraint ftsConstraint = FTSQueryParser.buildFTS(ftsExpression, factory, functionEvaluationContext, selector, columnMap, mode, defaultFieldConnective, null, options.getDefaultFieldName());
|
||||
ftsConstraint.setBoost(1000.0f);
|
||||
hasContains = true;
|
||||
return ftsConstraint;
|
||||
case CMISParser.PRED_IN:
|
||||
functionName = In.NAME;
|
||||
function = factory.getFunction(functionName);
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_MODE), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_MODE), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
argNode = (CommonTree) predicateNode.getChild(1);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_PROPERTY), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_PROPERTY), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
argNode = (CommonTree) predicateNode.getChild(2);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_LIST), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(In.ARG_LIST), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
arg = factory.createLiteralArgument(In.ARG_NOT, DataTypeDefinition.BOOLEAN, (predicateNode.getChildCount() > 3));
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
checkPredicateConditionsForIn(functionArguments, functionEvaluationContext, columnMap);
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
case CMISParser.PRED_LIKE:
|
||||
functionName = Like.NAME;
|
||||
function = factory.getFunction(functionName);
|
||||
functionArguments = new LinkedHashMap<String, Argument>();
|
||||
argNode = (CommonTree) predicateNode.getChild(0);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Like.ARG_PROPERTY), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Like.ARG_PROPERTY), factory, selectors, columnMap, false);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
argNode = (CommonTree) predicateNode.getChild(1);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Like.ARG_EXP), factory, selectors);
|
||||
arg = getFunctionArgument(argNode, function.getArgumentDefinition(Like.ARG_EXP), factory, selectors, columnMap, true);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
arg = factory.createLiteralArgument(Like.ARG_NOT, DataTypeDefinition.BOOLEAN, (predicateNode.getChildCount() > 2));
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
checkPredicateConditionsForLike(functionArguments, functionEvaluationContext, columnMap);
|
||||
return factory.createFunctionalConstraint(function, functionArguments);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPredicateConditionsForIn(Map<String, Argument> functionArguments, FunctionEvaluationContext functionEvaluationContext, Map<String, Column> columnMap)
|
||||
{
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
PropertyArgument propertyArgument = (PropertyArgument) functionArguments.get(In.ARG_PROPERTY);
|
||||
LiteralArgument modeArgument = (LiteralArgument) functionArguments.get(In.ARG_MODE);
|
||||
String modeString = DefaultTypeConverter.INSTANCE.convert(String.class, modeArgument.getValue(functionEvaluationContext));
|
||||
PredicateMode mode = PredicateMode.valueOf(modeString);
|
||||
String propertyName = propertyArgument.getPropertyName();
|
||||
|
||||
Column column = columnMap.get(propertyName);
|
||||
if (column != null)
|
||||
{
|
||||
// check for function type
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
propertyName = arg.getPropertyName();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CMISQueryException("Complex column reference not supoprted in LIKE " + propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isMultiValued = functionEvaluationContext.isMultiValued(propertyName);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ANY:
|
||||
if (isMultiValued)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryModelException("Predicate mode " + PredicateMode.ANY + " is not supported for IN and single valued properties");
|
||||
}
|
||||
case SINGLE_VALUED_PROPERTY:
|
||||
if (isMultiValued)
|
||||
{
|
||||
throw new QueryModelException("Predicate mode " + PredicateMode.SINGLE_VALUED_PROPERTY + " is not supported for IN and multi-valued properties");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new QueryModelException("Unsupported predicate mode " + mode);
|
||||
}
|
||||
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(propertyName);
|
||||
if (propDef.getDataType() == CMISDataTypeEnum.BOOLEAN)
|
||||
{
|
||||
|
||||
throw new QueryModelException("In is not supported for properties of type Boolean");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkPredicateConditionsForComparisons(Function function, Map<String, Argument> functionArguments, FunctionEvaluationContext functionEvaluationContext,
|
||||
Map<String, Column> columnMap)
|
||||
{
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
((BaseComparison) function).setPropertyAndStaticArguments(functionArguments);
|
||||
String propertyName = ((BaseComparison) function).getPropertyName();
|
||||
LiteralArgument modeArgument = (LiteralArgument) functionArguments.get(BaseComparison.ARG_MODE);
|
||||
String modeString = DefaultTypeConverter.INSTANCE.convert(String.class, modeArgument.getValue(functionEvaluationContext));
|
||||
PredicateMode mode = PredicateMode.valueOf(modeString);
|
||||
|
||||
Column column = columnMap.get(propertyName);
|
||||
if (column != null)
|
||||
{
|
||||
// check for function type
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
propertyName = arg.getPropertyName();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CMISQueryException("Complex column reference not supoprted in LIKE " + propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isMultiValued = functionEvaluationContext.isMultiValued(propertyName);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ANY:
|
||||
if (isMultiValued)
|
||||
{
|
||||
if (function.getName().equals(Equals.NAME))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryModelException("Predicate mode " + PredicateMode.ANY + " is only supported for " + Equals.NAME + " (and multi-valued properties).");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryModelException("Predicate mode " + PredicateMode.ANY + " is not supported for " + function.getName() + " and single valued properties");
|
||||
}
|
||||
case SINGLE_VALUED_PROPERTY:
|
||||
if (isMultiValued)
|
||||
{
|
||||
throw new QueryModelException("Predicate mode "
|
||||
+ PredicateMode.SINGLE_VALUED_PROPERTY + " is not supported for " + function.getName() + " and multi-valued properties");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new QueryModelException("Unsupported predicate mode " + mode);
|
||||
}
|
||||
|
||||
// limit support for ID and Boolean
|
||||
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(propertyName);
|
||||
if (propDef.getDataType() == CMISDataTypeEnum.ID)
|
||||
{
|
||||
if (function.getName().equals(Equals.NAME) || function.getName().equals(NotEquals.NAME))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryModelException("Comparison " + function.getName() + " is not supported for properties of type ID");
|
||||
}
|
||||
}
|
||||
else if (propDef.getDataType() == CMISDataTypeEnum.BOOLEAN)
|
||||
{
|
||||
if (function.getName().equals(Equals.NAME))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryModelException("Comparison " + function.getName() + " is not supported for properties of type Boolean");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkPredicateConditionsForLike(Map<String, Argument> functionArguments, FunctionEvaluationContext functionEvaluationContext, Map<String, Column> columnMap)
|
||||
{
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
PropertyArgument propertyArgument = (PropertyArgument) functionArguments.get(Like.ARG_PROPERTY);
|
||||
|
||||
boolean isMultiValued = functionEvaluationContext.isMultiValued(propertyArgument.getPropertyName());
|
||||
|
||||
if (isMultiValued)
|
||||
{
|
||||
throw new QueryModelException("Like is not supported for multi-valued properties");
|
||||
}
|
||||
|
||||
String cmisPropertyName = propertyArgument.getPropertyName();
|
||||
|
||||
Column column = columnMap.get(cmisPropertyName);
|
||||
if (column != null)
|
||||
{
|
||||
// check for function type
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
cmisPropertyName = arg.getPropertyName();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CMISQueryException("Complex column reference not supoprted in LIKE " + cmisPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(cmisPropertyName);
|
||||
if (propDef.getDataType() != CMISDataTypeEnum.STRING)
|
||||
{
|
||||
throw new CMISQueryException("LIKE is only supported against String types" + cmisPropertyName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param queryNode
|
||||
* @param factory
|
||||
@@ -480,6 +729,16 @@ public class CMISQueryParser
|
||||
match = column;
|
||||
break;
|
||||
}
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
String propertyName = arg.getPropertyName();
|
||||
if (propertyName.equals(columnName))
|
||||
{
|
||||
match = column;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// in strict mode the ordered column must be selected
|
||||
if ((options.getQueryMode() == CMISQueryMode.CMS_STRICT) && (match == null))
|
||||
@@ -513,6 +772,13 @@ public class CMISQueryParser
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + "." + columnName);
|
||||
}
|
||||
|
||||
// Check column/property applies to selector/type
|
||||
|
||||
if (!typeDef.getPropertyDefinitions().containsKey(propDef.getPropertyId().getId()))
|
||||
{
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + "." + columnName);
|
||||
}
|
||||
|
||||
// check there is a matching selector
|
||||
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
@@ -639,8 +905,6 @@ public class CMISQueryParser
|
||||
}
|
||||
Map<String, CMISPropertyDefinition> propDefs = typeDef.getPropertyDefinitions();
|
||||
for (CMISPropertyDefinition definition : propDefs.values())
|
||||
{
|
||||
if (definition.getCardinality() == CMISCardinalityEnum.SINGLE_VALUED)
|
||||
{
|
||||
Function function = factory.getFunction(PropertyAccessor.NAME);
|
||||
Argument arg = factory.createPropertyArgument(PropertyAccessor.ARG_PROPERTY, definition.isQueryable(), definition.isOrderable(), selector.getAlias(),
|
||||
@@ -656,7 +920,6 @@ public class CMISQueryParser
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CommonTree columnsNode = (CommonTree) queryNode.getFirstChildWithType(CMISParser.COLUMNS);
|
||||
if (columnsNode != null)
|
||||
@@ -686,8 +949,6 @@ public class CMISQueryParser
|
||||
}
|
||||
Map<String, CMISPropertyDefinition> propDefs = typeDef.getPropertyDefinitions();
|
||||
for (CMISPropertyDefinition definition : propDefs.values())
|
||||
{
|
||||
if (definition.getCardinality() == CMISCardinalityEnum.SINGLE_VALUED)
|
||||
{
|
||||
Function function = factory.getFunction(PropertyAccessor.NAME);
|
||||
Argument arg = factory.createPropertyArgument(PropertyAccessor.ARG_PROPERTY, definition.isQueryable(), definition.isOrderable(), selector.getAlias(),
|
||||
@@ -702,7 +963,6 @@ public class CMISQueryParser
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (columnNode.getType() == CMISParser.COLUMN)
|
||||
{
|
||||
@@ -735,6 +995,13 @@ public class CMISQueryParser
|
||||
}
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(columnName);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + " " + columnName);
|
||||
}
|
||||
|
||||
// Check column/property applies to selector/type
|
||||
|
||||
if (!typeDef.getPropertyDefinitions().containsKey(propDef.getPropertyId().getId()))
|
||||
{
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + "." + columnName);
|
||||
}
|
||||
@@ -780,7 +1047,7 @@ public class CMISQueryParser
|
||||
if (functionNode.getChildCount() > childIndex + 1)
|
||||
{
|
||||
CommonTree argNode = (CommonTree) functionNode.getChild(childIndex++);
|
||||
Argument arg = getFunctionArgument(argNode, definition, factory, selectors);
|
||||
Argument arg = getFunctionArgument(argNode, definition, factory, selectors, null, function.getName().equals(Like.NAME));
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
}
|
||||
else
|
||||
@@ -806,6 +1073,11 @@ public class CMISQueryParser
|
||||
int start = getStringPosition(query, functionNode.getLine(), functionNode.getCharPositionInLine());
|
||||
int end = getStringPosition(query, rparenNode.getLine(), rparenNode.getCharPositionInLine());
|
||||
|
||||
if (function.getName().equals(Score.NAME))
|
||||
{
|
||||
hasScore = true;
|
||||
}
|
||||
|
||||
String alias;
|
||||
if (function.getName().equals(Score.NAME))
|
||||
{
|
||||
@@ -860,11 +1132,12 @@ public class CMISQueryParser
|
||||
return position + charPositionInLine;
|
||||
}
|
||||
|
||||
private Argument getFunctionArgument(CommonTree argNode, ArgumentDefinition definition, QueryModelFactory factory, Map<String, Selector> selectors)
|
||||
private Argument getFunctionArgument(CommonTree argNode, ArgumentDefinition definition, QueryModelFactory factory, Map<String, Selector> selectors,
|
||||
Map<String, Column> columnMap, boolean inLike)
|
||||
{
|
||||
if (argNode.getType() == CMISParser.COLUMN_REF)
|
||||
{
|
||||
PropertyArgument arg = buildColumnReference(definition.getName(), argNode, factory);
|
||||
PropertyArgument arg = buildColumnReference(definition.getName(), argNode, factory, selectors, columnMap);
|
||||
if (!arg.isQueryable())
|
||||
{
|
||||
throw new CMISQueryException("Column refers to unqueryable property " + arg.getPropertyName());
|
||||
@@ -943,6 +1216,7 @@ public class CMISQueryParser
|
||||
{
|
||||
String text = argNode.getChild(0).getText();
|
||||
text = text.substring(1, text.length() - 1);
|
||||
text = unescape(text, inLike ? EscapeMode.LIKE : EscapeMode.LITERAL);
|
||||
LiteralArgument arg = factory.createLiteralArgument(definition.getName(), DataTypeDefinition.TEXT, text);
|
||||
return arg;
|
||||
}
|
||||
@@ -1003,7 +1277,7 @@ public class CMISQueryParser
|
||||
for (int i = 0; i < argNode.getChildCount(); i++)
|
||||
{
|
||||
CommonTree arg = (CommonTree) argNode.getChild(i);
|
||||
arguments.add(getFunctionArgument(arg, definition, factory, selectors));
|
||||
arguments.add(getFunctionArgument(arg, definition, factory, selectors, columnMap, inLike));
|
||||
}
|
||||
ListArgument arg = factory.createListArgument(definition.getName(), arguments);
|
||||
if (!arg.isQueryable())
|
||||
@@ -1017,6 +1291,11 @@ public class CMISQueryParser
|
||||
LiteralArgument arg = factory.createLiteralArgument(definition.getName(), DataTypeDefinition.TEXT, argNode.getText());
|
||||
return arg;
|
||||
}
|
||||
else if (argNode.getType() == CMISParser.SINGLE_VALUED_PROPERTY)
|
||||
{
|
||||
LiteralArgument arg = factory.createLiteralArgument(definition.getName(), DataTypeDefinition.TEXT, argNode.getText());
|
||||
return arg;
|
||||
}
|
||||
else if (argNode.getType() == CMISParser.NOT)
|
||||
{
|
||||
LiteralArgument arg = factory.createLiteralArgument(definition.getName(), DataTypeDefinition.TEXT, argNode.getText());
|
||||
@@ -1039,7 +1318,7 @@ public class CMISQueryParser
|
||||
if (argNode.getChildCount() > childIndex + 1)
|
||||
{
|
||||
CommonTree currentArgNode = (CommonTree) argNode.getChild(childIndex++);
|
||||
Argument arg = getFunctionArgument(currentArgNode, currentDefinition, factory, selectors);
|
||||
Argument arg = getFunctionArgument(currentArgNode, currentDefinition, factory, selectors, columnMap, inLike);
|
||||
functionArguments.put(arg.getName(), arg);
|
||||
}
|
||||
else
|
||||
@@ -1110,14 +1389,6 @@ public class CMISQueryParser
|
||||
throw new CMISQueryException("Type is not queryable " + tableName + " -> " + typeDef.getTypeId());
|
||||
}
|
||||
}
|
||||
// check sub types all include in super type query
|
||||
for(CMISTypeDefinition subType : typeDef.getSubTypes(true))
|
||||
{
|
||||
if(!subType.isIncludeInSuperTypeQuery())
|
||||
{
|
||||
throw new CMISQueryException("includeInSuperTypeQuery=falss is not support for "+tableName+ " descendant type "+subType.getQueryName());
|
||||
}
|
||||
}
|
||||
return factory.createSelector(typeDef.getTypeId().getQName(), alias);
|
||||
}
|
||||
else
|
||||
@@ -1149,14 +1420,7 @@ public class CMISQueryParser
|
||||
throw new CMISQueryException("Type is not queryable " + tableName + " -> " + typeDef.getTypeId());
|
||||
}
|
||||
}
|
||||
// check sub types all include in super type query
|
||||
for(CMISTypeDefinition subType : typeDef.getSubTypes(true))
|
||||
{
|
||||
if(!subType.isIncludeInSuperTypeQuery())
|
||||
{
|
||||
throw new CMISQueryException("includeInSuperTypeQuery=falss is not support for "+tableName+ " descendant type "+subType.getQueryName());
|
||||
}
|
||||
}
|
||||
|
||||
Source lhs = factory.createSelector(typeDef.getTypeId().getQName(), alias);
|
||||
|
||||
List<CommonTree> list = (List<CommonTree>) (source.getChildren());
|
||||
@@ -1183,7 +1447,7 @@ public class CMISQueryParser
|
||||
CommonTree joinConditionNode = (CommonTree) joinNode.getFirstChildWithType(CMISParser.ON);
|
||||
if (joinConditionNode != null)
|
||||
{
|
||||
PropertyArgument arg1 = buildColumnReference(Equals.ARG_LHS, (CommonTree) joinConditionNode.getChild(0), factory);
|
||||
PropertyArgument arg1 = buildColumnReference(Equals.ARG_LHS, (CommonTree) joinConditionNode.getChild(0), factory, null, null);
|
||||
if (!lhs.getSelectors().containsKey(arg1.getSelector()) && !rhs.getSelectors().containsKey(arg1.getSelector()))
|
||||
{
|
||||
throw new CMISQueryException("No table with alias " + arg1.getSelector());
|
||||
@@ -1198,7 +1462,7 @@ public class CMISQueryParser
|
||||
{
|
||||
throw new CMISQueryException("Unknown function: " + functionNameNode.getText());
|
||||
}
|
||||
PropertyArgument arg2 = buildColumnReference(Equals.ARG_RHS, (CommonTree) joinConditionNode.getChild(2), factory);
|
||||
PropertyArgument arg2 = buildColumnReference(Equals.ARG_RHS, (CommonTree) joinConditionNode.getChild(2), factory, null, null);
|
||||
if (!lhs.getSelectors().containsKey(arg2.getSelector()) && !rhs.getSelectors().containsKey(arg2.getSelector()))
|
||||
{
|
||||
throw new CMISQueryException("No table with alias " + arg2.getSelector());
|
||||
@@ -1219,27 +1483,193 @@ public class CMISQueryParser
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyArgument buildColumnReference(String argumentName, CommonTree columnReferenceNode, QueryModelFactory factory)
|
||||
public PropertyArgument buildColumnReference(String argumentName, CommonTree columnReferenceNode, QueryModelFactory factory, Map<String, Selector> selectors,
|
||||
Map<String, Column> columnMap)
|
||||
{
|
||||
String cmisPropertyName = columnReferenceNode.getChild(0).getText();
|
||||
String qualifer = "";
|
||||
String qualifier = "";
|
||||
if (columnReferenceNode.getChildCount() > 1)
|
||||
{
|
||||
qualifer = columnReferenceNode.getChild(1).getText();
|
||||
qualifier = columnReferenceNode.getChild(1).getText();
|
||||
}
|
||||
|
||||
if ((qualifier == "") && (columnMap != null))
|
||||
{
|
||||
Column column = columnMap.get(cmisPropertyName);
|
||||
if (column != null)
|
||||
{
|
||||
// check for function type
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
cmisPropertyName = arg.getPropertyName();
|
||||
qualifier = arg.getSelector();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: should be able to return non property arguments
|
||||
// The implementation should throw out what it can not support at build time.
|
||||
throw new CMISQueryException("Complex column reference unsupported (only direct column references are currently supported) " + cmisPropertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(cmisPropertyName);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Unknown column/property " + cmisPropertyName);
|
||||
}
|
||||
|
||||
if (selectors != null)
|
||||
{
|
||||
Selector selector = selectors.get(qualifier);
|
||||
if (selector == null)
|
||||
{
|
||||
if ((qualifier.equals("")) && (selectors.size() == 1))
|
||||
{
|
||||
selector = selectors.get(selectors.keySet().iterator().next());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CMISQueryException("No selector for " + qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(selector.getType(), validScopes);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Type unsupported in CMIS queries: " + selector.getAlias());
|
||||
}
|
||||
|
||||
// Check column/property applies to selector/type
|
||||
|
||||
if (!typeDef.getPropertyDefinitions().containsKey(propDef.getPropertyId().getId()))
|
||||
{
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + "." + cmisPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
if (!propDef.isQueryable())
|
||||
{
|
||||
throw new CMISQueryException("Column is not queryable " + qualifer + "." + cmisPropertyName);
|
||||
throw new CMISQueryException("Column is not queryable " + qualifier + "." + cmisPropertyName);
|
||||
}
|
||||
}
|
||||
return factory.createPropertyArgument(argumentName, propDef.isQueryable(), propDef.isOrderable(), qualifer, propDef.getPropertyId().getId());
|
||||
return factory.createPropertyArgument(argumentName, propDef.isQueryable(), propDef.isOrderable(), qualifier, propDef.getPropertyId().getId());
|
||||
}
|
||||
|
||||
private String unescape(String string, EscapeMode mode)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(string.length());
|
||||
|
||||
boolean lastWasEscape = false;
|
||||
|
||||
for (int i = 0; i < string.length(); i++)
|
||||
{
|
||||
char c = string.charAt(i);
|
||||
if (lastWasEscape)
|
||||
{
|
||||
|
||||
// Need to keep escaping for like as we have the same escaping
|
||||
if (mode == EscapeMode.LIKE)
|
||||
{
|
||||
// Like does its own escaping - so pass through \ % and _
|
||||
if (c == '\'')
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
else if (c == '%')
|
||||
{
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
}
|
||||
else if (c == '_')
|
||||
{
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnsupportedOperationException("Unsupported escape pattern in <" + string + "> at position " + i);
|
||||
}
|
||||
}
|
||||
else if (mode == EscapeMode.CONTAINS)
|
||||
{
|
||||
if (options.getQueryMode() == CMISQueryMode.CMS_STRICT)
|
||||
{
|
||||
if (c == '\'')
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
throw new UnsupportedOperationException("Unsupported escape pattern in <" + string + "> at position " + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '\'')
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mode == EscapeMode.LITERAL)
|
||||
{
|
||||
if (c == '\'')
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnsupportedOperationException("Unsupported escape pattern in <" + string + "> at position " + i);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnsupportedOperationException("Unsupported escape pattern in <" + string + "> at position " + i);
|
||||
|
||||
}
|
||||
lastWasEscape = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '\\')
|
||||
{
|
||||
lastWasEscape = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastWasEscape)
|
||||
{
|
||||
throw new FTSQueryException("Escape character at end of string " + string);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,9 @@ import org.alfresco.cmis.CMISQueryEnum;
|
||||
import org.alfresco.cmis.CMISQueryOptions;
|
||||
import org.alfresco.cmis.CMISQueryService;
|
||||
import org.alfresco.cmis.CMISResultSet;
|
||||
import org.alfresco.cmis.CMISScope;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.cmis.CMISQueryOptions.CMISQueryMode;
|
||||
import org.alfresco.repo.search.impl.querymodel.Query;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryEngine;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryEngineResults;
|
||||
@@ -117,9 +119,13 @@ public class CMISQueryServiceImpl implements CMISQueryService
|
||||
joinSupport = CMISJoinEnum.INNER_JOIN_SUPPORT;
|
||||
}
|
||||
|
||||
// TODO: Refactor to avoid duplication of valid scopes here and in CMISQueryParser
|
||||
|
||||
CMISScope[] validScopes = (options.getQueryMode() == CMISQueryMode.CMS_STRICT) ? CmisFunctionEvaluationContext.STRICT_SCOPES : CmisFunctionEvaluationContext.ALFRESCO_SCOPES;
|
||||
CmisFunctionEvaluationContext functionContext = new CmisFunctionEvaluationContext();
|
||||
functionContext.setCmisDictionaryService(cmisDictionaryService);
|
||||
functionContext.setNodeService(nodeService);
|
||||
functionContext.setValidScopes(validScopes);
|
||||
|
||||
CMISQueryParser parser = new CMISQueryParser(options, cmisDictionaryService, joinSupport);
|
||||
Query query = parser.parse(queryEngine.getQueryModelFactory(), functionContext);
|
||||
|
@@ -25,7 +25,6 @@
|
||||
package org.alfresco.cmis.search;
|
||||
|
||||
import org.alfresco.cmis.CMISDataTypeEnum;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISPropertyDefinition;
|
||||
import org.alfresco.cmis.CMISResultSetColumn;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
@@ -43,7 +43,6 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.search.LimitBy;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||
|
||||
@@ -79,7 +78,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#close()
|
||||
*/
|
||||
public void close()
|
||||
@@ -98,7 +96,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#getMetaData()
|
||||
*/
|
||||
public CMISResultSetMetaData getMetaData()
|
||||
@@ -108,7 +105,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#getRow(int)
|
||||
*/
|
||||
public CMISResultSetRow getRow(int i)
|
||||
@@ -118,7 +114,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#hasMore()
|
||||
*/
|
||||
public boolean hasMore()
|
||||
@@ -135,7 +130,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#length()
|
||||
*/
|
||||
public int getLength()
|
||||
@@ -149,7 +143,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSet#start()
|
||||
*/
|
||||
public int getStart()
|
||||
@@ -159,7 +152,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<CMISResultSetRow> iterator()
|
||||
@@ -212,12 +204,35 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
{
|
||||
return refs.values().iterator().next();
|
||||
}
|
||||
else
|
||||
else if(allNodeRefsEqual(refs))
|
||||
{
|
||||
return refs.values().iterator().next();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Ambiguous selector");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allNodeRefsEqual(Map<String, NodeRef> selected)
|
||||
{
|
||||
NodeRef last = null;
|
||||
for (NodeRef current : selected.values())
|
||||
{
|
||||
if (last == null)
|
||||
{
|
||||
last = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!last.equals(current))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<NodeRef> getNodeRefs()
|
||||
{
|
||||
ArrayList<NodeRef> nodeRefs = new ArrayList<NodeRef>(length());
|
||||
@@ -240,12 +255,36 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
||||
{
|
||||
return scores.values().iterator().next();
|
||||
}
|
||||
else if(allScoresEqual(scores))
|
||||
{
|
||||
return scores.values().iterator().next();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("Ambiguous selector");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allScoresEqual(Map<String, Float> scores)
|
||||
{
|
||||
Float last = null;
|
||||
for (Float current : scores.values())
|
||||
{
|
||||
if (last == null)
|
||||
{
|
||||
last = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!last.equals(current))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int length()
|
||||
{
|
||||
return getLength();
|
||||
|
@@ -33,7 +33,9 @@ import org.alfresco.cmis.CMISResultSet;
|
||||
import org.alfresco.cmis.CMISResultSetMetaData;
|
||||
import org.alfresco.cmis.CMISResultSetRow;
|
||||
import org.alfresco.repo.search.impl.querymodel.Column;
|
||||
import org.alfresco.repo.search.impl.querymodel.PropertyArgument;
|
||||
import org.alfresco.repo.search.impl.querymodel.Query;
|
||||
import org.alfresco.repo.search.impl.querymodel.impl.functions.PropertyAccessor;
|
||||
import org.alfresco.repo.search.results.ResultSetSPIWrapper;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -66,7 +68,8 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
private CMISDictionaryService cmisDictionaryService;
|
||||
|
||||
public CMISResultSetRowImpl(CMISResultSet resultSet, int index, Map<String, Float> scores, NodeService nodeService, Map<String, NodeRef> nodeRefs, Query query, CMISDictionaryService cmisDictionaryService)
|
||||
public CMISResultSetRowImpl(CMISResultSet resultSet, int index, Map<String, Float> scores, NodeService nodeService, Map<String, NodeRef> nodeRefs, Query query,
|
||||
CMISDictionaryService cmisDictionaryService)
|
||||
{
|
||||
this.resultSet = resultSet;
|
||||
this.index = index;
|
||||
@@ -79,7 +82,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getIndex()
|
||||
*/
|
||||
public int getIndex()
|
||||
@@ -89,7 +91,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getResultSet()
|
||||
*/
|
||||
public ResultSet getResultSet()
|
||||
@@ -99,7 +100,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getScore()
|
||||
*/
|
||||
public float getScore()
|
||||
@@ -115,7 +115,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getScore(java.lang.String)
|
||||
*/
|
||||
public float getScore(String selectorName)
|
||||
@@ -125,7 +124,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getScores()
|
||||
*/
|
||||
public Map<String, Float> getScores()
|
||||
@@ -135,7 +133,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getScore(java.lang.String)
|
||||
*/
|
||||
public NodeRef getNodeRef(String selectorName)
|
||||
@@ -145,7 +142,6 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getScores()
|
||||
*/
|
||||
public Map<String, NodeRef> getNodeRefs()
|
||||
@@ -155,14 +151,9 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getValue(java.lang.String)
|
||||
*/
|
||||
public Serializable getValue(String columnName)
|
||||
{
|
||||
for (Column column : query.getColumns())
|
||||
{
|
||||
if (column.getAlias().equals(columnName))
|
||||
{
|
||||
CmisFunctionEvaluationContext context = new CmisFunctionEvaluationContext();
|
||||
context.setCmisDictionaryService(cmisDictionaryService);
|
||||
@@ -170,15 +161,55 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
context.setNodeService(nodeService);
|
||||
context.setScores(scores);
|
||||
context.setScore(getScore());
|
||||
for (Column column : query.getColumns())
|
||||
{
|
||||
if (column.getAlias().equals(columnName))
|
||||
{
|
||||
return column.getFunction().getValue(column.getFunctionArguments(), context);
|
||||
}
|
||||
// Special case for one selector - ignore any table aliases
|
||||
// also allows look up direct and not by alias
|
||||
// Perhaps we should add the duplicates instead
|
||||
// TODO: check SQL 92 for single alias table behaviour for selectors
|
||||
if (nodeRefs.size() == 1)
|
||||
{
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
String propertyName = arg.getPropertyName();
|
||||
if (propertyName.equals(columnName))
|
||||
{
|
||||
return column.getFunction().getValue(column.getFunctionArguments(), context);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(arg.getSelector()).append(".").append(propertyName);
|
||||
propertyName = builder.toString();
|
||||
if (propertyName.equals(columnName))
|
||||
{
|
||||
return column.getFunction().getValue(column.getFunctionArguments(), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (column.getFunction().getName().equals(PropertyAccessor.NAME))
|
||||
{
|
||||
PropertyArgument arg = (PropertyArgument) column.getFunctionArguments().get(PropertyAccessor.ARG_PROPERTY);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(arg.getSelector()).append(".").append(arg.getPropertyName());
|
||||
String propertyName = builder.toString();
|
||||
if (propertyName.equals(columnName))
|
||||
{
|
||||
return column.getFunction().getValue(column.getFunctionArguments(), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.cmis.search.CMISResultSetRow#getValues()
|
||||
*/
|
||||
public Map<String, Serializable> getValues()
|
||||
@@ -208,9 +239,33 @@ public class CMISResultSetRowImpl implements CMISResultSetRow
|
||||
{
|
||||
return nodeRefs.values().iterator().next();
|
||||
}
|
||||
else if(allNodeRefsEqual(nodeRefs))
|
||||
{
|
||||
return nodeRefs.values().iterator().next();
|
||||
}
|
||||
throw new UnsupportedOperationException("Ambiguous selector");
|
||||
}
|
||||
|
||||
private boolean allNodeRefsEqual(Map<String, NodeRef> selected)
|
||||
{
|
||||
NodeRef last = null;
|
||||
for(NodeRef current : selected.values())
|
||||
{
|
||||
if(last == null)
|
||||
{
|
||||
last = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!last.equals(current))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public QName getQName()
|
||||
{
|
||||
return getChildAssocRef().getQName();
|
||||
|
@@ -28,15 +28,20 @@ import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.cmis.CMISCardinalityEnum;
|
||||
import org.alfresco.cmis.CMISDictionaryModel;
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISPropertyDefinition;
|
||||
import org.alfresco.cmis.CMISQueryException;
|
||||
import org.alfresco.cmis.CMISScope;
|
||||
import org.alfresco.cmis.CMISTypeDefinition;
|
||||
import org.alfresco.repo.search.impl.lucene.LuceneFunction;
|
||||
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
|
||||
import org.alfresco.repo.search.impl.querymodel.FunctionArgument;
|
||||
import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext;
|
||||
import org.alfresco.repo.search.impl.querymodel.PredicateMode;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryModelException;
|
||||
import org.alfresco.repo.search.impl.querymodel.Selector;
|
||||
import org.alfresco.repo.search.impl.querymodel.impl.functions.Lower;
|
||||
import org.alfresco.repo.search.impl.querymodel.impl.functions.Upper;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -49,6 +54,10 @@ import org.apache.lucene.search.Query;
|
||||
*/
|
||||
public class CmisFunctionEvaluationContext implements FunctionEvaluationContext
|
||||
{
|
||||
public static CMISScope[] STRICT_SCOPES = new CMISScope[] { CMISScope.DOCUMENT, CMISScope.FOLDER };
|
||||
|
||||
public static CMISScope[] ALFRESCO_SCOPES = new CMISScope[] { CMISScope.DOCUMENT, CMISScope.FOLDER, CMISScope.POLICY };
|
||||
|
||||
private Map<String, NodeRef> nodeRefs;
|
||||
|
||||
private Map<String, Float> scores;
|
||||
@@ -57,6 +66,8 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext
|
||||
|
||||
private CMISDictionaryService cmisDictionaryService;
|
||||
|
||||
private CMISScope[] validScopes;
|
||||
|
||||
private Float score;
|
||||
|
||||
/**
|
||||
@@ -95,6 +106,15 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext
|
||||
this.cmisDictionaryService = cmisDictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validScopes
|
||||
* the valid scopes to set
|
||||
*/
|
||||
public void setValidScopes(CMISScope[] validScopes)
|
||||
{
|
||||
this.validScopes = validScopes;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -268,7 +288,7 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext
|
||||
public String getLuceneSortField(LuceneQueryParser lqp, String propertyName)
|
||||
{
|
||||
CMISPropertyDefinition propertyDef = cmisDictionaryService.findProperty(propertyName, null);
|
||||
return propertyDef.getPropertyLuceneBuilder().getLuceneSortField();
|
||||
return propertyDef.getPropertyLuceneBuilder().getLuceneSortField(lqp);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,5 +361,44 @@ public class CmisFunctionEvaluationContext implements FunctionEvaluationContext
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext#checkFieldApplies(org.alfresco.service.namespace.QName, java.lang.String)
|
||||
*/
|
||||
public void checkFieldApplies(Selector selector, String propertyName)
|
||||
{
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(propertyName);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Unknown column/property " + propertyName);
|
||||
}
|
||||
|
||||
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(selector.getType(), validScopes);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Type unsupported in CMIS queries: " + selector.getAlias());
|
||||
}
|
||||
|
||||
// Check column/property applies to selector/type
|
||||
|
||||
if (!typeDef.getPropertyDefinitions().containsKey(propDef.getPropertyId().getId()))
|
||||
{
|
||||
throw new CMISQueryException("Invalid column for " + typeDef.getQueryName() + "." + propertyName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext#isMultiValued(java.lang.String)
|
||||
*/
|
||||
public boolean isMultiValued(String propertyName)
|
||||
{
|
||||
CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(propertyName);
|
||||
if (propDef == null)
|
||||
{
|
||||
throw new CMISQueryException("Unknown column/property " + propertyName);
|
||||
}
|
||||
return propDef.getCardinality() == CMISCardinalityEnum.MULTI_VALUED;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,9 +18,9 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.audit;
|
||||
|
||||
@@ -40,6 +40,7 @@ public class AuditBootstrap extends AbstractLifecycleBean
|
||||
{
|
||||
private TransactionService transactionService;
|
||||
private AuditModelRegistry auditModelRegistry;
|
||||
private boolean isActive = true;
|
||||
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
@@ -51,6 +52,11 @@ public class AuditBootstrap extends AbstractLifecycleBean
|
||||
this.auditModelRegistry = registry;
|
||||
}
|
||||
|
||||
public void setActive(boolean isActive)
|
||||
{
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AuditModelRegistry#loadAuditModels()
|
||||
*/
|
||||
@@ -63,6 +69,12 @@ public class AuditBootstrap extends AbstractLifecycleBean
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't start if we've been configured out
|
||||
if (!this.isActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RetryingTransactionCallback<Void> callback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
|
@@ -33,7 +33,8 @@ import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||
import org.alfresco.repo.audit.model.AuditApplication;
|
||||
import org.alfresco.repo.audit.model.AuditModelException;
|
||||
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
||||
import org.alfresco.repo.audit.model.AuditModelRegistryImpl;
|
||||
import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.PathMapper;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -57,12 +58,15 @@ public class AuditBootstrapTest extends TestCase
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
private static final Log logger = LogFactory.getLog(AuditBootstrapTest.class);
|
||||
|
||||
private AuditModelRegistry auditModelRegistry;
|
||||
private AuditModelRegistryImpl auditModelRegistry;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.modelRegistry");
|
||||
// We have to look inside the subsystem for this test
|
||||
ApplicationContextFactory subsystem = (ApplicationContextFactory) ctx.getBean("Audit");
|
||||
ApplicationContext subCtx = subsystem.getApplicationContext();
|
||||
auditModelRegistry = (AuditModelRegistryImpl) subCtx.getBean("auditModel.modelRegistry");
|
||||
|
||||
// Register a new model
|
||||
URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml");
|
||||
|
@@ -94,6 +94,15 @@ public interface AuditComponent
|
||||
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines whether the given source path is mapped to any audit applications. Allows optimizations to be made in
|
||||
* calling components.
|
||||
*
|
||||
* @return <code>true</code> if the given source path is mapped to one or more audit applications
|
||||
* @since 3.3
|
||||
*/
|
||||
public boolean isSourcePathMapped(String sourcePath);
|
||||
|
||||
/**
|
||||
* Delete audit entries for the given application and time range
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,9 +18,9 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.audit;
|
||||
|
||||
@@ -954,6 +954,15 @@ public class AuditComponentImpl implements AuditComponent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 3.2
|
||||
*/
|
||||
public boolean isSourcePathMapped(String sourcePath)
|
||||
{
|
||||
return !auditModelRegistry.getAuditPathMapper().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 3.2
|
||||
@@ -971,7 +980,7 @@ public class AuditComponentImpl implements AuditComponent
|
||||
{
|
||||
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// Check the path against the application
|
||||
application.checkPath(path);
|
||||
@@ -1162,10 +1171,11 @@ public class AuditComponentImpl implements AuditComponent
|
||||
ParameterCheck.mandatory("rootPath", rootPath);
|
||||
AuditApplication.checkPathFormat(rootPath);
|
||||
|
||||
if (values == null || values.isEmpty())
|
||||
if (values == null || values.isEmpty() || !isSourcePathMapped(rootPath))
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// Build the key paths using the session root path
|
||||
Map<String, Serializable> pathedValues = new HashMap<String, Serializable>(values.size() * 2);
|
||||
for (Map.Entry<String, Serializable> entry : values.entrySet())
|
||||
|
@@ -38,7 +38,8 @@ import junit.framework.TestCase;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.audit.model.AuditApplication;
|
||||
import org.alfresco.repo.audit.model.AuditModelException;
|
||||
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
||||
import org.alfresco.repo.audit.model.AuditModelRegistryImpl;
|
||||
import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
@@ -79,9 +80,9 @@ public class AuditComponentTest extends TestCase
|
||||
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private AuditModelRegistry auditModelRegistry;
|
||||
private ApplicationContextFactory subsystem;
|
||||
private AuditModelRegistryImpl auditModelRegistry;
|
||||
private AuditComponent auditComponent;
|
||||
private AuditMethodInterceptor auditMethodInterceptor;
|
||||
private AuditService auditService;
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private TransactionService transactionService;
|
||||
@@ -93,9 +94,11 @@ public class AuditComponentTest extends TestCase
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.modelRegistry");
|
||||
// We have to look inside the subsystem for this test
|
||||
subsystem = (ApplicationContextFactory) ctx.getBean("Audit");
|
||||
ApplicationContext subCtx = subsystem.getApplicationContext();
|
||||
auditModelRegistry = (AuditModelRegistryImpl) subCtx.getBean("auditModel.modelRegistry");
|
||||
auditComponent = (AuditComponent) ctx.getBean("auditComponent");
|
||||
auditMethodInterceptor = (AuditMethodInterceptor) ctx.getBean("AuditMethodInterceptor");
|
||||
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||
auditService = serviceRegistry.getAuditService();
|
||||
transactionService = serviceRegistry.getTransactionService();
|
||||
@@ -129,17 +132,14 @@ public class AuditComponentTest extends TestCase
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(resetDisabledPathsCallback);
|
||||
|
||||
auditMethodInterceptor.setEnabled(true);
|
||||
auditMethodInterceptor.setUseNewConfig(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
auditMethodInterceptor.setEnabled(false);
|
||||
auditMethodInterceptor.setUseNewConfig(false);
|
||||
// Throw away the reconfigured registry in the subsystem
|
||||
subsystem.stop();
|
||||
}
|
||||
|
||||
public void testSetUp()
|
||||
@@ -315,6 +315,11 @@ public class AuditComponentTest extends TestCase
|
||||
|
||||
AuditQueryCallback callback = new AuditQueryCallback()
|
||||
{
|
||||
public boolean valuesRequired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleAuditEntry(
|
||||
Long entryId, String applicationName, String user, long time, Map<String, Serializable> values)
|
||||
{
|
||||
@@ -482,6 +487,11 @@ public class AuditComponentTest extends TestCase
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
AuditQueryCallback auditQueryCallback = new AuditQueryCallback()
|
||||
{
|
||||
public boolean valuesRequired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleAuditEntry(
|
||||
Long entryId,
|
||||
String applicationName,
|
||||
@@ -576,6 +586,11 @@ public class AuditComponentTest extends TestCase
|
||||
{
|
||||
AuditQueryCallback auditQueryCallback = new AuditQueryCallback()
|
||||
{
|
||||
public boolean valuesRequired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleAuditEntry(
|
||||
Long entryId,
|
||||
String applicationName,
|
||||
@@ -604,4 +619,5 @@ public class AuditComponentTest extends TestCase
|
||||
params.setToId(Long.MAX_VALUE);
|
||||
auditService.auditQuery(auditQueryCallback, params, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,7 +18,7 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
@@ -84,8 +84,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
*/
|
||||
public class AuditMethodInterceptor implements MethodInterceptor
|
||||
{
|
||||
public static final String AUDIT_PATH_API_PRE = "/alfresco-api/pre";
|
||||
public static final String AUDIT_PATH_API_POST = "/alfresco-api/post";
|
||||
public static final String AUDIT_PATH_API_ROOT = "/alfresco-api";
|
||||
public static final String AUDIT_PATH_API_PRE = AUDIT_PATH_API_ROOT + "/pre";
|
||||
public static final String AUDIT_PATH_API_POST = AUDIT_PATH_API_ROOT + "/post";
|
||||
public static final String AUDIT_SNIPPET_ARGS = "/args";
|
||||
public static final String AUDIT_SNIPPET_RESULT = "/result";
|
||||
public static final String AUDIT_SNIPPET_ERROR = "/error";
|
||||
@@ -97,24 +98,17 @@ public class AuditMethodInterceptor implements MethodInterceptor
|
||||
private AuditComponent auditComponent;
|
||||
private TransactionService transactionService;
|
||||
|
||||
private boolean enabled = false;
|
||||
// SysAdmin cache - used to cluster certain configuration parameters
|
||||
private boolean useNewConfig = false;
|
||||
|
||||
private final ThreadLocal<Boolean> inAudit = new ThreadLocal<Boolean>();
|
||||
private final ThreadLocal<Boolean> auditEnabled = new ThreadLocal<Boolean>();
|
||||
|
||||
public AuditMethodInterceptor()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable auditing at a high level (default: <b>false</b>)
|
||||
*/
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the new audit configuration (default: <b>false</b>)
|
||||
*
|
||||
@@ -142,6 +136,23 @@ public class AuditMethodInterceptor implements MethodInterceptor
|
||||
|
||||
public Object invoke(MethodInvocation mi) throws Throwable
|
||||
{
|
||||
// Cache the enabled flag at the top of the stack
|
||||
Boolean wasEnabled = auditEnabled.get();
|
||||
try
|
||||
{
|
||||
boolean enabled;
|
||||
if (wasEnabled == null)
|
||||
{
|
||||
// There hasn't been an invocation in this thread yet, so check whether we are currently enabled in the
|
||||
// audit subsystem
|
||||
enabled = this.auditComponent.isSourcePathMapped(AUDIT_PATH_API_ROOT);
|
||||
auditEnabled.set(enabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
enabled = wasEnabled;
|
||||
}
|
||||
|
||||
if(!enabled)
|
||||
{
|
||||
// No auditing
|
||||
@@ -157,6 +168,11 @@ public class AuditMethodInterceptor implements MethodInterceptor
|
||||
// Use previous configuration
|
||||
return auditComponent.audit(mi);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
auditEnabled.set(wasEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -39,7 +39,8 @@ import org.springframework.util.ResourceUtils;
|
||||
public class AuditModelReader implements InitializingBean
|
||||
{
|
||||
private URL auditModelUrl;
|
||||
private AuditModelRegistry auditModelRegistry;
|
||||
private AuditModelRegistryImpl auditModelRegistry;
|
||||
private boolean isActive = true;
|
||||
|
||||
/**
|
||||
* Set the XML location using <b>file:</b>, <b>classpath:</b> or any of the
|
||||
@@ -56,16 +57,32 @@ public class AuditModelReader implements InitializingBean
|
||||
*
|
||||
* @param auditModelRegistry the registry that combines all loaded models
|
||||
*/
|
||||
public void setAuditModelRegistry(AuditModelRegistry auditModelRegistry)
|
||||
public void setAuditModelRegistry(AuditModelRegistryImpl auditModelRegistry)
|
||||
{
|
||||
this.auditModelRegistry = auditModelRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether or not this bean registers its model with the registry on initialization.
|
||||
*
|
||||
* @param isActive
|
||||
* <code>true</code> if this bean should register its model with the registry on initialization.
|
||||
*/
|
||||
public void setActive(boolean isActive)
|
||||
{
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls in the configuration and registers it
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
if (!this.isActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyCheck.mandatory(this, "configUrl", auditModelUrl);
|
||||
PropertyCheck.mandatory(this, "auditModelRegistry", auditModelRegistry);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,209 +18,27 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.audit.model;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.ValidationEvent;
|
||||
import javax.xml.bind.ValidationEventHandler;
|
||||
import javax.xml.bind.ValidationEventLocator;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.error.ExceptionStackUtil;
|
||||
import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||
import org.alfresco.repo.audit.model._3.Application;
|
||||
import org.alfresco.repo.audit.model._3.Audit;
|
||||
import org.alfresco.repo.audit.model._3.DataExtractors;
|
||||
import org.alfresco.repo.audit.model._3.DataGenerators;
|
||||
import org.alfresco.repo.audit.model._3.ObjectFactory;
|
||||
import org.alfresco.repo.audit.model._3.PathMap;
|
||||
import org.alfresco.repo.audit.model._3.PathMappings;
|
||||
import org.alfresco.repo.domain.audit.AuditDAO;
|
||||
import org.alfresco.repo.domain.audit.AuditDAO.AuditApplicationInfo;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PathMapper;
|
||||
import org.springframework.extensions.surf.util.PropertyCheck;
|
||||
import org.alfresco.util.registry.NamedObjectRegistry;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Component used to store audit model definitions. It ensures that duplicate application and converter
|
||||
* definitions are detected and provides a single lookup for code using the Audit model.
|
||||
* Interface for component used to store audit model definitions.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
* @since 3.3
|
||||
*/
|
||||
public class AuditModelRegistry
|
||||
public interface AuditModelRegistry
|
||||
{
|
||||
public static final String AUDIT_SCHEMA_LOCATION = "classpath:alfresco/audit/alfresco-audit-3.2.xsd";
|
||||
public static final String AUDIT_RESERVED_KEY_USERNAME = "username";
|
||||
public static final String AUDIT_RESERVED_KEY_SYSTEMTIME = "systemTime";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AuditModelRegistry.class);
|
||||
|
||||
private TransactionService transactionService;
|
||||
private AuditDAO auditDAO;
|
||||
private NamedObjectRegistry<DataExtractor> dataExtractors;
|
||||
private NamedObjectRegistry<DataGenerator> dataGenerators;
|
||||
|
||||
private final ReentrantReadWriteLock.ReadLock readLock;
|
||||
private final ReentrantReadWriteLock.WriteLock writeLock;
|
||||
private final ObjectFactory objectFactory;
|
||||
|
||||
private final Set<URL> auditModelUrls;
|
||||
private final List<Audit> auditModels;
|
||||
/**
|
||||
* Used to lookup path translations
|
||||
*/
|
||||
private PathMapper auditPathMapper;
|
||||
/**
|
||||
* Used to lookup the audit application java hierarchy
|
||||
*/
|
||||
private final Map<String, AuditApplication> auditApplicationsByKey;
|
||||
/**
|
||||
* Used to lookup the audit application java hierarchy
|
||||
*/
|
||||
private final Map<String, AuditApplication> auditApplicationsByName;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AuditModelRegistry()
|
||||
{
|
||||
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
|
||||
objectFactory = new ObjectFactory();
|
||||
|
||||
auditModelUrls = new HashSet<URL>(7);
|
||||
auditModels = new ArrayList<Audit>(7);
|
||||
auditPathMapper = new PathMapper();
|
||||
auditApplicationsByKey = new HashMap<String, AuditApplication>(7);
|
||||
auditApplicationsByName = new HashMap<String, AuditApplication>(7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service to ensure DAO calls are transactionally wrapped
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DAO used to persisted the registered audit models
|
||||
*/
|
||||
public void setAuditDAO(AuditDAO auditDAO)
|
||||
{
|
||||
this.auditDAO = auditDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registry of {@link DataExtractor data extractors}
|
||||
*/
|
||||
public void setDataExtractors(NamedObjectRegistry<DataExtractor> dataExtractors)
|
||||
{
|
||||
this.dataExtractors = dataExtractors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registry of {@link DataGenerator data generators}
|
||||
*/
|
||||
public void setDataGenerators(NamedObjectRegistry<DataGenerator> dataGenerators)
|
||||
{
|
||||
this.dataGenerators = dataGenerators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that all properties have been set for use.
|
||||
*/
|
||||
private void checkProperties()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
||||
PropertyCheck.mandatory(this, "auditDAO", auditDAO);
|
||||
PropertyCheck.mandatory(this, "dataExtractors", dataExtractors);
|
||||
PropertyCheck.mandatory(this, "dataGenerators", dataGenerators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an audit model at a given URL.
|
||||
*
|
||||
* @param auditModelUrl the source of the model
|
||||
*/
|
||||
public void registerModel(URL auditModelUrl)
|
||||
{
|
||||
checkProperties();
|
||||
writeLock.lock();
|
||||
try
|
||||
{
|
||||
if (auditModelUrls.contains(auditModelUrl))
|
||||
{
|
||||
logger.warn("An audit model has already been registered at URL " + auditModelUrl);
|
||||
}
|
||||
auditModelUrls.add(auditModelUrl);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an audit model at a given node reference.
|
||||
*
|
||||
* @param auditModelNodeRef the source of the audit model
|
||||
*/
|
||||
public void registerModel(NodeRef auditModelNodeRef)
|
||||
{
|
||||
checkProperties();
|
||||
writeLock.lock();
|
||||
try
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out all derived data
|
||||
*/
|
||||
private void clearCaches()
|
||||
{
|
||||
auditModels.clear();
|
||||
auditApplicationsByKey.clear();
|
||||
auditApplicationsByName.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to load audit models into memory. This method is also responsible for persisting
|
||||
* the audit models for later retrieval. Models are loaded from the locations given by the
|
||||
@@ -229,59 +47,7 @@ public class AuditModelRegistry
|
||||
* Note, the models are loaded in a new transaction, so this method can be called by any code
|
||||
* at any time.
|
||||
*/
|
||||
public void loadAuditModels()
|
||||
{
|
||||
checkProperties();
|
||||
|
||||
RetryingTransactionCallback<Void> loadModelsCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Load models from the URLs
|
||||
Set<URL> auditModelUrlsInner = new HashSet<URL>(auditModelUrls);
|
||||
for (URL auditModelUrl : auditModelUrlsInner)
|
||||
{
|
||||
try
|
||||
{
|
||||
Audit audit = AuditModelRegistry.unmarshallModel(auditModelUrl);
|
||||
// That worked, so now get an input stream and write the model
|
||||
Long auditModelId = auditDAO.getOrCreateAuditModel(auditModelUrl).getFirst();
|
||||
// Now cache it (eagerly)
|
||||
cacheAuditElements(auditModelId, audit);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Mainly for test purposes, we clear out the failed URL
|
||||
auditModelUrls.remove(auditModelUrl);
|
||||
clearCaches();
|
||||
|
||||
throw new AuditModelException(
|
||||
"Failed to load audit model: " + auditModelUrl,
|
||||
e);
|
||||
}
|
||||
}
|
||||
// NOTE: If we support other types of loading, then that will have to go here, too
|
||||
|
||||
// Done
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
writeLock.lock();
|
||||
// Drop all cached data
|
||||
clearCaches();
|
||||
try
|
||||
{
|
||||
auditPathMapper = new PathMapper();
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(loadModelsCallback,
|
||||
transactionService.isReadOnly(), true);
|
||||
auditPathMapper.lock();
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
public void loadAuditModels();
|
||||
|
||||
/**
|
||||
* Get the application model for the given root key (as defined on the application)
|
||||
@@ -289,18 +55,7 @@ public class AuditModelRegistry
|
||||
* @param key the key defined on the application
|
||||
* @return the java model (<tt>null</tt> if not found)
|
||||
*/
|
||||
public AuditApplication getAuditApplicationByKey(String key)
|
||||
{
|
||||
readLock.lock();
|
||||
try
|
||||
{
|
||||
return auditApplicationsByKey.get(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
public AuditApplication getAuditApplicationByKey(String key);
|
||||
|
||||
/**
|
||||
* Get the application model for the given application name
|
||||
@@ -308,285 +63,11 @@ public class AuditModelRegistry
|
||||
* @param applicationName the name of the audited application
|
||||
* @return the java model (<tt>null</tt> if not found)
|
||||
*/
|
||||
public AuditApplication getAuditApplicationByName(String applicationName)
|
||||
{
|
||||
readLock.lock();
|
||||
try
|
||||
{
|
||||
return auditApplicationsByName.get(applicationName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
public AuditApplication getAuditApplicationByName(String applicationName);
|
||||
|
||||
/**
|
||||
* Get the
|
||||
* @return
|
||||
* Get the path mapper.
|
||||
* @return the path mapper
|
||||
*/
|
||||
public PathMapper getAuditPathMapper()
|
||||
{
|
||||
return auditPathMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshalls the Audit model from the URL.
|
||||
*
|
||||
* @throws AlfrescoRuntimeException if an IOException occurs
|
||||
*/
|
||||
public static Audit unmarshallModel(URL configUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load it
|
||||
InputStream is = new BufferedInputStream(configUrl.openStream());
|
||||
return unmarshallModel(is, configUrl.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("The Audit model XML failed to load: " + configUrl, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshalls the Audit model from a stream
|
||||
*/
|
||||
private static Audit unmarshallModel(InputStream is, final String source)
|
||||
{
|
||||
final Schema schema;
|
||||
final JAXBContext jaxbCtx;
|
||||
final Unmarshaller jaxbUnmarshaller;
|
||||
try
|
||||
{
|
||||
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
schema = sf.newSchema(ResourceUtils.getURL(AUDIT_SCHEMA_LOCATION));
|
||||
jaxbCtx = JAXBContext.newInstance("org.alfresco.repo.audit.model._3");
|
||||
jaxbUnmarshaller = jaxbCtx.createUnmarshaller();
|
||||
jaxbUnmarshaller.setSchema(schema);
|
||||
jaxbUnmarshaller.setEventHandler(new ValidationEventHandler()
|
||||
{
|
||||
public boolean handleEvent(ValidationEvent ve)
|
||||
{
|
||||
if (ve.getSeverity() == ValidationEvent.FATAL_ERROR || ve.getSeverity() == ValidationEvent.ERROR)
|
||||
{
|
||||
ValidationEventLocator locator = ve.getLocator();
|
||||
logger.error("Invalid Audit XML: \n" +
|
||||
" Source: " + source + "\n" +
|
||||
" Location: Line " + locator.getLineNumber() + " column " + locator.getColumnNumber() + "\n" +
|
||||
" Error: " + ve.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"Failed to load Alfresco Audit Schema from " + AUDIT_SCHEMA_LOCATION, e);
|
||||
}
|
||||
try
|
||||
{
|
||||
// Unmarshall with validation
|
||||
@SuppressWarnings("unchecked")
|
||||
JAXBElement<Audit> auditElement = (JAXBElement<Audit>) jaxbUnmarshaller.unmarshal(is);
|
||||
|
||||
Audit audit = auditElement.getValue();
|
||||
// Done
|
||||
return audit;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Dig out a SAXParseException, if there is one
|
||||
Throwable saxError = ExceptionStackUtil.getCause(e, SAXParseException.class);
|
||||
if (saxError != null)
|
||||
{
|
||||
e = saxError;
|
||||
}
|
||||
throw new AuditModelException(
|
||||
"Failed to read Audit model XML: \n" +
|
||||
" Source: " + source + "\n" +
|
||||
" Error: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { is.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheAuditElements(Long auditModelId, Audit audit)
|
||||
{
|
||||
Map<String, DataExtractor> dataExtractorsByName = new HashMap<String, DataExtractor>(13);
|
||||
Map<String, DataGenerator> dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
|
||||
|
||||
// Get the data extractors and check for duplicates
|
||||
DataExtractors extractorsElement = audit.getDataExtractors();
|
||||
if (extractorsElement == null)
|
||||
{
|
||||
extractorsElement = objectFactory.createDataExtractors();
|
||||
}
|
||||
List<org.alfresco.repo.audit.model._3.DataExtractor> extractorElements = extractorsElement.getDataExtractor();
|
||||
for (org.alfresco.repo.audit.model._3.DataExtractor extractorElement : extractorElements)
|
||||
{
|
||||
String name = extractorElement.getName();
|
||||
// If the name is taken, make sure that they are equal
|
||||
if (dataExtractorsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' has already been defined.");
|
||||
}
|
||||
// Construct the converter
|
||||
final DataExtractor dataExtractor;
|
||||
if (extractorElement.getClazz() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> dataExtractorClazz = Class.forName(extractorElement.getClazz());
|
||||
dataExtractor = (DataExtractor) dataExtractorClazz.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' class not found: " + extractorElement.getClazz());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' could not be constructed: " + extractorElement.getClazz());
|
||||
}
|
||||
}
|
||||
else if (extractorElement.getRegisteredName() != null)
|
||||
{
|
||||
String registeredName = extractorElement.getRegisteredName();
|
||||
dataExtractor = dataExtractors.getNamedObject(registeredName);
|
||||
if (dataExtractor == null)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"No registered audit data extractor exists for '" + registeredName + "'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor has no class or registered name: " + name);
|
||||
}
|
||||
// Store
|
||||
dataExtractorsByName.put(name, dataExtractor);
|
||||
}
|
||||
// Get the data generators and check for duplicates
|
||||
DataGenerators generatorsElement = audit.getDataGenerators();
|
||||
if (generatorsElement == null)
|
||||
{
|
||||
generatorsElement = objectFactory.createDataGenerators();
|
||||
}
|
||||
List<org.alfresco.repo.audit.model._3.DataGenerator> generatorElements = generatorsElement.getDataGenerator();
|
||||
for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements)
|
||||
{
|
||||
String name = generatorElement.getName();
|
||||
// If the name is taken, make sure that they are equal
|
||||
if (dataGeneratorsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' has already been defined.");
|
||||
}
|
||||
// Construct the generator
|
||||
final DataGenerator dataGenerator;
|
||||
if (generatorElement.getClazz() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> dataGeneratorClazz = Class.forName(generatorElement.getClazz());
|
||||
dataGenerator = (DataGenerator) dataGeneratorClazz.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' class not found: " + generatorElement.getClazz());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz());
|
||||
}
|
||||
}
|
||||
else if (generatorElement.getRegisteredName() != null)
|
||||
{
|
||||
String registeredName = generatorElement.getRegisteredName();
|
||||
dataGenerator = dataGenerators.getNamedObject(registeredName);
|
||||
if (dataGenerator == null)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"No registered audit data generator exists for '" + registeredName + "'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator has no class or registered name: " + name);
|
||||
}
|
||||
// Store
|
||||
dataGeneratorsByName.put(name, dataGenerator);
|
||||
}
|
||||
// Get the application and check for duplicates
|
||||
List<Application> applications = audit.getApplication();
|
||||
for (Application application : applications)
|
||||
{
|
||||
String key = application.getKey();
|
||||
if (auditApplicationsByKey.containsKey(key))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit application key '" + key + "' is used by: " + auditApplicationsByKey.get(key));
|
||||
}
|
||||
|
||||
String name = application.getName();
|
||||
if (auditApplicationsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit application '" + name + "' is used by: " + auditApplicationsByName.get(name));
|
||||
}
|
||||
|
||||
// Get the ID of the application
|
||||
AuditApplicationInfo appInfo = auditDAO.getAuditApplication(name);
|
||||
if (appInfo == null)
|
||||
{
|
||||
appInfo = auditDAO.createAuditApplication(name, auditModelId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update it with the new model ID
|
||||
auditDAO.updateAuditApplicationModel(appInfo.getId(), auditModelId);
|
||||
}
|
||||
|
||||
AuditApplication wrapperApp = new AuditApplication(
|
||||
dataExtractorsByName,
|
||||
dataGeneratorsByName,
|
||||
application,
|
||||
appInfo.getId(),
|
||||
appInfo.getDisabledPathsId());
|
||||
auditApplicationsByName.put(name, wrapperApp);
|
||||
auditApplicationsByKey.put(key, wrapperApp);
|
||||
}
|
||||
// Pull out all the audit path maps
|
||||
buildAuditPathMap(audit);
|
||||
// Store the model itself
|
||||
auditModels.add(audit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the reverse lookup maps for quick conversion of data to target maps
|
||||
*/
|
||||
private void buildAuditPathMap(Audit audit)
|
||||
{
|
||||
PathMappings pathMappings = audit.getPathMappings();
|
||||
if (pathMappings == null)
|
||||
{
|
||||
pathMappings = objectFactory.createPathMappings();
|
||||
}
|
||||
for (PathMap pathMap : pathMappings.getPathMap())
|
||||
{
|
||||
String sourcePath = pathMap.getSource();
|
||||
String targetPath = pathMap.getTarget();
|
||||
auditPathMapper.addPathMap(sourcePath, targetPath);
|
||||
}
|
||||
}
|
||||
public PathMapper getAuditPathMapper();
|
||||
}
|
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.audit.model;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.ValidationEvent;
|
||||
import javax.xml.bind.ValidationEventHandler;
|
||||
import javax.xml.bind.ValidationEventLocator;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.error.ExceptionStackUtil;
|
||||
import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||
import org.alfresco.repo.audit.model._3.Application;
|
||||
import org.alfresco.repo.audit.model._3.Audit;
|
||||
import org.alfresco.repo.audit.model._3.DataExtractors;
|
||||
import org.alfresco.repo.audit.model._3.DataGenerators;
|
||||
import org.alfresco.repo.audit.model._3.ObjectFactory;
|
||||
import org.alfresco.repo.audit.model._3.PathMap;
|
||||
import org.alfresco.repo.audit.model._3.PathMappings;
|
||||
import org.alfresco.repo.domain.audit.AuditDAO;
|
||||
import org.alfresco.repo.domain.audit.AuditDAO.AuditApplicationInfo;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PathMapper;
|
||||
import org.alfresco.util.registry.NamedObjectRegistry;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.PropertyCheck;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Component used to store audit model definitions. It ensures that duplicate application and converter
|
||||
* definitions are detected and provides a single lookup for code using the Audit model.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuditModelRegistryImpl implements AuditModelRegistry
|
||||
{
|
||||
private static final String AUDIT_SCHEMA_LOCATION = "classpath:alfresco/audit/alfresco-audit-3.2.xsd";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AuditModelRegistryImpl.class);
|
||||
|
||||
private TransactionService transactionService;
|
||||
private AuditDAO auditDAO;
|
||||
private NamedObjectRegistry<DataExtractor> dataExtractors;
|
||||
private NamedObjectRegistry<DataGenerator> dataGenerators;
|
||||
|
||||
private final ReentrantReadWriteLock.ReadLock readLock;
|
||||
private final ReentrantReadWriteLock.WriteLock writeLock;
|
||||
private final ObjectFactory objectFactory;
|
||||
|
||||
private final Set<URL> auditModelUrls;
|
||||
private final List<Audit> auditModels;
|
||||
/**
|
||||
* Used to lookup path translations
|
||||
*/
|
||||
private PathMapper auditPathMapper;
|
||||
/**
|
||||
* Used to lookup the audit application java hierarchy
|
||||
*/
|
||||
private final Map<String, AuditApplication> auditApplicationsByKey;
|
||||
/**
|
||||
* Used to lookup the audit application java hierarchy
|
||||
*/
|
||||
private final Map<String, AuditApplication> auditApplicationsByName;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AuditModelRegistryImpl()
|
||||
{
|
||||
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
|
||||
objectFactory = new ObjectFactory();
|
||||
|
||||
auditModelUrls = new HashSet<URL>(7);
|
||||
auditModels = new ArrayList<Audit>(7);
|
||||
auditPathMapper = new PathMapper();
|
||||
auditApplicationsByKey = new HashMap<String, AuditApplication>(7);
|
||||
auditApplicationsByName = new HashMap<String, AuditApplication>(7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service to ensure DAO calls are transactionally wrapped
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DAO used to persisted the registered audit models
|
||||
*/
|
||||
public void setAuditDAO(AuditDAO auditDAO)
|
||||
{
|
||||
this.auditDAO = auditDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registry of {@link DataExtractor data extractors}
|
||||
*/
|
||||
public void setDataExtractors(NamedObjectRegistry<DataExtractor> dataExtractors)
|
||||
{
|
||||
this.dataExtractors = dataExtractors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registry of {@link DataGenerator data generators}
|
||||
*/
|
||||
public void setDataGenerators(NamedObjectRegistry<DataGenerator> dataGenerators)
|
||||
{
|
||||
this.dataGenerators = dataGenerators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that all properties have been set for use.
|
||||
*/
|
||||
private void checkProperties()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
||||
PropertyCheck.mandatory(this, "auditDAO", auditDAO);
|
||||
PropertyCheck.mandatory(this, "dataExtractors", dataExtractors);
|
||||
PropertyCheck.mandatory(this, "dataGenerators", dataGenerators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an audit model at a given URL.
|
||||
*
|
||||
* @param auditModelUrl the source of the model
|
||||
*/
|
||||
public void registerModel(URL auditModelUrl)
|
||||
{
|
||||
checkProperties();
|
||||
writeLock.lock();
|
||||
try
|
||||
{
|
||||
if (auditModelUrls.contains(auditModelUrl))
|
||||
{
|
||||
logger.warn("An audit model has already been registered at URL " + auditModelUrl);
|
||||
}
|
||||
auditModelUrls.add(auditModelUrl);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an audit model at a given node reference.
|
||||
*
|
||||
* @param auditModelNodeRef the source of the audit model
|
||||
*/
|
||||
public void registerModel(NodeRef auditModelNodeRef)
|
||||
{
|
||||
checkProperties();
|
||||
writeLock.lock();
|
||||
try
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out all derived data
|
||||
*/
|
||||
private void clearCaches()
|
||||
{
|
||||
auditModels.clear();
|
||||
auditApplicationsByKey.clear();
|
||||
auditApplicationsByName.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.audit.model.AuditModelRegistry#loadAuditModels()
|
||||
*/
|
||||
public void loadAuditModels()
|
||||
{
|
||||
checkProperties();
|
||||
|
||||
RetryingTransactionCallback<Void> loadModelsCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Load models from the URLs
|
||||
Set<URL> auditModelUrlsInner = new HashSet<URL>(auditModelUrls);
|
||||
for (URL auditModelUrl : auditModelUrlsInner)
|
||||
{
|
||||
try
|
||||
{
|
||||
Audit audit = AuditModelRegistryImpl.unmarshallModel(auditModelUrl);
|
||||
// That worked, so now get an input stream and write the model
|
||||
Long auditModelId = auditDAO.getOrCreateAuditModel(auditModelUrl).getFirst();
|
||||
// Now cache it (eagerly)
|
||||
cacheAuditElements(auditModelId, audit);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Mainly for test purposes, we clear out the failed URL
|
||||
auditModelUrls.remove(auditModelUrl);
|
||||
clearCaches();
|
||||
|
||||
throw new AuditModelException(
|
||||
"Failed to load audit model: " + auditModelUrl,
|
||||
e);
|
||||
}
|
||||
}
|
||||
// NOTE: If we support other types of loading, then that will have to go here, too
|
||||
|
||||
// Done
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
writeLock.lock();
|
||||
// Drop all cached data
|
||||
clearCaches();
|
||||
try
|
||||
{
|
||||
auditPathMapper = new PathMapper();
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(loadModelsCallback,
|
||||
transactionService.isReadOnly(), true);
|
||||
auditPathMapper.lock();
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByKey(java.lang.String)
|
||||
*/
|
||||
public AuditApplication getAuditApplicationByKey(String key)
|
||||
{
|
||||
readLock.lock();
|
||||
try
|
||||
{
|
||||
return auditApplicationsByKey.get(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByName(java.lang.String)
|
||||
*/
|
||||
public AuditApplication getAuditApplicationByName(String applicationName)
|
||||
{
|
||||
readLock.lock();
|
||||
try
|
||||
{
|
||||
return auditApplicationsByName.get(applicationName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditPathMapper()
|
||||
*/
|
||||
public PathMapper getAuditPathMapper()
|
||||
{
|
||||
return auditPathMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshalls the Audit model from the URL.
|
||||
*
|
||||
* @throws AlfrescoRuntimeException if an IOException occurs
|
||||
*/
|
||||
public static Audit unmarshallModel(URL configUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load it
|
||||
InputStream is = new BufferedInputStream(configUrl.openStream());
|
||||
return unmarshallModel(is, configUrl.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("The Audit model XML failed to load: " + configUrl, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshalls the Audit model from a stream
|
||||
*/
|
||||
private static Audit unmarshallModel(InputStream is, final String source)
|
||||
{
|
||||
final Schema schema;
|
||||
final JAXBContext jaxbCtx;
|
||||
final Unmarshaller jaxbUnmarshaller;
|
||||
try
|
||||
{
|
||||
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
schema = sf.newSchema(ResourceUtils.getURL(AUDIT_SCHEMA_LOCATION));
|
||||
jaxbCtx = JAXBContext.newInstance("org.alfresco.repo.audit.model._3");
|
||||
jaxbUnmarshaller = jaxbCtx.createUnmarshaller();
|
||||
jaxbUnmarshaller.setSchema(schema);
|
||||
jaxbUnmarshaller.setEventHandler(new ValidationEventHandler()
|
||||
{
|
||||
public boolean handleEvent(ValidationEvent ve)
|
||||
{
|
||||
if (ve.getSeverity() == ValidationEvent.FATAL_ERROR || ve.getSeverity() == ValidationEvent.ERROR)
|
||||
{
|
||||
ValidationEventLocator locator = ve.getLocator();
|
||||
logger.error("Invalid Audit XML: \n" +
|
||||
" Source: " + source + "\n" +
|
||||
" Location: Line " + locator.getLineNumber() + " column " + locator.getColumnNumber() + "\n" +
|
||||
" Error: " + ve.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"Failed to load Alfresco Audit Schema from " + AUDIT_SCHEMA_LOCATION, e);
|
||||
}
|
||||
try
|
||||
{
|
||||
// Unmarshall with validation
|
||||
@SuppressWarnings("unchecked")
|
||||
JAXBElement<Audit> auditElement = (JAXBElement<Audit>) jaxbUnmarshaller.unmarshal(is);
|
||||
|
||||
Audit audit = auditElement.getValue();
|
||||
// Done
|
||||
return audit;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Dig out a SAXParseException, if there is one
|
||||
Throwable saxError = ExceptionStackUtil.getCause(e, SAXParseException.class);
|
||||
if (saxError != null)
|
||||
{
|
||||
e = saxError;
|
||||
}
|
||||
throw new AuditModelException(
|
||||
"Failed to read Audit model XML: \n" +
|
||||
" Source: " + source + "\n" +
|
||||
" Error: " + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { is.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheAuditElements(Long auditModelId, Audit audit)
|
||||
{
|
||||
Map<String, DataExtractor> dataExtractorsByName = new HashMap<String, DataExtractor>(13);
|
||||
Map<String, DataGenerator> dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
|
||||
|
||||
// Get the data extractors and check for duplicates
|
||||
DataExtractors extractorsElement = audit.getDataExtractors();
|
||||
if (extractorsElement == null)
|
||||
{
|
||||
extractorsElement = objectFactory.createDataExtractors();
|
||||
}
|
||||
List<org.alfresco.repo.audit.model._3.DataExtractor> extractorElements = extractorsElement.getDataExtractor();
|
||||
for (org.alfresco.repo.audit.model._3.DataExtractor extractorElement : extractorElements)
|
||||
{
|
||||
String name = extractorElement.getName();
|
||||
// If the name is taken, make sure that they are equal
|
||||
if (dataExtractorsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' has already been defined.");
|
||||
}
|
||||
// Construct the converter
|
||||
final DataExtractor dataExtractor;
|
||||
if (extractorElement.getClazz() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> dataExtractorClazz = Class.forName(extractorElement.getClazz());
|
||||
dataExtractor = (DataExtractor) dataExtractorClazz.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' class not found: " + extractorElement.getClazz());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor '" + name + "' could not be constructed: " + extractorElement.getClazz());
|
||||
}
|
||||
}
|
||||
else if (extractorElement.getRegisteredName() != null)
|
||||
{
|
||||
String registeredName = extractorElement.getRegisteredName();
|
||||
dataExtractor = dataExtractors.getNamedObject(registeredName);
|
||||
if (dataExtractor == null)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"No registered audit data extractor exists for '" + registeredName + "'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data extractor has no class or registered name: " + name);
|
||||
}
|
||||
// Store
|
||||
dataExtractorsByName.put(name, dataExtractor);
|
||||
}
|
||||
// Get the data generators and check for duplicates
|
||||
DataGenerators generatorsElement = audit.getDataGenerators();
|
||||
if (generatorsElement == null)
|
||||
{
|
||||
generatorsElement = objectFactory.createDataGenerators();
|
||||
}
|
||||
List<org.alfresco.repo.audit.model._3.DataGenerator> generatorElements = generatorsElement.getDataGenerator();
|
||||
for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements)
|
||||
{
|
||||
String name = generatorElement.getName();
|
||||
// If the name is taken, make sure that they are equal
|
||||
if (dataGeneratorsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' has already been defined.");
|
||||
}
|
||||
// Construct the generator
|
||||
final DataGenerator dataGenerator;
|
||||
if (generatorElement.getClazz() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> dataGeneratorClazz = Class.forName(generatorElement.getClazz());
|
||||
dataGenerator = (DataGenerator) dataGeneratorClazz.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' class not found: " + generatorElement.getClazz());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz());
|
||||
}
|
||||
}
|
||||
else if (generatorElement.getRegisteredName() != null)
|
||||
{
|
||||
String registeredName = generatorElement.getRegisteredName();
|
||||
dataGenerator = dataGenerators.getNamedObject(registeredName);
|
||||
if (dataGenerator == null)
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"No registered audit data generator exists for '" + registeredName + "'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit data generator has no class or registered name: " + name);
|
||||
}
|
||||
// Store
|
||||
dataGeneratorsByName.put(name, dataGenerator);
|
||||
}
|
||||
// Get the application and check for duplicates
|
||||
List<Application> applications = audit.getApplication();
|
||||
for (Application application : applications)
|
||||
{
|
||||
String key = application.getKey();
|
||||
if (auditApplicationsByKey.containsKey(key))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit application key '" + key + "' is used by: " + auditApplicationsByKey.get(key));
|
||||
}
|
||||
|
||||
String name = application.getName();
|
||||
if (auditApplicationsByName.containsKey(name))
|
||||
{
|
||||
throw new AuditModelException(
|
||||
"Audit application '" + name + "' is used by: " + auditApplicationsByName.get(name));
|
||||
}
|
||||
|
||||
// Get the ID of the application
|
||||
AuditApplicationInfo appInfo = auditDAO.getAuditApplication(name);
|
||||
if (appInfo == null)
|
||||
{
|
||||
appInfo = auditDAO.createAuditApplication(name, auditModelId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update it with the new model ID
|
||||
auditDAO.updateAuditApplicationModel(appInfo.getId(), auditModelId);
|
||||
}
|
||||
|
||||
AuditApplication wrapperApp = new AuditApplication(
|
||||
dataExtractorsByName,
|
||||
dataGeneratorsByName,
|
||||
application,
|
||||
appInfo.getId(),
|
||||
appInfo.getDisabledPathsId());
|
||||
auditApplicationsByName.put(name, wrapperApp);
|
||||
auditApplicationsByKey.put(key, wrapperApp);
|
||||
}
|
||||
// Pull out all the audit path maps
|
||||
buildAuditPathMap(audit);
|
||||
// Store the model itself
|
||||
auditModels.add(audit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the reverse lookup maps for quick conversion of data to target maps
|
||||
*/
|
||||
private void buildAuditPathMap(Audit audit)
|
||||
{
|
||||
PathMappings pathMappings = audit.getPathMappings();
|
||||
if (pathMappings == null)
|
||||
{
|
||||
pathMappings = objectFactory.createPathMappings();
|
||||
}
|
||||
for (PathMap pathMap : pathMappings.getPathMap())
|
||||
{
|
||||
String sourcePath = pathMap.getSource();
|
||||
String targetPath = pathMap.getTarget();
|
||||
auditPathMapper.addPathMap(sourcePath, targetPath);
|
||||
}
|
||||
}
|
||||
}
|
@@ -159,6 +159,11 @@ import org.alfresco.service.namespace.QName;
|
||||
return type.getArchive();
|
||||
}
|
||||
|
||||
public Boolean getIncludedInSuperTypeQuery()
|
||||
{
|
||||
return type.getIncludedInSuperTypeQuery();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.ClassDefinition#getProperties()
|
||||
*/
|
||||
|
@@ -41,6 +41,7 @@ public abstract class M2Class
|
||||
private String description = null;
|
||||
private String parentName = null;
|
||||
private Boolean archive = null;
|
||||
private Boolean includedInSuperTypeQuery = null;
|
||||
|
||||
private List<M2Property> properties = new ArrayList<M2Property>();
|
||||
private List<M2PropertyOverride> propertyOverrides = new ArrayList<M2PropertyOverride>();
|
||||
@@ -110,6 +111,16 @@ public abstract class M2Class
|
||||
this.archive = Boolean.valueOf(archive);
|
||||
}
|
||||
|
||||
public Boolean getIncludedInSuperTypeQuery()
|
||||
{
|
||||
return includedInSuperTypeQuery;
|
||||
}
|
||||
|
||||
public void setIncludedInSuperTypeQuery(boolean includedInSuperTypeQuery)
|
||||
{
|
||||
this.includedInSuperTypeQuery = Boolean.valueOf(includedInSuperTypeQuery);
|
||||
}
|
||||
|
||||
public M2Property createProperty(String name)
|
||||
{
|
||||
M2Property property = new M2Property();
|
||||
|
@@ -71,6 +71,8 @@ import org.alfresco.util.EqualsHelper;
|
||||
private Set<QName> inheritedDefaultAspectNames = new HashSet<QName>();
|
||||
private Boolean archive = null;
|
||||
private Boolean inheritedArchive = null;
|
||||
private Boolean includedInSuperTypeQuery = null;
|
||||
private Boolean inheritedIncludedInSuperTypeQuery = null;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
@@ -88,6 +90,7 @@ import org.alfresco.util.EqualsHelper;
|
||||
// Resolve Names
|
||||
this.name = QName.createQName(m2Class.getName(), resolver);
|
||||
this.archive = m2Class.getArchive();
|
||||
this.includedInSuperTypeQuery = m2Class.getIncludedInSuperTypeQuery();
|
||||
if (m2Class.getParentName() != null && m2Class.getParentName().length() > 0)
|
||||
{
|
||||
this.parentName = QName.createQName(m2Class.getParentName(), resolver);
|
||||
@@ -315,6 +318,13 @@ import org.alfresco.util.EqualsHelper;
|
||||
// archive not explicitly set on this class and there is a parent class
|
||||
inheritedArchive = ((M2ClassDefinition)parentClass).getArchive();
|
||||
}
|
||||
|
||||
// resolve includedInSuperTypeQuery inheritance
|
||||
if (parentClass != null && includedInSuperTypeQuery == null)
|
||||
{
|
||||
// archive not explicitly set on this class and there is a parent class
|
||||
inheritedIncludedInSuperTypeQuery = ((M2ClassDefinition)parentClass).getIncludedInSuperTypeQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -383,6 +393,22 @@ import org.alfresco.util.EqualsHelper;
|
||||
return archive == null ? inheritedArchive : archive;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.ClassDefinition#includedInSuperTypeQuery()
|
||||
*/
|
||||
public Boolean getIncludedInSuperTypeQuery()
|
||||
{
|
||||
if(includedInSuperTypeQuery != null)
|
||||
{
|
||||
return includedInSuperTypeQuery;
|
||||
}
|
||||
if(inheritedIncludedInSuperTypeQuery != null)
|
||||
{
|
||||
return inheritedIncludedInSuperTypeQuery;
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.ClassDefinition#getProperties()
|
||||
*/
|
||||
@@ -618,6 +644,23 @@ import org.alfresco.util.EqualsHelper;
|
||||
}
|
||||
}
|
||||
|
||||
// check includedInSuperTypeQuery/inheritedIncludedInSuperTypeQuery
|
||||
if (includedInSuperTypeQuery == null)
|
||||
{
|
||||
if (classDef.getIncludedInSuperTypeQuery() != null)
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Boolean classIncludedInSuperTypeQuery = classDef.getIncludedInSuperTypeQuery();
|
||||
if (classIncludedInSuperTypeQuery == null || classIncludedInSuperTypeQuery.booleanValue() != includedInSuperTypeQuery.booleanValue())
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
}
|
||||
|
||||
String modelDiffType;
|
||||
if (isAspect())
|
||||
{
|
||||
|
@@ -61,6 +61,7 @@
|
||||
<value name="description" field="description" usage="optional"/>
|
||||
<value name="parent" field="parentName" usage="optional"/>
|
||||
<value name="archive" field="archive" usage="optional"/>
|
||||
<value name="includedInSuperTypeQuery" field="includedInSuperTypeQuery" usage="optional"/>
|
||||
<structure name="properties" usage="optional">
|
||||
<collection field="properties" item-type="org.alfresco.repo.dictionary.M2Property" factory="org.alfresco.repo.dictionary.M2Model.createList"/>
|
||||
</structure>
|
||||
|
@@ -362,6 +362,12 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
this.callback = callback;
|
||||
this.more = true;
|
||||
}
|
||||
|
||||
public boolean valuesRequired()
|
||||
{
|
||||
return callback.valuesRequired();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void processResult(AuditQueryResult row)
|
||||
{
|
||||
@@ -371,7 +377,10 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
return;
|
||||
}
|
||||
// See if the value is available or if it has to be built up
|
||||
Map<String, Serializable> auditValues = row.getAuditValue();
|
||||
Map<String, Serializable> auditValues = null;
|
||||
if (valuesRequired())
|
||||
{
|
||||
auditValues = row.getAuditValue();
|
||||
if (auditValues == null)
|
||||
{
|
||||
List<PropertyIdSearchRow> propMapRows = row.getAuditValueRows();
|
||||
@@ -383,10 +392,8 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
if (auditValuesPair == null)
|
||||
{
|
||||
// Ignore
|
||||
more = callback.handleAuditEntryError(
|
||||
row.getAuditEntryId(),
|
||||
"Audit entry not joined to audit properties: " + row,
|
||||
null);
|
||||
more = callback.handleAuditEntryError(row.getAuditEntryId(),
|
||||
"Audit entry not joined to audit properties: " + row, null);
|
||||
return;
|
||||
}
|
||||
auditValues = (Map<String, Serializable>) auditValuesPair.getSecond();
|
||||
@@ -396,34 +403,30 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
// Resolve the map
|
||||
try
|
||||
{
|
||||
auditValues = (Map<String, Serializable>) propertyValueDAO.convertPropertyIdSearchRows(propMapRows);
|
||||
auditValues = (Map<String, Serializable>) propertyValueDAO
|
||||
.convertPropertyIdSearchRows(propMapRows);
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
more = callback.handleAuditEntryError(
|
||||
row.getAuditEntryId(),
|
||||
"Audit entry not linked to a Map<String, Serializable> value: " + row,
|
||||
e);
|
||||
more = callback.handleAuditEntryError(row.getAuditEntryId(),
|
||||
"Audit entry not linked to a Map<String, Serializable> value: " + row, e);
|
||||
return;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
more = callback.handleAuditEntryError(
|
||||
row.getAuditEntryId(),
|
||||
"Audit entry unable to extract audited values: " + row,
|
||||
e);
|
||||
more = callback.handleAuditEntryError(row.getAuditEntryId(),
|
||||
"Audit entry unable to extract audited values: " + row, e);
|
||||
return;
|
||||
}
|
||||
if (auditValues == null)
|
||||
{
|
||||
more = callback.handleAuditEntryError(
|
||||
row.getAuditEntryId(),
|
||||
"Audit entry incompletely joined to audit properties: " + row,
|
||||
null);
|
||||
more = callback.handleAuditEntryError(row.getAuditEntryId(),
|
||||
"Audit entry incompletely joined to audit properties: " + row, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Resolve the application and username
|
||||
String auditAppName = (String) propertyValueDAO.getPropertyValueById(row.getAuditAppNameId()).getSecond();
|
||||
Long auditUserId = row.getAuditUserId();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user