Compare commits

...

54 Commits
10.13 ... 11.5

Author SHA1 Message Date
Travis CI User
c28950843a [maven-release-plugin][skip ci] prepare release 11.5 2021-04-07 14:30:25 +00:00
Davide
28f1429a13 SEARCH-2782 use current transaction timestamp instead of current time as event time (#371) 2021-04-07 15:59:24 +02:00
dependabot-preview[bot]
9bd54efc10 Bump woodstox-core from 6.2.4 to 6.2.5 (#374) 2021-04-06 21:56:51 +00:00
Travis CI User
3c81ec949e [maven-release-plugin][skip ci] prepare for next development iteration 2021-04-06 12:52:40 +00:00
Travis CI User
53704a2c58 [maven-release-plugin][skip ci] prepare release 11.4 2021-04-06 12:52:36 +00:00
Alan Davis
b4455f7d60 version.schema=15000 as we will use a 1000 gap for minor versions rather than just 100 2021-04-06 10:25:53 +01:00
dependabot-preview[bot]
0617fbb0bf Bump maven-artifact from 3.6.3 to 3.8.1 (#369) 2021-04-05 21:43:17 +00:00
Travis CI User
f748334f1e [maven-release-plugin][skip ci] prepare for next development iteration 2021-04-05 18:37:13 +00:00
Travis CI User
08748e8af5 [maven-release-plugin][skip ci] prepare release 11.3 2021-04-05 18:37:09 +00:00
evasques
ce62fb1da3 MNT-20500 - Admin console breaks with serialised objects (#291)
* Added macro convertToJSON to recursively parse hashes and enumerables
* Added attempt/recover in macros to handle errors and not break the page
* Changed the output of serialized objects to JSON format
2021-04-05 17:52:15 +01:00
Nicolas Barithel
34f360211f Externalize the nodeServiceCleanup CRON expression (#326) 2021-03-31 10:17:58 +03:00
Travis CI User
b559e78827 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-30 14:29:34 +00:00
Travis CI User
1add8a0f08 [maven-release-plugin][skip ci] prepare release 11.2 2021-03-30 14:29:29 +00:00
dependabot-preview[bot]
5eb8767f4c Bump commons-lang3 from 3.11 to 3.12.0 (#324) 2021-03-30 12:52:05 +00:00
dependabot-preview[bot]
7fb3386413 Bump dependency.jackson.version from 2.12.1 to 2.12.2 (#329) 2021-03-30 12:44:26 +00:00
dependabot-preview[bot]
22945a30ea Bump commons-net from 3.7.2 to 3.8.0 (#304) 2021-03-30 12:14:48 +00:00
dependabot-preview[bot]
fc531f64ed Bump dependency.camel.version from 3.7.0 to 3.7.1 (#303) 2021-03-30 12:14:33 +00:00
dependabot-preview[bot]
98090ac48c Bump dependency.webscripts.version from 8.17 to 8.18 (#337) 2021-03-30 11:54:17 +00:00
dependabot-preview[bot]
33b64f483d Bump dependency.cxf.version from 3.4.2 to 3.4.3 (#354) 2021-03-30 11:50:35 +00:00
dependabot-preview[bot]
5e2d939f4e Bump json from 20201115 to 20210307 (#343) 2021-03-30 11:28:18 +00:00
dependabot-preview[bot]
26dbcd3e79 Bump cmis from 1.27 to 1.29 (#365) 2021-03-30 11:12:32 +00:00
dependabot-preview[bot]
8ec9fa5f5e Bump utility from 3.0.43 to 3.0.44 (#364) 2021-03-30 10:46:44 +00:00
dependabot-preview[bot]
578becd586 Bump joda-time from 2.10.9 to 2.10.10 (#277) 2021-03-30 10:35:59 +00:00
dependabot[bot]
1f6774f2ef Bump junit from 4.13 to 4.13.1 (#271) 2021-03-30 10:19:38 +00:00
dependabot-preview[bot]
9ff5f3b843 Bump dependency.tika.version from 1.25 to 1.26 (#366) 2021-03-29 21:57:43 +00:00
Travis CI User
9e3bb59067 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-29 13:44:23 +00:00
Travis CI User
db47063830 [maven-release-plugin][skip ci] prepare release 11.1 2021-03-29 13:44:19 +00:00
Tom Page
562479bde4 SEARCH-2768 Add callback feature for asynchronous ACL updates. (#357)
* SEARCH-2768 Add callback feature for asynchronous ACL updates.

Change default for user filter to empty, as changes from all users could affect metadata
or permissions which might need to be indexing by the enterprise Elasticsearch Connector.

* SEARCH-2768 Add unit test for new listeners.

* SEARCH-2768 Rename listener callback function.

* SEARCH-2768 Add unit test to test suite.
2021-03-29 11:31:36 +01:00
Travis CI User
e738e0a0fb [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-27 15:37:29 +00:00
Travis CI User
eb703c19aa [maven-release-plugin][skip ci] prepare release 11.0 2021-03-27 15:37:25 +00:00
alandavis
b772205539 Switch master to support ACS 7.1.0
* incremented pom versions to 11.0 so that 9 may be used by 7.0.1 and 10 for 7.0.2
* version.schema not changed this time as it had already been incremented by 100 to 14100
2021-03-27 09:45:27 +00:00
Travis CI User
b9c6b59129 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-26 18:20:03 +00:00
Travis CI User
cf7ce72209 [maven-release-plugin][skip ci] prepare release 9.6 2021-03-26 18:19:57 +00:00
alandavis
7a58014c32 Remove whitesource token as we don't use whitesource any more 2021-03-26 17:40:31 +00:00
Travis CI User
e964aab211 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-26 14:36:33 +00:00
Travis CI User
2d3cac3c27 [maven-release-plugin][skip ci] prepare release 9.5 2021-03-26 14:36:29 +00:00
evasques
3a495f7b3f MNT-22295 - FixedACLJob not processing all nodes due to unordered results (#359)
* Added method selectNodesWithAspects that accepts a boolean as param to order values
* Added param ordered to IdsEntity class
* Added optional ordered param to the query template that orderes the results by node id in asc order
* Added method getNodesWithAspects that accepts a boolean as param to order values in nodeDAO
* FixedACLUpdater Job calls the new getNodesWithAspects, with the ordered param as true
2021-03-26 13:11:32 +00:00
Travis CI User
949e257f19 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-25 23:35:22 +00:00
Travis CI User
dfb34140ac [maven-release-plugin][skip ci] prepare release 9.4 2021-03-25 23:35:17 +00:00
dependabot-preview[bot]
c1f78b1a17 Bump restapi from 1.56 to 1.57 (#361) 2021-03-25 22:58:09 +00:00
Travis CI User
8b70483aa0 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-24 13:30:20 +00:00
Travis CI User
3ebeac2eb4 [maven-release-plugin][skip ci] prepare release 9.3 2021-03-24 13:30:16 +00:00
Denis Ungureanu
d91a552925 ACS-1252 : Add tests for the JMS/ActiveMQ/Camel configuration in *alfresco-community-repo* (#356)
- fix messaging context for tests by adding missing mocked beans and properties
   - add tests for amqp, jms, activemq protocols
   - add travis job to run messaging tests
2021-03-24 14:13:37 +02:00
Bruno Bossola
8c91145b39 Revert "[ACS-1291] Asynchronous mechanism to send events (#351)" as no events are sent to AMQ with this change
This reverts commit f446031069.
2021-03-24 11:53:12 +00:00
Travis CI User
86fcf67016 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-19 16:57:50 +00:00
Travis CI User
48c85ec24f [maven-release-plugin][skip ci] prepare release 9.2 2021-03-19 16:57:46 +00:00
Bruno Bossola
f446031069 [ACS-1291] Asynchronous mechanism to send events (#351)
* Performance optimisation spike

* Event2 is now sending event asynchronously

* Now forcing synchronous calls in tests for events2

* Now qualifying the event service used in tests

Co-authored-by: Nana Insaidoo <insaidoo.nana@yahoo.it>
2021-03-19 11:08:13 +00:00
Travis CI User
a9dabb0e99 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-12 16:47:18 +00:00
Travis CI User
bdc95019ae [maven-release-plugin][skip ci] prepare release 9.1 2021-03-12 16:47:13 +00:00
evasques
ace87c9c3b MNT-21898 Unexpected ACLs when job runs Fix (#344)
* On move node, verify if parent has pending acl aspect applied and consider the pending shared ACL to update inheritance to avoid ending up with mixed permissions as children of pending acl nodes do not have the correct acls and when moved, keep their wrong acl.
* Add public method setInheritanceForChildren that receives an additional param: forceSharedACL. If an unexpected ACL occurs in a child, it can be overridden by setting it.
* Implement method setInheritanceForChildren that receives an additional parameter: forceSharedACL
* Add method setFixedAcls that receives an additional parameter: forceSharedACL - When a child node has an unexpected ACL, setting this parameter to true will force it to assume the new shared ACL instead of throwing a concurrency exception. When the shared ACL is forces, a warning is thrown in the log informing on what node exactly are we forcing the ACL. This is only possible when the child ACL is type SHARED and when it has an unexpected ACL
* All methods that called setFixedAcls without the new parameter will continue to operate as normal, as having forceSharedACL=false
* Added property forceSharedACL to the FixedACLUpdaterJob. If set to true it will force shared ACL to propagate through children even if there is an unexpected ACL
* When there is a exception detected when doing setInheritanceForChildren on the job, catch and log the error, but do not rollback the entire batch
* On copy/move unit tests I changed the ACL of the target folders on copy and move tests so that the old shared ACL accessed was never the same for origin and target folders as happens when performing these operations between sites
* Added unit test to verify fix for MNT-21898 - testAsyncWithNodeMoveChildToChildPendingFolder
* Added unit test to verify system property for the job: forceSharedACL - testAsyncWithErrorsForceSharedACL
2021-03-12 14:25:58 +00:00
Travis CI User
af8b556bf8 [maven-release-plugin][skip ci] prepare for next development iteration 2021-03-10 22:59:09 +00:00
Travis CI User
5990fadb3b [maven-release-plugin][skip ci] prepare release 9.0 2021-03-10 22:59:05 +00:00
alandavis
08b62afb10 Missed setting <acs.version.revision>1</acs.version.revision> 2021-03-10 21:51:09 +00:00
alandavis
d4bae73b86 Use master for ACS 7.0.1
* version.schema=14100 (100 more than used for ACS 7.0.0 originally)
* Reset pom.xml version to next major number (9), as 8.x will be used for 7.0.0 HFs
2021-03-10 21:15:34 +00:00
41 changed files with 955 additions and 165 deletions

View File

@@ -25,10 +25,6 @@
<url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
</pluginRepository>
</pluginRepositories>
<properties>
<!-- WhiteSource token -->
<org.whitesource.orgToken>${env.WHITESOURCE_API_KEY}</org.whitesource.orgToken>
</properties>
</profile>
</profiles>

View File

@@ -177,6 +177,11 @@ jobs:
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
script: travis_wait 20 mvn -B test -pl repository -Dtest=AllDBTestsTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - Messaging tests"
before_script:
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
script: travis_wait 20 mvn -B test -pl repository -Dtest=CamelRoutesTest,CamelComponentsTest
- name: "Remote-api - AppContext01TestSuite"
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.1 postgres -c 'max_connections=300'

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<dependencies>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<properties>
@@ -167,7 +167,7 @@
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.2.4</version>
<version>6.2.5</version>
</dependency>
<!-- the cxf libs were updated, see dependencyManagement section -->

View File

@@ -9,6 +9,6 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
</project>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<profiles>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<modules>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<developers>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<developers>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<properties>

26
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -22,7 +22,7 @@
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>0</acs.version.minor>
<acs.version.minor>1</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.label />
@@ -55,14 +55,14 @@
<dependency.spring.version>5.3.3</dependency.spring.version>
<dependency.antlr.version>3.5.2</dependency.antlr.version>
<dependency.jackson.version>2.12.1</dependency.jackson.version>
<dependency.jackson.version>2.12.2</dependency.jackson.version>
<dependency.jackson-databind.version>${dependency.jackson.version}</dependency.jackson-databind.version>
<dependency.cxf.version>3.4.2</dependency.cxf.version>
<dependency.cxf.version>3.4.3</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.18</dependency.webscripts.version>
<dependency.bouncycastle.version>1.68</dependency.bouncycastle.version>
<dependency.mockito-core.version>3.8.0</dependency.mockito-core.version>
<dependency.org-json.version>20201115</dependency.org-json.version>
<dependency.org-json.version>20210307</dependency.org-json.version>
<dependency.commons-dbcp.version>1.4-DBCP330</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.8.0</dependency.commons-io.version>
<dependency.gson.version>2.8.5</dependency.gson.version>
@@ -73,14 +73,14 @@
<dependency.slf4j.version>1.7.30</dependency.slf4j.version>
<dependency.gytheio.version>0.12</dependency.gytheio.version>
<dependency.groovy.version>2.5.9</dependency.groovy.version>
<dependency.tika.version>1.25</dependency.tika.version>
<dependency.tika.version>1.26</dependency.tika.version>
<dependency.spring-security.version>5.4.1</dependency.spring-security.version>
<dependency.truezip.version>7.7.10</dependency.truezip.version>
<dependency.poi.version>4.1.2</dependency.poi.version>
<dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
<dependency.keycloak.version>11.0.0-alfresco-001</dependency.keycloak.version>
<dependency.jboss.logging.version>3.4.1.Final</dependency.jboss.logging.version>
<dependency.camel.version>3.7.0</dependency.camel.version>
<dependency.camel.version>3.7.1</dependency.camel.version>
<dependency.activemq.version>5.16.1</dependency.activemq.version>
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
<dependency.awaitility.version>4.0.3</dependency.awaitility.version>
@@ -102,10 +102,10 @@
<dependency.postgresql.version>42.2.19</dependency.postgresql.version>
<dependency.mysql.version>8.0.23</dependency.mysql.version>
<dependency.mariadb.version>2.7.2</dependency.mariadb.version>
<dependency.tas-utility.version>3.0.43</dependency.tas-utility.version>
<dependency.tas-utility.version>3.0.44</dependency.tas-utility.version>
<dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.56</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.27</dependency.tas-cmis.version>
<dependency.tas-restapi.version>1.57</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.29</dependency.tas-cmis.version>
<dependency.tas-email.version>1.8</dependency.tas-email.version>
<dependency.tas-webdav.version>1.6</dependency.tas-webdav.version>
<dependency.tas-ftp.version>1.5</dependency.tas-ftp.version>
@@ -116,7 +116,7 @@
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>HEAD</tag>
<tag>11.5</tag>
</scm>
<distributionManagement>
@@ -679,7 +679,7 @@
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.9</version>
<version>2.10.10</version>
</dependency>
<!-- provided dependencies -->
@@ -694,7 +694,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<dependencies>

View File

@@ -4,31 +4,71 @@
<#macro dateFormat date>${date?string("dd MMM yyyy HH:mm:ss 'GMT'Z '('zzz')'")}</#macro>
<#macro propValue p>
<#if p.value??>
<#if p.value?is_date>
<@dateFormat p.value />
<#elseif p.value?is_boolean>
${p.value?string}
<#elseif p.value?is_number>
${p.value?c}
<#elseif p.value?is_string>
${p.value?html}
<#elseif p.value?is_hash>
<#assign result = "{"/>
<#assign first = true />
<#list p.value?keys as key>
<#if first = false>
<#assign result = result + ", "/>
<#attempt>
<#if p.value??>
<#if p.value?is_date>
<@dateFormat p.value />
<#elseif p.value?is_boolean>
${p.value?string}
<#elseif p.value?is_number>
${p.value?c}
<#elseif p.value?is_string>
${p.value?html}
<#elseif p.value?is_hash || p.value?is_enumerable>
<@convertToJSON p.value />
</#if>
<#else>
${null}
</#if>
<#recover>
<span style="color:red">${.error}</span>
</#attempt>
</#macro>
<#macro convertToJSON v>
<#attempt>
<#if v??>
<#if v?is_date>
<@dateFormat v />
<#elseif v?is_boolean>
${v?string}
<#elseif v?is_number>
${v?c}
<#elseif v?is_string>
"${v?string}"
<#elseif v?is_hash>
<@compress single_line=true>
{
<#assign first = true />
<#list v?keys as key>
<#if first = false>,</#if>
"${key}":
<#if v[key]??>
<@convertToJSON v[key] />
<#else>
${null}
</#if>
<#assign first = false/>
</#list>
}
</@compress>
<#elseif v?is_enumerable>
<#assign first = true />
<@compress single_line=true>
[
<#list v as item>
<#if first = false>,</#if>
<@convertToJSON item />
<#assign first = false/>
</#list>
]
</@compress>
</#if>
<#assign result = result + "${key}=${p.value[key]?html}" />
<#assign first = false/>
</#list>
<#assign result = result + "}"/>
${result}
</#if>
<#else>
${null}
</#if>
<#else>
${null}
</#if>
<#recover>
<span style="color:red">${.error}</span>
</#attempt>
</#macro>
<#macro contentUrl nodeRef prop>
${url.serviceContext}/api/node/${nodeRef?replace("://","/")}/content;${prop?url}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>8.424-SNAPSHOT</version>
<version>11.5</version>
</parent>
<dependencies>
@@ -82,7 +82,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
@@ -191,7 +191,7 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.6.3</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>de.schlichtherle.truezip</groupId>
@@ -383,7 +383,7 @@
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.2.4</version>
<version>6.2.5</version>
</dependency>
<!-- GData -->
@@ -810,7 +810,7 @@
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.7.2</version>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -40,6 +40,7 @@ public class IdsEntity
private Long idThree;
private Long idFour;
private List<Long> ids;
private boolean ordered;
public Long getIdOne()
{
return idOne;
@@ -80,4 +81,12 @@ public class IdsEntity
{
this.ids = ids;
}
public boolean isOrdered()
{
return ordered;
}
public void setOrdered(boolean ordered)
{
this.ordered = ordered;
}
}

View File

@@ -1483,7 +1483,17 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
// Update ACLs for moved tree
Long newParentAclId = newParentNode.getAclId();
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
// Verify if parent has aspect applied and ACL's are pending
if (hasNodeAspect(oldParentNodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
{
Long oldParentSharedAclId = (Long) this.getNodeProperty(oldParentNodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
accessControlListDAO.updateInheritance(newChildNodeId, oldParentSharedAclId, newParentAclId);
}
else
{
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
}
}
// Done
@@ -2746,6 +2756,22 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
selectNodesWithAspects(qnameIds, minNodeId, maxNodeId, resultsCallback);
}
@Override
public void getNodesWithAspects(
Set<QName> aspectQNames,
Long minNodeId, Long maxNodeId, boolean ordered,
NodeRefQueryCallback resultsCallback)
{
Set<Long> qnameIdsSet = qnameDAO.convertQNamesToIds(aspectQNames, false);
if (qnameIdsSet.size() == 0)
{
// No point running a query
return;
}
List<Long> qnameIds = new ArrayList<Long>(qnameIdsSet);
selectNodesWithAspects(qnameIds, minNodeId, maxNodeId, ordered, resultsCallback);
}
/**
* @return Returns a writable copy of the cached aspects set
*/
@@ -4917,6 +4943,10 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
List<Long> qnameIds,
Long minNodeId, Long maxNodeId,
NodeRefQueryCallback resultsCallback);
protected abstract void selectNodesWithAspects(
List<Long> qnameIds,
Long minNodeId, Long maxNodeId, boolean ordered,
NodeRefQueryCallback resultsCallback);
protected abstract Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex);
protected abstract int updateNodeAssoc(Long id, int assocIndex);
protected abstract int deleteNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId);

View File

@@ -405,6 +405,20 @@ public interface NodeDAO extends NodeBulkLoader
Long minNodeId, Long maxNodeId,
NodeRefQueryCallback resultsCallback);
/**
* Get nodes with aspects between the given ranges, ordering the results optionally
*
* @param aspectQNames the aspects that must be on the nodes
* @param minNodeId the minimum node ID (inclusive)
* @param maxNodeId the maximum node ID (exclusive)
* @param ordered if the results are to be ordered by nodeID
* @param resultsCallback callback to process results
*/
public void getNodesWithAspects(
Set<QName> aspectQNames,
Long minNodeId, Long maxNodeId, boolean ordered,
NodeRefQueryCallback resultsCallback);
/*
* Node Assocs
*/

View File

@@ -764,6 +764,31 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
template.select(SELECT_NODES_WITH_ASPECT_IDS, parameters, resultHandler);
}
@Override
protected void selectNodesWithAspects(
List<Long> qnameIds,
Long minNodeId, Long maxNodeId, boolean ordered,
final NodeRefQueryCallback resultsCallback)
{
@SuppressWarnings("rawtypes")
ResultHandler resultHandler = new ResultHandler()
{
public void handleResult(ResultContext context)
{
NodeEntity entity = (NodeEntity) context.getResultObject();
Pair<Long, NodeRef> nodePair = new Pair<Long, NodeRef>(entity.getId(), entity.getNodeRef());
resultsCallback.handle(nodePair);
}
};
IdsEntity parameters = new IdsEntity();
parameters.setIdOne(minNodeId);
parameters.setIdTwo(maxNodeId);
parameters.setIds(qnameIds);
parameters.setOrdered(ordered);
template.select(SELECT_NODES_WITH_ASPECT_IDS, parameters, resultHandler);
}
@Override
protected Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex)
{

View File

@@ -337,6 +337,13 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false, asyncCall, true);
return changes;
}
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall, boolean forceSharedACL)
{
List<AclChange> changes = new ArrayList<AclChange>();
setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false, asyncCall, true, forceSharedACL);
return changes;
}
public void updateChangedAcls(NodeRef startingPoint, List<AclChange> changes)
{
@@ -362,6 +369,29 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, false, true);
}
/**
* Support to set a shared ACL on a node and all of its children
*
* @param nodeId
* the parent node
* @param inheritFrom
* the parent node's ACL
* @param mergeFrom
* the shared ACL, if already known. If <code>null</code>, will be retrieved / created lazily
* @param changes
* the list in which to record changes
* @param set
* set the shared ACL on the parent ?
* @param asyncCall
* function may require asynchronous call depending the execution time; if time exceeds configured <code>fixedAclMaxTransactionTime</code> value,
* recursion is stopped using propagateOnChildren parameter(set on false) and those nodes for which the method execution was not finished
* in the classical way, will have ASPECT_PENDING_FIX_ACL, which will be used in {@link FixedAclUpdater} for later processing
*/
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
{
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, false, true, false);
}
/**
* Support to set a shared ACL on a node and all of its children
*
@@ -379,8 +409,10 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
* function may require asynchronous call depending the execution time; if time exceeds configured <code>fixedAclMaxTransactionTime</code> value,
* recursion is stopped using propagateOnChildren parameter(set on false) and those nodes for which the method execution was not finished
* in the classical way, will have ASPECT_PENDING_FIX_ACL, which will be used in {@link FixedAclUpdater} for later processing
* @param forceSharedACL
* When a child node has an unexpected ACL, force it to assume the new shared ACL instead of throwing a concurrency exception.
*/
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren, boolean forceSharedACL)
{
if (log.isDebugEnabled())
{
@@ -431,14 +463,14 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
if (acl == null)
{
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren, forceSharedACL);
}
else
{
// Still has old shared ACL or already replaced
if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom) || acl.equals(currentAcl))
{
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren, forceSharedACL);
}
else
{
@@ -457,7 +489,20 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
}
else if (dbAcl.getAclType() == ACLType.SHARED)
{
throw new ConcurrencyFailureException("setFixedAcls: unexpected shared acl: "+dbAcl);
if (forceSharedACL)
{
log.warn("Forcing shared ACL on node: " + child.getId() + " ( "
+ nodeDAO.getNodePair(child.getId()).getSecond() + ") - " + dbAcl);
sharedAclToReplace = acl;
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace,
changes, false, asyncCall, propagateOnChildren, forceSharedACL);
}
else
{
throw new ConcurrencyFailureException(
"setFixedAcls: unexpected shared acl: " + dbAcl + " on node " + child.getId() + " ( "
+ nodeDAO.getNodePair(child.getId()).getSecond() + ")");
}
}
}
}
@@ -506,7 +551,7 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
*
*/
private boolean setFixAclPending(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace,
List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren, boolean forceSharedACL)
{
// check transaction time
long transactionStartTime = AlfrescoTransactionSupport.getTransactionStartTime();
@@ -514,7 +559,7 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
if (transactionTime < fixedAclMaxTransactionTime)
{
// make regular method call if time is under max transaction configured time
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren);
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren, forceSharedACL);
return true;
}

View File

@@ -91,6 +91,11 @@ public interface AccessControlListDAO
*/
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall);
/**
* Set the inheritance on a given node and it's children. If an unexpected ACL occurs in a child, it can be overriden by setting forceSharedACL
*/
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall, boolean forceSharedACL);
public Long getIndirectAcl(NodeRef nodeRef);
public Long getInheritedAcl(NodeRef nodeRef);

View File

@@ -35,9 +35,12 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.common.collect.Sets;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.batch.BatchProcessWorkProvider;
import org.alfresco.repo.batch.BatchProcessor;
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
import org.alfresco.repo.lock.JobLockService;
@@ -50,6 +53,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.PermissionServicePolicies;
import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -64,6 +68,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.ConcurrencyFailureException;
/**
* Finds nodes with ASPECT_PENDING_FIX_ACL aspect and sets fixed ACLs for them
@@ -79,18 +85,22 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
public static final String FIXED_ACL_ASYNC_REQUIRED_KEY = "FIXED_ACL_ASYNC_REQUIRED";
public static final String FIXED_ACL_ASYNC_CALL_KEY = "FIXED_ACL_ASYNC_CALL";
protected static final QName LOCK_Q_NAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "FixedAclUpdater");
/** A set of listeners to receive callback events whenever permissions are updated by this class. */
private static Set<FixedAclUpdaterListener> listeners = Sets.newConcurrentHashSet();
private ApplicationContext applicationContext;
private JobLockService jobLockService;
private TransactionService transactionService;
private AccessControlListDAO accessControlListDAO;
private NodeDAO nodeDAO;
private QName lockQName = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "FixedAclUpdater");
private long lockTimeToLive = 10000;
private long lockRefreshTime = lockTimeToLive / 2;
private int maxItemBatchSize = 100;
private int numThreads = 4;
private boolean forceSharedACL = false;
private ClassPolicyDelegate<OnInheritPermissionsDisabled> onInheritPermissionsDisabledDelegate;
private PolicyComponent policyComponent;
@@ -132,6 +142,11 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
this.maxItemBatchSize = maxItemBatchSize;
}
public void setForceSharedACL(boolean forceSharedACL)
{
this.forceSharedACL = forceSharedACL;
}
public void setLockTimeToLive(long lockTimeToLive)
{
this.lockTimeToLive = lockTimeToLive;
@@ -148,6 +163,12 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
this.policyIgnoreUtil = policyIgnoreUtil;
}
/** Register a {@link FixedAclUpdaterListener} to be notified when a node is updated by an instance of this class. */
public static void registerListener(FixedAclUpdaterListener listener)
{
listeners.add(listener);
}
public void init()
{
onInheritPermissionsDisabledDelegate = policyComponent
@@ -182,7 +203,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
public List<NodeRef> execute() throws Throwable
{
getNodesCallback.init();
nodeDAO.getNodesWithAspects(aspects, getNodesCallback.getMinNodeId(), null, getNodesCallback);
nodeDAO.getNodesWithAspects(aspects, getNodesCallback.getMinNodeId(), null, true, getNodesCallback);
getNodesCallback.done();
return getNodesCallback.getNodes();
@@ -231,7 +252,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
}
}
private class AclWorker implements BatchProcessor.BatchProcessWorker<NodeRef>
protected class AclWorker implements BatchProcessor.BatchProcessWorker<NodeRef>
{
private Set<QName> aspects = new HashSet<>(1);
@@ -253,7 +274,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
{
}
public void process(final NodeRef nodeRef) throws Throwable
public void process(final NodeRef nodeRef)
{
RunAsWork<Void> findAndUpdateAclRunAsWork = new RunAsWork<Void>()
{
@@ -265,36 +286,48 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
log.debug(String.format("Processing node %s", nodeRef));
}
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do not
// process
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
try
{
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do
// not
// process
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
{
accessControlListDAO.removePendingAclAspect(nodeId);
return null;
}
// retrieve acl properties from node
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
// set inheritance using retrieved prop
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true,
forceSharedACL);
// Remove aspect
accessControlListDAO.removePendingAclAspect(nodeId);
return null;
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
{
boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport
.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
.get(ContentModel.TYPE_BASE);
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
}
}
// retrieve acl properties from node
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
// set inheritance using retrieved prop
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true);
// Remove aspect
accessControlListDAO.removePendingAclAspect(nodeId);
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
catch (Exception e)
{
boolean transformedToAsyncOperation = toBoolean(
(Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
.get(ContentModel.TYPE_BASE);
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
log.error("Job could not process pending ACL node " + nodeRef + ": " + e);
e.printStackTrace();
}
listeners.forEach(listener -> listener.permissionsUpdatedAsynchronously(nodeRef));
if (log.isDebugEnabled())
{
log.debug(String.format("Node processed %s", nodeRef));
@@ -308,8 +341,15 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
AuthenticationUtil.runAs(findAndUpdateAclRunAsWork, AuthenticationUtil.getSystemUserName());
}
};
private class GetNodesWithAspectCallback implements NodeRefQueryCallback
/** Create a new AclWorker. */
protected AclWorker createAclWorker()
{
return new AclWorker();
}
class GetNodesWithAspectCallback implements NodeRefQueryCallback
{
private List<NodeRef> nodes = new ArrayList<>();
private long minNodeId;
@@ -400,11 +440,11 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
try
{
lockToken = jobLockService.getLock(lockQName, lockTimeToLive, 0, 1);
jobLockService.refreshLock(lockToken, lockQName, lockRefreshTime, jobLockRefreshCallback);
lockToken = jobLockService.getLock(LOCK_Q_NAME, lockTimeToLive, 0, 1);
jobLockService.refreshLock(lockToken, LOCK_Q_NAME, lockRefreshTime, jobLockRefreshCallback);
AclWorkProvider provider = new AclWorkProvider();
AclWorker worker = new AclWorker();
AclWorker worker = createAclWorker();
BatchProcessor<NodeRef> bp = new BatchProcessor<>("FixedAclUpdater",
transactionService.getRetryingTransactionHelper(), provider, numThreads, maxItemBatchSize, applicationContext,
log, 100);
@@ -421,7 +461,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
jobLockRefreshCallback.isActive.set(false);
if (lockToken != null)
{
jobLockService.releaseLock(lockToken, lockQName);
jobLockService.releaseLock(lockToken, LOCK_Q_NAME);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.domain.permissions;
import org.alfresco.service.cmr.repository.NodeRef;
/** Listener to receive callback events when permissions are asynchronously updated with the {@link FixedAclUpdater}. */
public interface FixedAclUpdaterListener
{
/** Callback method for when permissions have been updated by the FixedAclUpdater. */
void permissionsUpdatedAsynchronously(NodeRef nodeRef);
}

View File

@@ -27,12 +27,16 @@ package org.alfresco.repo.event2;
import java.io.Serializable;
import java.net.URI;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.Transaction;
import org.alfresco.repo.event.v1.model.EventType;
import org.alfresco.repo.event.v1.model.RepoEvent;
import org.alfresco.repo.event2.filter.ChildAssociationTypeFilter;
@@ -94,6 +98,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
private TransactionService transactionService;
private PersonService personService;
protected NodeResourceHelper nodeResourceHelper;
private NodeDAO nodeDAO;
private NodeTypeFilter nodeTypeFilter;
private ChildAssociationTypeFilter childAssociationTypeFilter;
@@ -113,6 +118,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "personService", personService);
PropertyCheck.mandatory(this, "nodeResourceHelper", nodeResourceHelper);
PropertyCheck.mandatory(this, "nodeDAO", nodeDAO);
this.nodeTypeFilter = eventFilterRegistry.getNodeTypeFilter();
this.childAssociationTypeFilter = eventFilterRegistry.getChildAssociationTypeFilter();
@@ -145,6 +151,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
new JavaBehaviour(this, "beforeDeleteAssociation"));
}
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
@@ -370,13 +381,22 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
private EventInfo getEventInfo(String user)
{
return new EventInfo().setTimestamp(ZonedDateTime.now())
return new EventInfo().setTimestamp(getCurrentTransactionTimestamp())
.setId(UUID.randomUUID().toString())
.setTxnId(AlfrescoTransactionSupport.getTransactionId())
.setPrincipal(user)
.setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId()));
}
private ZonedDateTime getCurrentTransactionTimestamp()
{
Long currentTransactionId = nodeDAO.getCurrentTransactionId(false);
Transaction transaction = nodeDAO.getTxnById(currentTransactionId);
Instant commitTimeMs = Instant.ofEpochMilli(transaction.getCommitTimeMs());
ZonedDateTime timestamp = ZonedDateTime.ofInstant(commitTimeMs, ZoneOffset.UTC);
return timestamp;
}
@Override
protected void onBootstrap(ApplicationEvent applicationEvent)
{

View File

@@ -41,6 +41,7 @@
<property name="event2MessageProducer" ref="event2MessageProducer"/>
<property name="transactionService" ref="transactionService"/>
<property name="personService" ref="personService"/>
<property name="nodeDAO" ref="nodeDAO"/>
</bean>
<bean id="baseNodeResourceHelper" abstract="true">

View File

@@ -779,6 +779,7 @@
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
and na.qname_id in
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
<if test="ordered == true">order by node.id ASC</if>
</select>
<!-- Common results for result_NodeAssoc -->

View File

@@ -117,6 +117,7 @@
<property name="nodeDAO" ref="nodeDAO"/>
<property name="maxItemBatchSize" value="${system.fixedACLsUpdater.maxItemBatchSize}"/>
<property name="numThreads" value="${system.fixedACLsUpdater.numThreads}"/>
<property name="forceSharedACL" value="${system.fixedACLsUpdater.forceSharedACL}"/>
<property name="lockTimeToLive" value="${system.fixedACLsUpdater.lockTTL}"/>
<property name="policyComponent" ref="policyComponent"/>
<property name="policyIgnoreUtil" ref="policyIgnoreUtil"/>

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
version.schema=14002
version.schema=15000
# Directory configuration
@@ -220,6 +220,8 @@ system.content.deletionFailureAction=IGNORE
# The CRON expression to trigger the deletion of resources associated with orphaned content.
system.content.orphanCleanup.cronExpression=0 0 4 * * ?
# The CRON expression to trigger the cleanup of deleted nodes and dangling transactions that are old enough
system.nodeServiceCleanup.cronExpression=0 0 21 * * ?
# When transforming archive files (.zip etc) into text representations (such as
# for full text indexing), should the files within the archive be processed too?
@@ -1082,6 +1084,8 @@ system.fixedACLsUpdater.lockTTL=10000
system.fixedACLsUpdater.maxItemBatchSize=100
# fixedACLsUpdater - the number of threads to use
system.fixedACLsUpdater.numThreads=4
# fixedACLsUpdater - Force shared ACL to propagate through children even if there is an unexpected ACL
system.fixedACLsUpdater.forceSharedACL=false
# fixedACLsUpdater cron expression - fire at midnight every day
system.fixedACLsUpdater.cronExpression=0 0 0 * * ?
@@ -1204,7 +1208,7 @@ repo.event2.filter.nodeAspects=sys:*
repo.event2.filter.childAssocTypes=rn:rendition
# Comma separated list of users which should be excluded
# Note: username's case-sensitivity depends on the {user.name.caseSensitive} setting
repo.event2.filter.users=System, null
repo.event2.filter.users=
# Topic name
repo.event2.topic.endpoint=amqp:topic:alfresco.repo.event2
@@ -1225,4 +1229,4 @@ system.new-node-transaction-indexes.ignored=true
# Allows the configuration of maximum limits of the temp files to be deleted or the maximum time allowed to run for the job
system.tempFileCleaner.maxFilesToDelete=
system.tempFileCleaner.maxTimeToRun=
system.tempFileCleaner.maxTimeToRun=

View File

@@ -107,7 +107,7 @@
</property>
</bean>
<bean id="nodeServiceCleanupTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="cronExpression" value="0 0 21 * * ?"/>
<property name="cronExpression" value="${system.nodeServiceCleanup.cronExpression}"/>
<property name="startDelay" value="${system.cronJob.startDelayMilliseconds}"/>
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

View File

@@ -170,6 +170,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.content.caching.quota.UnlimitedQuotaStrategyTest.class,
org.alfresco.repo.content.caching.CachingContentStoreTest.class,
org.alfresco.repo.content.caching.ContentCacheImplTest.class,
org.alfresco.repo.domain.permissions.FixedAclUpdaterUnitTest.class,
org.alfresco.repo.domain.propval.PropertyTypeConverterTest.class,
org.alfresco.repo.search.MLAnaysisModeExpansionTest.class,
org.alfresco.repo.search.DocumentNavigatorTest.class,

View File

@@ -0,0 +1,99 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.messaging.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
/**
* Tests Camel components defined in the application's Spring context
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/test-messaging-context.xml")
public class CamelComponentsTest {
@Autowired
protected CamelContext camelContext;
@Produce("activemq:queue:alfresco.test")
protected ProducerTemplate activemqTemplate;
@Produce("amqp:queue:alfresco.test")
protected ProducerTemplate amqpTemplate;
@Produce("jms:queue:alfresco.test")
protected ProducerTemplate jmsTemplate;
@Test
public void testActivemqComponent()
{
final String msg = "ping <activemq>";
activemqTemplate.sendBody(msg);
final Object reply = camelContext
.createConsumerTemplate()
.receiveBody("activemq:queue:alfresco.test", 2000);
assertEquals(msg, reply);
}
@Test
public void testAmqpComponent()
{
final String msg = "ping <amqp>";
amqpTemplate.sendBody(msg);
final Object reply = camelContext
.createConsumerTemplate()
.receiveBody("amqp:queue:alfresco.test", 2000);
assertEquals(msg, reply);
}
@Test
public void testJmsComponent()
{
final String msg = "ping <jms>";
jmsTemplate.sendBody(msg);
final Object reply = camelContext
.createConsumerTemplate()
.receiveBody("jms:queue:alfresco.test", 2000);
assertEquals(msg, reply);
}
}

View File

@@ -61,76 +61,76 @@ public class CamelRoutesTest
@Produce("direct-vm:alfresco.test.1")
protected ProducerTemplate template1;
@Produce("direct-vm:alfresco.test.2")
protected ProducerTemplate template2;
@Produce("direct-vm:alfresco.default")
protected ProducerTemplate template3;
@Produce("direct-vm:alfresco.test.transacted")
protected ProducerTemplate template4;
@Autowired
protected MockExceptionProcessor messagingExceptionProcessor;
@Autowired
protected MockConsumer mockConsumer;
@Autowired
protected MockExceptionThrowingConsumer mockExceptionThrowingConsumer;
@Test
public void testMessageRouteXmlDefined() throws Exception {
String expectedBody = "<matched.>";
resultEndpoint1.expectedBodiesReceived(expectedBody);
template1.sendBody(expectedBody);
resultEndpoint1.assertIsSatisfied();
}
@Test
public void testMessageRoutePackageDefined() throws Exception {
String expectedBody = "<matched.>";
resultEndpoint2.expectedBodiesReceived(expectedBody);
template2.sendBody(expectedBody);
resultEndpoint2.assertIsSatisfied();
}
@Test
public void testMessageRouteXmlOverride() throws Exception {
String expectedBody = "<matched.>";
dlqEndpoint.expectedBodiesReceived(expectedBody);
template3.sendBody(expectedBody);
dlqEndpoint.assertIsSatisfied();
}
@Test
public void testTransactedRoute() throws Exception {
String expectedBody = "<matched.>";
template4.sendBody(expectedBody);
// Wait for Camel and ActiveMQ to process
Thread.sleep(2000);
// Test that our exception processor received the error
assertNotNull(messagingExceptionProcessor.getLastError());
assertTrue(messagingExceptionProcessor.getLastError().getClass().equals(
IllegalArgumentException.class));
// Check that an error was thrown the first time
assertTrue(mockExceptionThrowingConsumer.isErrorThrown());
assertNull(mockExceptionThrowingConsumer.getLastMessage());
// Check that the message was re-delivered to a second consumer
assertEquals(expectedBody, mockConsumer.getLastMessage());
}

View File

@@ -90,8 +90,8 @@ public class FixedAclUpdaterTest extends TestCase
private CheckOutCheckInService checkOutCheckInService;
private ContentService contentService;
private AuthorityService authorityService;
private static final long MAX_TRANSACTION_TIME_DEFAULT = 50;
private static final int[] filesPerLevelMoreFolders = { 5, 3, 1, 50 };
private static final long MAX_TRANSACTION_TIME_DEFAULT = 10;
private static final int[] filesPerLevelMoreFolders = { 5, 1, 1, 1, 1, 1, 1 };
private static final int[] filesPerLevelMoreFiles = { 5, 100 };
private long maxTransactionTime;
private static HashMap<Integer, Class<?>> errors;
@@ -306,7 +306,7 @@ public class FixedAclUpdaterTest extends TestCase
public void testSyncCopyNoTimeOut() throws FileExistsException, FileNotFoundException
{
NodeRef originalRef = createFolderHierarchyInRootForFolderTests("originFolder");
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("targetFolder");
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("targetFolder");
// Get ACLS for later comparison
ACLComparator aclComparatorOrigin = new ACLComparator(originalRef);
@@ -316,6 +316,19 @@ public class FixedAclUpdaterTest extends TestCase
maxTransactionTime = 86400000;
setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Set Shared permissions on origin
permissionService.setInheritParentPermissions(originalRef, true, false);
permissionService.setPermission(originalRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
@@ -343,7 +356,7 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(originalRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
@@ -354,14 +367,26 @@ public class FixedAclUpdaterTest extends TestCase
public void testAsyncWithNodeCopy()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeCopyTargetFolder",
ContentModel.TYPE_FOLDER);
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, false, false);
@@ -410,7 +435,7 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(folderRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
@@ -421,13 +446,26 @@ public class FixedAclUpdaterTest extends TestCase
public void testAsyncWithNodeCopyToPendingFolder()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, false, false);
@@ -487,7 +525,7 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(folderRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
@@ -499,13 +537,26 @@ public class FixedAclUpdaterTest extends TestCase
public void testAsyncWithNodeCopyParentToChildPendingFolder()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, false, false);
@@ -585,7 +636,151 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(folderRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
/*
* Move child of node that has the aspect to a child folder of a folder that also has the aspect applied before job
* runs
*/
@Test
public void testAsyncWithNodeMoveChildToChildPendingFolder()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveChildToChildPendingFolderOrigin");
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveChildToChildPendingFolderTarget");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Set permissions on a child to get a new shared ACL with pending acl nodes
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, true, false);
permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
return null;
}, false, true);
// Get target Folder with a pending ACL
NodeRef targetFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, targetRef);
assertNotNull("No children folders were found with pendingFixACl aspect", targetFolderWithPendingAcl);
NodeRef targetFolderWithPendingAclChild = nodeDAO
.getNodePair(getChild(nodeDAO.getNodePair(targetFolderWithPendingAcl).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetFolderWithPendingAcl);
aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
// Set permissions on origin folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(folderRef, true, false);
permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
return null;
}, false, true);
// Find a pending ACL folder
NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
NodeRef originFolderWithPendingAclChild = nodeDAO
.getNodePair(getChild(nodeDAO.getNodePair(originFolderWithPendingAcl).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorMovedNode = new ACLComparator(originFolderWithPendingAclChild);
aclComparatorMovedNode.setOriginalPermission(TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION);
// Move one pending folder into the other
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
fileFolderService.move(originFolderWithPendingAclChild, targetFolderWithPendingAclChild, "movedFolder");
return null;
}, false, true);
// Trigger job
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
assertTrue("Moved node did not inherit permissions from target",
aclComparatorMovedNode.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
assertTrue("Child of Pending Moved node did not inherit permissions from target",
aclComparatorMovedNode.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
assertFalse("Moved node kept original permissions", aclComparatorMovedNode.parentHasOriginalPermission());
assertFalse("Child of Moved node kept original permissions",
aclComparatorMovedNode.firstChildHasOriginalPermission());
}
finally
{
deleteNodes(folderRef);
deleteNodes(targetRefBase);
}
}
/*
* Create a conflicting ACL on a node and then try to run the job normally, without forcing the ACL to get the
* expected error and then run it again with the forcedShareACL property as true so it can override the problematic
* ACL
*/
@Test
public void testAsyncWithErrorsForceSharedACL()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithErrorsForceSharedACL");
try
{
// Set permissions on origin folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(folderRef, true, false);
permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
return null;
}, false, true);
// Find a pending ACL folder
NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
NodeRef originFolderWithPendingAclChild = nodeDAO
.getNodePair(getChild(nodeDAO.getNodePair(originFolderWithPendingAcl).getFirst())).getSecond();
// Create a new ACL elsewhere and put the shared ACL (from a child) on the pending node child to simulate
// conflict
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
NodeRef tempNode = createFile(fileFolderService, folderRef, "testAsyncWithErrorsForceSharedACLTemp",
ContentModel.TYPE_FOLDER);
permissionService.setInheritParentPermissions(tempNode, false, false);
permissionService.setPermission(tempNode, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
NodeRef tempNodeChild = createFile(fileFolderService, tempNode, "testAsyncWithErrorsForceSharedACLTempChild",
ContentModel.TYPE_FOLDER);
setACL(permissionsDaoComponent, originFolderWithPendingAclChild,
nodeDAO.getNodeAclId(nodeDAO.getNodePair(tempNodeChild).getFirst()));
return null;
}, false, true);
ACLComparator aclComparator = new ACLComparator(originFolderWithPendingAclChild);
// Trigger job without forcing the shared ACL, only 1 error is expected
triggerFixedACLJob(false);
assertEquals("Unexpected number of errors", 1, getNodesCountWithPendingFixedAclAspect());
// Trigger job forcing the shared ACL
triggerFixedACLJob(true);
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
assertTrue("Child of node with conflict does not have correct permissions",
aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
assertTrue("Node with conflict does not have correct permissions",
aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
}
finally
{
deleteNodes(folderRef);
}
}
@@ -596,14 +791,26 @@ public class FixedAclUpdaterTest extends TestCase
public void testAsyncWithNodeMove()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeMoveTargetFolder",
ContentModel.TYPE_FOLDER);
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, false, false);
@@ -649,7 +856,7 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(folderRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
@@ -660,13 +867,27 @@ public class FixedAclUpdaterTest extends TestCase
public void testAsyncWithNodeMoveToPendingFolder()
{
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
try
{
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRefBase, true, false);
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
return null;
}, false, true);
// Trigger the job so the target folder structure has a different base ACL
triggerFixedACLJob();
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
// Get ACLS for later comparison
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
// Set permissions on target folder
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
permissionService.setInheritParentPermissions(targetRef, false, false);
@@ -723,7 +944,7 @@ public class FixedAclUpdaterTest extends TestCase
finally
{
deleteNodes(folderRef);
deleteNodes(targetRef);
deleteNodes(targetRefBase);
}
}
@@ -1250,6 +1471,19 @@ public class FixedAclUpdaterTest extends TestCase
}
}
private static void setACL(PermissionsDaoComponent permissionsDaoComponent, NodeRef nodeRef, long aclId)
{
if (permissionsDaoComponent instanceof ADMPermissionsDaoComponentImpl)
{
AccessControlListDAO acldao = ((ADMPermissionsDaoComponentImpl) permissionsDaoComponent).getACLDAO(nodeRef);
if (acldao instanceof ADMAccessControlListDAO)
{
ADMAccessControlListDAO admAcLDao = (ADMAccessControlListDAO) acldao;
admAcLDao.setAccessControlList(nodeRef, aclId);
}
}
}
private NodeRef createFolderHierarchyInRoot(String folderName, int[] filesPerLevel)
{
return txnHelper.doInTransaction((RetryingTransactionCallback<NodeRef>) () -> {
@@ -1318,6 +1552,11 @@ public class FixedAclUpdaterTest extends TestCase
}
private void triggerFixedACLJob()
{
triggerFixedACLJob(false);
}
private void triggerFixedACLJob(boolean forceSharedACL)
{
// run the fixedAclUpdater until there is nothing more to fix (running the updater may create more to fix up) or
// the count doesn't change for 3 cycles, meaning we have a problem.
@@ -1325,6 +1564,7 @@ public class FixedAclUpdaterTest extends TestCase
int count = 0;
int previousCount = 0;
int rounds = 0;
fixedAclUpdater.setForceSharedACL(forceSharedACL);
do
{
previousCount = count;
@@ -1356,8 +1596,13 @@ public class FixedAclUpdaterTest extends TestCase
isDescendent = true;
}
}
if (isDescendent && nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
{
// If folder, the tests will need a child and a grandchild to verify permissions
if (nodeType.equals(ContentModel.TYPE_FOLDER) && !hasGrandChilden(nodeRef)) {
continue;
}
return nodeRef;
}
}
@@ -1377,6 +1622,10 @@ public class FixedAclUpdaterTest extends TestCase
NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
if (nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
{
// If folder, the tests will need a child and a grandchild to verify permissions
if (nodeType.equals(ContentModel.TYPE_FOLDER) && !hasGrandChilden(nodeRef)) {
continue;
}
return nodeRef;
}
}
@@ -1385,6 +1634,18 @@ public class FixedAclUpdaterTest extends TestCase
}
private boolean hasGrandChilden(NodeRef nodeRef)
{
Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
Long childId = getChild(nodeId);
Long grandChild = null;
if (childId != null)
{
grandChild = getChild(childId);
}
return (grandChild != null);
}
private void deleteNodes(NodeRef folder)
{
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {

View File

@@ -0,0 +1,108 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.domain.permissions;
import static org.alfresco.model.ContentModel.TYPE_BASE;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_ARCHIVE_SPACESSTORE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.permissions.FixedAclUpdater.AclWorker;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
import org.alfresco.util.PolicyIgnoreUtil;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
/** Mock-based unit tests for {@link FixedAclUpdater}. */
public class FixedAclUpdaterUnitTest
{
private static final NodeRef NODE_REF = new NodeRef("test://node/ref");
private static final long NODE_ID = 123L;
private static final NodeRef ARCHIVED_NODE = new NodeRef(STORE_REF_ARCHIVE_SPACESSTORE, "archived");
@InjectMocks
private FixedAclUpdater fixedAclUpdater = new FixedAclUpdater();
/** The inner class under test. */
private AclWorker aclWorker = fixedAclUpdater.createAclWorker();
@Mock
private NodeDAO nodeDAO;
@Mock
private AccessControlListDAO accessControlListDAO;
@Mock
private PolicyIgnoreUtil policyIgnoreUtil;
@Mock
private ClassPolicyDelegate<OnInheritPermissionsDisabled> onInheritPermissionsDisabledDelegate;
@Mock
private OnInheritPermissionsDisabled onInheritPermissionsDisabled;
/** A pair of mock listeners. */
@Mock
private FixedAclUpdaterListener listenerA, listenerB;
@Before
public void setUp()
{
openMocks(this);
fixedAclUpdater.registerListener(listenerA);
fixedAclUpdater.registerListener(listenerB);
}
/** Check that when the AclWorker successfully processes a node then the listeners are notified. */
@Test
public void testListenersNotifiedAboutUpdate() throws Throwable
{
when(nodeDAO.getNodePair(NODE_REF)).thenReturn(new Pair<>(NODE_ID, NODE_REF));
when(onInheritPermissionsDisabledDelegate.get(TYPE_BASE)).thenReturn(onInheritPermissionsDisabled);
aclWorker.process(NODE_REF);
verify(listenerA).permissionsUpdatedAsynchronously(NODE_REF);
verify(listenerB).permissionsUpdatedAsynchronously(NODE_REF);
}
/** Check that archived nodes get the "Pending ACL" aspect removed without further updates, and the listeners are not notified. */
@Test
public void testListenersNotNotifiedAboutArchivedNode() throws Throwable
{
when(nodeDAO.getNodePair(ARCHIVED_NODE)).thenReturn(new Pair<>(NODE_ID, ARCHIVED_NODE));
when(onInheritPermissionsDisabledDelegate.get(TYPE_BASE)).thenReturn(onInheritPermissionsDisabled);
aclWorker.process(ARCHIVED_NODE);
verify(accessControlListDAO).removePendingAclAspect(NODE_ID);
verify(listenerA, never()).permissionsUpdatedAsynchronously(any(NodeRef.class));
verify(listenerB, never()).permissionsUpdatedAsynchronously(any(NodeRef.class));
}
}

View File

@@ -26,9 +26,14 @@
package org.alfresco.repo.event2;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.Transaction;
import org.alfresco.repo.event.v1.model.EventData;
import org.alfresco.repo.event.v1.model.EventType;
import org.alfresco.repo.event.v1.model.NodeResource;
@@ -38,6 +43,7 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Iulian Aftene
@@ -45,6 +51,9 @@ import org.junit.Test;
public class CreateRepoEventIT extends AbstractContextAwareRepoEvent
{
@Autowired
private NodeDAO nodeDAO;
@Test
public void testCreateEvent()
{
@@ -149,9 +158,32 @@ public class CreateRepoEventIT extends AbstractContextAwareRepoEvent
assertTrue("isFile flag should be TRUE for nodeType=cm:content. ", resource.isFile());
assertFalse("isFolder flag should be FALSE for nodeType=cm:content. ", resource.isFolder());
}
@Test
public void testEventTimestampEqualsToTransactionCommitTime()
{
String name = "TestFile-" + System.currentTimeMillis() + ".txt";
PropertyMap propertyMap = new PropertyMap();
propertyMap.put(ContentModel.PROP_NAME, name);
//create a node and return the transaction id required later
Long transactionId = retryingTransactionHelper.doInTransaction(() -> {
nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(TEST_NAMESPACE, GUID.generate()), ContentModel.TYPE_CONTENT, propertyMap).getChildRef();
return nodeDAO.getCurrentTransactionId(false);
});
RepoEvent<EventData<NodeResource>> resultRepoEvent = getRepoEvent(1);
Transaction transaction = nodeDAO.getTxnById(transactionId);
Instant commitTimeMs = Instant.ofEpochMilli(transaction.getCommitTimeMs());
ZonedDateTime timestamp = ZonedDateTime.ofInstant(commitTimeMs, ZoneOffset.UTC);
assertEquals(timestamp, resultRepoEvent.getTime());
}
@Test
public void testCteateMultipleNodesInTheSameTransaction()
public void testCreateMultipleNodesInTheSameTransaction()
{
retryingTransactionHelper.doInTransaction(() -> {
for (int i = 0; i < 3; i++)

View File

@@ -231,7 +231,7 @@ public class ModuleVersionNumberTest extends TestCase
return (ModuleVersionNumber) objectInputStream.readObject();
}
// Tests that we can strip the suffixes such as "-M2", "-A12" or "-RC2" from versions "7.0.0-M2", "6.2.2-A12", "7.0.1-RC2"
// Tests that we can strip the suffixes such as "-M2", "-A12" or "-RC2" from versions "7.0.0-M2", "6.2.2-A12", "7.1.0-RC2"
// The main version may contain 3 or 4 digit parts.
public void testGetVersionWithoutSuffix()
{

View File

@@ -9,13 +9,13 @@
</bean>
<import resource="classpath:/alfresco/subsystems/Messaging/default/messaging-context.xml" />
<bean id="messagingExceptionProcessor"
class="org.alfresco.messaging.camel.MockExceptionProcessor" />
<bean id="mockConsumer"
class="org.alfresco.messaging.camel.MockConsumer" />
<bean id="mockExceptionThrowingConsumer"
class="org.alfresco.messaging.camel.MockExceptionThrowingConsumer" />
@@ -25,4 +25,19 @@
<property name="routeContextId" value="customRoutes" />
</bean>
<bean id="transactionAwareEventProducer" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.alfresco.repo.rawevents.TransactionAwareEventProducer" />
</bean>
<bean id="policyComponent" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.alfresco.repo.policy.PolicyComponentImpl"/>
</bean>
<bean id="renditionEventProcessor" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.alfresco.repo.rendition2.RenditionEventProcessor"/>
</bean>
<bean id="transformRequestProcessor" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.alfresco.repo.rendition2.TransformRequestProcessor" />
</bean>
</beans>

View File

@@ -1,6 +1,9 @@
messaging.broker.url=vm://localhost?broker.persistent=false
messaging.broker.url=nio://localhost:61616
messaging.broker.ssl=false
messaging.broker.connections.max=8
messaging.transacted=true
messaging.broker.username=
messaging.broker.password=
messaging.broker.password=
acs.repo.rendition.events.endpoint=jms:acs-repo-rendition-events-test?jmsMessageType=Text
acs.repo.transform.request.endpoint=jms:acs-repo-transform-request-test?jmsMessageType=Text