Compare commits

..

46 Commits
10.1 ... 11.3

Author SHA1 Message Date
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
86 changed files with 2495 additions and 3167 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

@@ -54,7 +54,7 @@ jobs:
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=AppContext01TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext02TestSuite"
@@ -67,14 +67,14 @@ jobs:
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=AppContext03TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext04TestSuite"
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=AppContext04TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext05TestSuite"
@@ -91,21 +91,21 @@ jobs:
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=AppContext06TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContextExtraTestSuite"
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=AppContextExtraTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - MiscContextTestSuite"
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl repository -Dtest=MiscContextTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - SearchTestSuite"
@@ -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'
@@ -187,21 +192,21 @@ jobs:
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext02TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContext03TestSuite"
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext03TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContext04TestSuite"
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'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.4.0
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:2.3.10
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext04TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContextExtraTestSuite"

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<dependencies>

View File

@@ -21,6 +21,7 @@ package org.alfresco.httpclient;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.AlgorithmParameters;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -31,11 +32,14 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.encryption.AlfrescoKeyStore;
import org.alfresco.encryption.AlfrescoKeyStoreImpl;
import org.alfresco.encryption.EncryptionUtils;
import org.alfresco.encryption.Encryptor;
import org.alfresco.encryption.KeyProvider;
import org.alfresco.encryption.KeyResourceLoader;
import org.alfresco.encryption.KeyStoreParameters;
import org.alfresco.encryption.ssl.AuthSSLProtocolSocketFactory;
import org.alfresco.encryption.ssl.SSLEncryptionParameters;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.util.Pair;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
@@ -49,6 +53,8 @@ import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.DefaultHttpParams;
import org.apache.commons.httpclient.params.DefaultHttpParamsFactory;
import org.apache.commons.httpclient.params.HttpClientParams;
@@ -69,25 +75,23 @@ import org.apache.commons.logging.LogFactory;
*/
public class HttpClientFactory
{
/**
* Communication type for HttpClient:
* - NONE is plain http
* - SECRET is plain http with a shared secret via request header
* - HTTPS is mTLS with client authentication (certificates are required)
*/
public static enum SecureCommsType
{
HTTPS, NONE, SECRET;
HTTPS, NONE;
public static SecureCommsType getType(String type)
{
switch (type.toLowerCase())
if(type.equalsIgnoreCase("https"))
{
case "https": return HTTPS;
case "none": return NONE;
case "secret": return SECRET;
default: throw new IllegalArgumentException("Invalid communications type");
return HTTPS;
}
else if(type.equalsIgnoreCase("none"))
{
return NONE;
}
else
{
throw new IllegalArgumentException("Invalid communications type");
}
}
};
@@ -118,24 +122,14 @@ public class HttpClientFactory
private int connectionTimeout = 0;
// Shared secret parameters
private String sharedSecret;
private String sharedSecretHeader = DEFAULT_SHAREDSECRET_HEADER;
// Default name for HTTP Request Header when using shared secret communication
public static final String DEFAULT_SHAREDSECRET_HEADER = "X-Alfresco-Search-Secret";
public HttpClientFactory()
{
}
/**
* Default constructor for legacy subsystems.
*/
public HttpClientFactory(SecureCommsType secureCommsType, SSLEncryptionParameters sslEncryptionParameters,
KeyResourceLoader keyResourceLoader, KeyStoreParameters keyStoreParameters,
MD5EncryptionParameters encryptionParameters, String host, int port, int sslPort,
int maxTotalConnections, int maxHostConnections, int socketTimeout)
KeyResourceLoader keyResourceLoader, KeyStoreParameters keyStoreParameters,
MD5EncryptionParameters encryptionParameters, String host, int port, int sslPort, int maxTotalConnections,
int maxHostConnections, int socketTimeout)
{
this.secureCommsType = secureCommsType;
this.sslEncryptionParameters = sslEncryptionParameters;
@@ -151,21 +145,6 @@ public class HttpClientFactory
init();
}
/**
* Recommended constructor for subsystems supporting Shared Secret communication.
* This constructor supports Shared Secret ("secret") communication method additionally to the legacy ones: "none" and "https".
*/
public HttpClientFactory(SecureCommsType secureCommsType, SSLEncryptionParameters sslEncryptionParameters,
KeyResourceLoader keyResourceLoader, KeyStoreParameters keyStoreParameters,
MD5EncryptionParameters encryptionParameters, String sharedSecret, String sharedSecretHeader,
String host, int port, int sslPort, int maxTotalConnections, int maxHostConnections, int socketTimeout)
{
this(secureCommsType, sslEncryptionParameters, keyResourceLoader, keyStoreParameters, encryptionParameters,
host, port, sslPort, maxTotalConnections, maxHostConnections, socketTimeout);
this.sharedSecret = sharedSecret;
this.sharedSecretHeader = sharedSecretHeader;
}
public void init()
{
this.sslKeyStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getKeyStoreParameters(), keyResourceLoader);
@@ -293,44 +272,10 @@ public class HttpClientFactory
this.connectionTimeout = connectionTimeout;
}
/**
* Shared secret used for SECRET communication
* @param secret shared secret word
*/
public void setSharedSecret(String sharedSecret)
{
this.sharedSecret = sharedSecret;
}
/**
* @return Shared secret used for SECRET communication
*/
public String getSharedSecret()
{
return sharedSecret;
}
/**
* HTTP Request header used for SECRET communication
* @param sharedSecretHeader HTTP Request header
*/
public void setSharedSecretHeader(String sharedSecretHeader)
{
this.sharedSecretHeader = sharedSecretHeader;
}
/**
* @return HTTP Request header used for SECRET communication
*/
public String getSharedSecretHeader()
{
return sharedSecretHeader;
}
protected RequestHeadersHttpClient constructHttpClient()
protected HttpClient constructHttpClient()
{
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
RequestHeadersHttpClient httpClient = new RequestHeadersHttpClient(connectionManager);
HttpClient httpClient = new HttpClient(connectionManager);
HttpClientParams params = httpClient.getParams();
params.setBooleanParameter(HttpConnectionParams.TCP_NODELAY, true);
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true);
@@ -346,15 +291,15 @@ public class HttpClientFactory
return httpClient;
}
protected RequestHeadersHttpClient getHttpsClient()
protected HttpClient getHttpsClient()
{
return getHttpsClient(host, sslPort);
}
protected RequestHeadersHttpClient getHttpsClient(String httpsHost, int httpsPort)
protected HttpClient getHttpsClient(String httpsHost, int httpsPort)
{
// Configure a custom SSL socket factory that will enforce mutual authentication
RequestHeadersHttpClient httpClient = constructHttpClient();
HttpClient httpClient = constructHttpClient();
// Default port is 443 for the HostFactory, when including customised port (like 8983) the port name is skipped from "getHostURL" string
HttpHostFactory hostFactory = new HttpHostFactory(new Protocol("https", sslSocketFactory, HttpsURL.DEFAULT_PORT));
httpClient.setHostConfiguration(new HostConfigurationWithHostFactory(hostFactory));
@@ -362,54 +307,28 @@ public class HttpClientFactory
return httpClient;
}
protected RequestHeadersHttpClient getDefaultHttpClient()
protected HttpClient getDefaultHttpClient()
{
return getDefaultHttpClient(host, port);
}
protected RequestHeadersHttpClient getDefaultHttpClient(String httpHost, int httpPort)
protected HttpClient getDefaultHttpClient(String httpHost, int httpPort)
{
RequestHeadersHttpClient httpClient = constructHttpClient();
httpClient.getHostConfiguration().setHost(httpHost, httpPort);
return httpClient;
}
/**
* Build HTTP Client using default headers
* @return RequestHeadersHttpClient including default header for shared secret method
*/
protected RequestHeadersHttpClient constructSharedSecretHttpClient()
{
RequestHeadersHttpClient client = constructHttpClient();
client.setDefaultHeaders(Map.of(sharedSecretHeader, sharedSecret));
return client;
}
protected RequestHeadersHttpClient getSharedSecretHttpClient()
{
return getSharedSecretHttpClient(host, port);
}
protected RequestHeadersHttpClient getSharedSecretHttpClient(String httpHost, int httpPort)
{
RequestHeadersHttpClient httpClient = constructSharedSecretHttpClient();
HttpClient httpClient = constructHttpClient();
httpClient.getHostConfiguration().setHost(httpHost, httpPort);
return httpClient;
}
protected AlfrescoHttpClient getAlfrescoHttpsClient()
{
return new HttpsClient(getHttpsClient());
AlfrescoHttpClient repoClient = new HttpsClient(getHttpsClient());
return repoClient;
}
protected AlfrescoHttpClient getAlfrescoHttpClient()
{
return new DefaultHttpClient(getDefaultHttpClient());
}
protected AlfrescoHttpClient getAlfrescoSharedSecretClient()
{
return new DefaultHttpClient(getSharedSecretHttpClient());
AlfrescoHttpClient repoClient = new DefaultHttpClient(getDefaultHttpClient());
return repoClient;
}
protected HttpClient getMD5HttpClient(String host, int port)
@@ -422,37 +341,66 @@ public class HttpClientFactory
public AlfrescoHttpClient getRepoClient(String host, int port)
{
switch (secureCommsType)
AlfrescoHttpClient repoClient = null;
if(secureCommsType == SecureCommsType.HTTPS)
{
case HTTPS: return getAlfrescoHttpsClient();
case NONE: return getAlfrescoHttpClient();
case SECRET: return getAlfrescoSharedSecretClient();
default: throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in [solr|alfresco].secureComms, should be 'ssl', 'none' or 'secret'");
repoClient = getAlfrescoHttpsClient();
}
else if(secureCommsType == SecureCommsType.NONE)
{
repoClient = getAlfrescoHttpClient();
}
else
{
throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in alfresco.secureComms, should be 'ssl'or 'none'");
}
return repoClient;
}
public RequestHeadersHttpClient getHttpClient()
public HttpClient getHttpClient()
{
switch (secureCommsType)
HttpClient httpClient = null;
if(secureCommsType == SecureCommsType.HTTPS)
{
case HTTPS: return getHttpsClient();
case NONE: return getDefaultHttpClient();
case SECRET: return getSharedSecretHttpClient();
default: throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in [solr|alfresco].secureComms, should be 'ssl', 'none' or 'secret'");
httpClient = getHttpsClient();
}
else if(secureCommsType == SecureCommsType.NONE)
{
httpClient = getDefaultHttpClient();
}
else
{
throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in alfresco.secureComms, should be 'ssl'or 'none'");
}
return httpClient;
}
public RequestHeadersHttpClient getHttpClient(String host, int port)
public HttpClient getHttpClient(String host, int port)
{
switch (secureCommsType)
HttpClient httpClient = null;
if(secureCommsType == SecureCommsType.HTTPS)
{
case HTTPS: return getHttpsClient(host, port);
case NONE: return getDefaultHttpClient(host, port);
case SECRET: return getSharedSecretHttpClient(host, port);
default: throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in [solr|alfresco].secureComms, should be 'ssl', 'none' or 'secret'");
httpClient = getHttpsClient(host, port);
}
else if(secureCommsType == SecureCommsType.NONE)
{
httpClient = getDefaultHttpClient(host, port);
}
else
{
throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in alfresco.secureComms, should be 'ssl'or 'none'");
}
return httpClient;
}
/**
* A secure client connection to the repository.
*

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2005-2021 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.httpclient;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
/**
* Since Apache HttpClient 3.1 doesn't support including custom headers by default,
* this class is adding that custom headers every time a method is invoked.
*/
public class RequestHeadersHttpClient extends HttpClient
{
private Map<String, String> defaultHeaders;
public RequestHeadersHttpClient(MultiThreadedHttpConnectionManager connectionManager)
{
super(connectionManager);
}
public Map<String, String> getDefaultHeaders()
{
return defaultHeaders;
}
public void setDefaultHeaders(Map<String, String> defaultHeaders)
{
this.defaultHeaders = defaultHeaders;
}
private void addDefaultHeaders(HttpMethod method)
{
if (defaultHeaders != null)
{
defaultHeaders.forEach((k,v) -> {
method.addRequestHeader(k, v);
});
}
}
@Override
public int executeMethod(HttpMethod method) throws IOException, HttpException
{
addDefaultHeaders(method);
return super.executeMethod(method);
}
@Override
public int executeMethod(HostConfiguration hostConfiguration, HttpMethod method) throws IOException, HttpException
{
addDefaultHeaders(method);
return super.executeMethod(hostConfiguration, method);
}
@Override
public int executeMethod(HostConfiguration hostconfig, HttpMethod method, HttpState state)
throws IOException, HttpException
{
addDefaultHeaders(method);
return super.executeMethod(hostconfig, method, state);
}
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<properties>
@@ -167,7 +167,7 @@
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.2.6</version>
<version>6.2.4</version>
</dependency>
<!-- the cxf libs were updated, see dependencyManagement section -->
@@ -283,31 +283,6 @@
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
</exclusion>
<!-- No longer needed -->
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jempbox</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>xmpbox</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jbig2-imageio</artifactId>
</exclusion>
</exclusions>
</dependency>

View File

@@ -60,15 +60,12 @@ public abstract class ConfigScheduler<Data>
// Synchronized has little effect in normal operation, but on laptops that are suspended, there can be a number
// of Threads calling execute concurrently without it, resulting in errors in the log. Theoretically possible in
// production but not very likely.
public void execute(JobExecutionContext context) throws JobExecutionException
public synchronized void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
ConfigScheduler configScheduler = (ConfigScheduler)dataMap.get(CONFIG_SCHEDULER);
synchronized (configScheduler)
{
boolean successReadingConfig = configScheduler.readConfigAndReplace(true);
configScheduler.changeScheduleOnStateChange(successReadingConfig);
}
boolean successReadingConfig = configScheduler.readConfigAndReplace(true);
configScheduler.changeScheduleOnStateChange(successReadingConfig);
}
}

View File

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

View File

@@ -1,6 +1,6 @@
# Fetch image based on Tomcat 9.0, Java 11 and Centos 8
# More infos about this image: https://github.com/Alfresco/alfresco-docker-base-tomcat
FROM alfresco/alfresco-base-tomcat:9.0.45-java-11-centos-8
FROM alfresco/alfresco-base-tomcat:9.0.41-java-11-openjdk-centos-8
# Set default docker_context.
ARG resource_path=target
@@ -66,11 +66,11 @@ RUN sed -i -e "s_log4j.appender.File.File\=alfresco.log_log4j.appender.File.File
# fontconfig is required by Activiti worflow diagram generator
# installing pinned dependencies as well
RUN yum install -y fontconfig-2.13.1-3.el8 \
dejavu-fonts-common-2.35-7.el8 \
dejavu-fonts-common-2.35-6.el8 \
fontpackages-filesystem-1.44-22.el8 \
freetype-2.9.1-4.el8_3.1 \
libpng-1.6.34-5.el8 \
dejavu-sans-fonts-2.35-7.el8 && \
dejavu-sans-fonts-2.35-6.el8 && \
yum clean all
# The standard configuration is to have all Tomcat files owned by root with group GROUPNAME and whilst owner has read/write privileges,

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<profiles>

View File

@@ -1,4 +1,4 @@
TRANSFORMERS_TAG=2.4.0
SOLR6_TAG=2.0.2-RC2
TRANSFORMERS_TAG=2.3.10
SOLR6_TAG=2.0.1
POSTGRES_TAG=13.1
ACTIVEMQ_TAG=5.16.1

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<properties>

View File

@@ -57,8 +57,8 @@ ModuleDetails shareServicesModule = moduleService.getModule("alfresco-share-serv
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Alfresco</title>
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/reset.css" />
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/alfresco.css" />
<link rel="stylesheet" type="text/css" href="./css/reset.css" />
<link rel="stylesheet" type="text/css" href="./css/alfresco.css" />
</head>
<body>
<div class="sticky-wrapper">

View File

@@ -57,8 +57,8 @@ ModuleDetails shareServicesModule = moduleService.getModule("alfresco-share-serv
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Alfresco</title>
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/reset.css" />
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/alfresco.css" />
<link rel="stylesheet" type="text/css" href="./css/reset.css" />
<link rel="stylesheet" type="text/css" href="./css/alfresco.css" />
</head>
<body>
<div class="sticky-wrapper">

61
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>10.1</version>
<version>11.3</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -22,8 +22,8 @@
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>0</acs.version.minor>
<acs.version.revision>1</acs.version.revision>
<acs.version.minor>1</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.label />
<version.edition>Community</version.edition>
@@ -34,15 +34,15 @@
<image.registry>quay.io</image.registry>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.build.sourceVersion>${java.version}</maven.build.sourceVersion>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.build.sourceVersion>11</maven.build.sourceVersion>
<dir.root>${project.build.directory}/alf_data</dir.root>
<dependency.alfresco-hb-data-sender.version>1.0.12</dependency.alfresco-hb-data-sender.version>
<dependency.alfresco-mmt.version>6.0</dependency.alfresco-mmt.version>
<dependency.alfresco-trashcan-cleaner.version>2.4.1</dependency.alfresco-trashcan-cleaner.version>
<dependency.alfresco-trashcan-cleaner.version>2.3</dependency.alfresco-trashcan-cleaner.version>
<dependency.alfresco-jlan.version>7.1</dependency.alfresco-jlan.version>
<dependency.alfresco-server-root.version>6.0.1</dependency.alfresco-server-root.version>
<dependency.alfresco-messaging-repo.version>1.2.15</dependency.alfresco-messaging-repo.version>
@@ -55,13 +55,13 @@
<dependency.spring.version>5.3.3</dependency.spring.version>
<dependency.antlr.version>3.5.2</dependency.antlr.version>
<dependency.jackson.version>2.12.3</dependency.jackson.version>
<dependency.jackson-databind.version>2.12.3</dependency.jackson-databind.version>
<dependency.cxf.version>3.4.4</dependency.cxf.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.3</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.19</dependency.webscripts.version>
<dependency.bouncycastle.version>1.69</dependency.bouncycastle.version>
<dependency.mockito-core.version>3.9.0</dependency.mockito-core.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>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>
@@ -74,17 +74,16 @@
<dependency.gytheio.version>0.12</dependency.gytheio.version>
<dependency.groovy.version>2.5.9</dependency.groovy.version>
<dependency.tika.version>1.26</dependency.tika.version>
<dependency.spring-security.version>5.5.0</dependency.spring-security.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>13.0.1</dependency.keycloak.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.4</dependency.camel.version>
<dependency.camel.version>3.7.1</dependency.camel.version>
<dependency.activemq.version>5.16.1</dependency.activemq.version>
<dependency.apache-compress.version>1.20</dependency.apache-compress.version>
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
<dependency.awaitility.version>4.1.0</dependency.awaitility.version>
<dependency.awaitility.version>4.0.3</dependency.awaitility.version>
<dependency.jakarta-jaxb-api.version>2.3.3</dependency.jakarta-jaxb-api.version>
<dependency.jakarta-ws-api.version>2.3.3</dependency.jakarta-ws-api.version>
@@ -97,16 +96,16 @@
<dependency.jakarta-json-api.version>1.1.6</dependency.jakarta-json-api.version>
<dependency.jakarta-rpc-api.version>1.1.4</dependency.jakarta-rpc-api.version>
<alfresco.googledrive.version>3.2.1.3</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.0.1</alfresco.aos-module.version>
<alfresco.googledrive.version>3.2.1</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.0</alfresco.aos-module.version>
<dependency.postgresql.version>42.2.20</dependency.postgresql.version>
<dependency.mysql.version>8.0.25</dependency.mysql.version>
<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.44</dependency.tas-utility.version>
<dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.58</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.30</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>
@@ -117,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>10.1</tag>
<tag>11.3</tag>
</scm>
<distributionManagement>
@@ -550,7 +549,8 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${dependency.bouncycastle.version}</version>
<version>1.68</version>
<!-- <version>${dependency.bouncycastle.version}</version>-->
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
@@ -583,7 +583,7 @@
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.16.0</version>
<version>2.15.0</version>
</dependency>
<!-- upgrade dependency from TIKA -->
<dependency>
@@ -601,7 +601,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${dependency.apache-compress.version}</version>
<version>1.20</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@@ -694,7 +694,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -814,7 +814,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -829,4 +829,5 @@
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>10.1</version>
<version>11.3</version>
</parent>
<dependencies>

View File

@@ -25,18 +25,21 @@
*/
package org.alfresco.repo.web.scripts.solr;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.httpclient.HttpClientFactory;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -85,7 +88,9 @@ public class SOLRAuthenticationFilter implements DependencyInjectedFilter, Initi
private String sharedSecret;
private String sharedSecretHeader = HttpClientFactory.DEFAULT_SHAREDSECRET_HEADER;
private String sharedSecretHeader = DEFAULT_SHAREDSECRET_HEADER;
private static final String DEFAULT_SHAREDSECRET_HEADER = "X-Alfresco-Search-Secret";
public void setSecureComms(String type)
{

View File

@@ -716,7 +716,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
}
else
{
if((pathInfo.length() > 5 && !pathInfo.substring(0, 6).toLowerCase().equals("/cmis/")) && !pathInfo.equals("/discovery"))
if(!pathInfo.substring(0, 6).toLowerCase().equals("/cmis/") && !pathInfo.equals("/discovery"))
{
// remove tenant
int idx = pathInfo.indexOf('/', 1);

View File

@@ -41,11 +41,7 @@ public class DefaultExceptionResolver implements ExceptionResolver<Exception>
@Override
public ErrorResponse resolveException(Exception ex)
{
return new ErrorResponse(DEFAULT_MESSAGE_ID,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
ex.getLocalizedMessage(),
ex.getStackTrace(),
null);
return new ErrorResponse(DEFAULT_MESSAGE_ID, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), ex.getStackTrace(), null);
}
}

View File

@@ -26,12 +26,10 @@
package org.alfresco.rest.framework.tools;
import org.alfresco.metrics.rest.RestMetricsReporter;
import org.alfresco.repo.search.QueryParserException;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.core.exceptions.DefaultExceptionResolver;
import org.alfresco.rest.framework.core.exceptions.ErrorResponse;
import org.alfresco.rest.framework.core.exceptions.ExceptionResolver;
import org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -50,7 +48,6 @@ public class ApiAssistant {
private ExceptionResolver<Exception> defaultResolver = new DefaultExceptionResolver();
private ExceptionResolver<WebScriptException> webScriptExceptionResolver;
private ExceptionResolver<QueryParserException> queryParserExceptionResolver;
private ExceptionResolver<Exception> resolver;
private JacksonHelper jsonHelper;
private RestMetricsReporter restMetricsReporter;
@@ -80,10 +77,6 @@ public class ApiAssistant {
{
error = webScriptExceptionResolver.resolveException((WebScriptException) ex);
}
else if (ex instanceof QueryParserException)
{
error = queryParserExceptionResolver.resolveException((QueryParserException) ex);
}
else
{
error = resolver.resolveException(ex);
@@ -107,11 +100,6 @@ public class ApiAssistant {
this.webScriptExceptionResolver = webScriptExceptionResolver;
}
public void setQueryParserExceptionResolver(ExceptionResolver<QueryParserException> queryParserExceptionResolver)
{
this.queryParserExceptionResolver = queryParserExceptionResolver;
}
public void setResolver(ExceptionResolver<Exception> resolver) {
this.resolver = resolver;
}

View File

@@ -31,7 +31,6 @@ import java.util.Properties;
import javax.servlet.ServletContext;
import org.alfresco.httpclient.HttpClientFactory.SecureCommsType;
import org.alfresco.web.scripts.servlet.X509ServletFilterBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -71,9 +70,7 @@ public class AlfrescoX509ServletFilter extends X509ServletFilterBase
* Return true or false based on the property. This will switch on/off X509 enforcement in the X509ServletFilterBase.
*/
if (prop == null ||
SecureCommsType.getType(prop) == SecureCommsType.NONE ||
SecureCommsType.getType(prop) == SecureCommsType.SECRET)
if (prop == null || "none".equals(prop))
{
return false;
}

View File

@@ -134,8 +134,6 @@
</bean>
<bean id="webScriptExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.WebScriptExceptionResolver">
</bean>
<bean id="queryParserExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver">
</bean>
<bean id="simpleMappingExceptionResolverParent" abstract="true" class="org.alfresco.rest.framework.core.exceptions.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
@@ -184,7 +182,6 @@
<property name="resolver" ref="simpleMappingExceptionResolver" />
<property name="webScriptExceptionResolver" ref="webScriptExceptionResolver" />
<property name="restMetricsReporter" ref="restMetricsReporter"/>
<property name="queryParserExceptionResolver" ref="queryParserExceptionResolver" />
</bean>
<!-- Using annotation-config=false means AutowiredAnnotationBeanPostProcessor

View File

@@ -1,7 +1,7 @@
<#assign null><span style="color:red">${msg("nodebrowser.null")?html}</span></#assign>
<#assign none><span style="color:red">${msg("nodebrowser.none")?html}</span></#assign>
<#assign collection>${msg("nodebrowser.collection")?html}</#assign>
<#assign maxDepth=1000 />
<#macro dateFormat date>${date?string("dd MMM yyyy HH:mm:ss 'GMT'Z '('zzz')'")}</#macro>
<#macro propValue p>
<#attempt>
@@ -25,52 +25,50 @@
</#attempt>
</#macro>
<#macro convertToJSON v>
<#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>
<#if v?keys?size gt maxDepth >
<#stop "Max depth of object achieved">
</#if>
<@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>
<#if v?size gt maxDepth>
<#stop "Max depth of object achieved" >
</#if>
<#assign first = true />
<#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>
[
<#list v as item>
<#if first = false>,</#if>
<@convertToJSON item />
<#assign first = false/>
{
<#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>
<#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

@@ -31,7 +31,6 @@ import static org.junit.Assert.assertNull;
import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.search.QueryParserException;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.DeletedResourceException;
@@ -123,13 +122,4 @@ public class ExceptionResolverTests
assertEquals(422, response.getStatusCode());
}
/** Check that the status code from SS is passed back to the caller. */
@Test
public void testQueryParserException()
{
ErrorResponse response = assistant.resolveException(new QueryParserException("Endpoint not found", 404));
assertNotNull(response);
assertEquals("Expected status code to be passed through from query parser.", 404, response.getStatusCode());
}
}

View File

@@ -33,12 +33,10 @@
</bean>
<bean id="webScriptExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.WebScriptExceptionResolver">
</bean>
<bean id="queryParserExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.QueryParserExceptionResolver" />
<bean id="apiAssistant" class="org.alfresco.rest.framework.tools.ApiAssistant">
<property name="jsonHelper" ref="jsonHelper" />
<property name="resolver" ref="simpleMappingExceptionResolver" />
<property name="webScriptExceptionResolver" ref="webScriptExceptionResolver" />
<property name="queryParserExceptionResolver" ref="queryParserExceptionResolver" />
</bean>
<bean id="simpleMappingExceptionResolver" class="org.alfresco.rest.framework.core.exceptions.SimpleMappingExceptionResolver">
<property name="exceptionMappings">

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>10.1</version>
<version>11.3</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>
@@ -383,7 +383,7 @@
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.2.6</version>
<version>6.2.4</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

@@ -32,8 +32,6 @@ import org.alfresco.sync.repo.Client;
import org.alfresco.sync.repo.Client.ClientType;
import org.alfresco.repo.activities.ActivityType;
import org.alfresco.repo.model.filefolder.HiddenAspect;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.activities.ActivityInfo;
import org.alfresco.service.cmr.activities.ActivityPoster;
@@ -230,7 +228,7 @@ public class ActivityPosterImpl implements CmisActivityPoster, InitializingBean
{
if(activitiesEnabled && !hiddenAspect.hasHiddenAspect(nodeRef))
{
SiteInfo siteInfo = getSiteAsSystem(nodeRef);
SiteInfo siteInfo = siteService.getSite(nodeRef);
String siteId = (siteInfo != null ? siteInfo.getShortName() : null);
if(siteId != null && !siteId.equals(""))
{
@@ -293,15 +291,4 @@ public class ActivityPosterImpl implements CmisActivityPoster, InitializingBean
}
}
private SiteInfo getSiteAsSystem(NodeRef nodeRef)
{
return AuthenticationUtil.runAsSystem(new RunAsWork<SiteInfo>()
{
@Override
public SiteInfo doWork() throws Exception
{
return siteService.getSite(nodeRef);
}
});
}
}

View File

@@ -35,6 +35,8 @@ 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;
@@ -83,13 +85,16 @@ 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;
@@ -158,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
@@ -241,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);
@@ -315,6 +326,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
e.printStackTrace();
}
listeners.forEach(listener -> listener.permissionsUpdatedAsynchronously(nodeRef));
if (log.isDebugEnabled())
{
log.debug(String.format("Node processed %s", nodeRef));
@@ -330,7 +343,13 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
};
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;
@@ -421,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);
@@ -442,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

@@ -1,8 +1,8 @@
/*
* #%L
* Alfresco Remote API
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* 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
@@ -23,26 +23,13 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.framework.core.exceptions;
package org.alfresco.repo.domain.permissions;
import org.alfresco.repo.search.QueryParserException;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* QueryParserException is related with search requests to Search Services.
*/
public class QueryParserExceptionResolver implements ExceptionResolver<QueryParserException>
/** Listener to receive callback events when permissions are asynchronously updated with the {@link FixedAclUpdater}. */
public interface FixedAclUpdaterListener
{
@Override
public ErrorResponse resolveException(QueryParserException ex)
{
return new ErrorResponse(
DefaultExceptionResolver.DEFAULT_MESSAGE_ID,
// Mapping the original HTTP Status code returned by Search Services
ex.getHttpStatusCode(),
ex.getLocalizedMessage(),
ex.getStackTrace(),
null);
}
/** Callback method for when permissions have been updated by the FixedAclUpdater. */
void permissionsUpdatedAsynchronously(NodeRef nodeRef);
}

View File

@@ -69,19 +69,19 @@ public class DeleteNotExistsExecutor implements StatementExecutor
public static final String PROPERTY_READ_ONLY = "system.delete_not_exists.read_only";
public static final String PROPERTY_TIMEOUT_SECONDS = "system.delete_not_exists.timeout_seconds";
protected Connection connection;
private Connection connection;
private String sql;
private int line;
private File scriptFile;
private Properties globalProperties;
protected boolean readOnly;
protected int deleteBatchSize;
protected int batchSize;
private boolean readOnly;
private int deleteBatchSize;
private int batchSize;
private long timeoutSec;
protected long deletedCount;
protected Date startTime;
private long deletedCount;
private Date startTime;
public DeleteNotExistsExecutor(Connection connection, String sql, int line, File scriptFile, Properties globalProperties)
{
@@ -164,7 +164,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected void process(Pair<String, String>[] tableColumn, Long[] tableUpperLimits, String[] optionalWhereClauses) throws SQLException
private void process(Pair<String, String>[] tableColumn, Long[] tableUpperLimits, String[] optionalWhereClauses) throws SQLException
{
// The approach is to fetch ordered row ids from all referencer/secondary (e.g.
// alf_audit_app, alf_audit_entry, alf_prop_unique_ctx) tables and
@@ -190,7 +190,6 @@ public class DeleteNotExistsExecutor implements StatementExecutor
try
{
connection.setAutoCommit(false);
primaryPrepStmt = connection.prepareStatement(createPreparedSelectStatement(primaryTableName, primaryColumnName, primaryWhereClause));
primaryPrepStmt.setFetchSize(batchSize);
primaryPrepStmt.setLong(1, primaryId);
@@ -265,7 +264,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected boolean isTimeoutExceeded()
private boolean isTimeoutExceeded()
{
if (timeoutSec <= 0)
{
@@ -276,7 +275,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return (now.getTime() > startTime.getTime() + (timeoutSec * 1000));
}
protected Long processPrimaryTableResultSet(PreparedStatement primaryPrepStmt, PreparedStatement[] secondaryPrepStmts, PreparedStatement deletePrepStmt, Set<Long> deleteIds, String primaryTableName,
private Long processPrimaryTableResultSet(PreparedStatement primaryPrepStmt, PreparedStatement[] secondaryPrepStmts, PreparedStatement deletePrepStmt, Set<Long> deleteIds, String primaryTableName,
String primaryColumnName, Pair<String, String>[] tableColumn) throws SQLException
{
int rowsProcessed = 0;
@@ -337,7 +336,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return primaryId;
}
protected void deleteFromPrimaryTable(PreparedStatement deletePrepStmt, Set<Long> deleteIds, String primaryTableName) throws SQLException
private void deleteFromPrimaryTable(PreparedStatement deletePrepStmt, Set<Long> deleteIds, String primaryTableName) throws SQLException
{
int deletedBatchCount = deleteIds.size();
if (!readOnly && !deleteIds.isEmpty())
@@ -426,7 +425,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return batchUpperLimit;
}
protected boolean isLess(Long primaryId, Long[] secondaryIds)
private boolean isLess(Long primaryId, Long[] secondaryIds)
{
for (Long secondaryId : secondaryIds)
{
@@ -449,7 +448,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return quotedString.replace("\"", "");
}
protected String createPreparedSelectStatement(String tableName, String columnName, String whereClause)
private String createPreparedSelectStatement(String tableName, String columnName, String whereClause)
{
StringBuilder sqlBuilder = new StringBuilder("SELECT " + columnName + " FROM " + tableName + " WHERE ");
@@ -462,7 +461,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return sqlBuilder.toString();
}
protected String createPreparedDeleteStatement(String tableName, String idColumnName, int deleteBatchSize, String whereClause)
private String createPreparedDeleteStatement(String tableName, String idColumnName, int deleteBatchSize, String whereClause)
{
StringBuilder stmtBuilder = new StringBuilder("DELETE FROM " + tableName + " WHERE ");
@@ -516,7 +515,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected Long getColumnValueById(ResultSet resultSet, String columnId) throws SQLException
private Long getColumnValueById(ResultSet resultSet, String columnId) throws SQLException
{
Long columnValue = null;
if (resultSet != null && resultSet.next())
@@ -527,7 +526,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return columnValue;
}
protected ResultSet[] getSecondaryResultSets(PreparedStatement[] preparedStatements) throws SQLException
private ResultSet[] getSecondaryResultSets(PreparedStatement[] preparedStatements) throws SQLException
{
ResultSet[] secondaryResultSets = new ResultSet[preparedStatements.length];
for (int i = 1; i < preparedStatements.length; i++)
@@ -541,7 +540,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
return secondaryResultSets;
}
protected Long[] getSecondaryIds(ResultSet[] secondaryResultSets, Pair<String, String>[] tableColumn) throws SQLException
private Long[] getSecondaryIds(ResultSet[] secondaryResultSets, Pair<String, String>[] tableColumn) throws SQLException
{
Long[] secondaryIds = new Long[tableColumn.length];
@@ -572,7 +571,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected void closeQuietly(Statement statement)
private void closeQuietly(Statement statement)
{
if (statement != null)
{
@@ -587,7 +586,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected void closeQuietly(Statement[] statements)
private void closeQuietly(Statement[] statements)
{
if (statements != null)
{
@@ -598,7 +597,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected void closeQuietly(ResultSet resultSet)
private void closeQuietly(ResultSet resultSet)
{
if (resultSet != null)
{
@@ -613,7 +612,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
}
}
protected void closeQuietly(ResultSet[] resultSets)
private void closeQuietly(ResultSet[] resultSets)
{
if (resultSets != null)
{

View File

@@ -1,278 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2020 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.schema.script;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.sql.DataSource;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
/**
* Extends <code>{@link DeleteNotExistsExecutor}</code> to cope with MySQL
* specific fetch size limitation and restrictions.
*/
public class MySQLDeleteNotExistsExecutor extends DeleteNotExistsExecutor
{
private static final Log logger = LogFactory.getLog(MySQLDeleteNotExistsExecutor.class);
private final DataSource dataSource;
public MySQLDeleteNotExistsExecutor(Connection connection, String sql, int line, File scriptFile, Properties globalProperties, DataSource dataSource)
{
super(connection, sql, line, scriptFile, globalProperties);
this.dataSource = dataSource;
}
@Override
protected void process(Pair<String, String>[] tableColumn, Long[] tableUpperLimits, String[] optionalWhereClauses) throws SQLException
{
// The approach is to fetch ordered row ids from all referencer/secondary (e.g.
// alf_audit_app, alf_audit_entry, alf_prop_unique_ctx) tables and
// referenced/primary table (e.g. alf_prop_root) concurrently, so that it is
// possible skip over id gaps efficiently while at the same time being able to
// work out which ids are obsolete and delete them in batches.
// The algorithm can be further improved by iterating over the rows in descending order.
// This is due to the fact that older data should be more stable in time.
String primaryTableName = tableColumn[0].getFirst();
String primaryColumnName = tableColumn[0].getSecond();
String primaryWhereClause = optionalWhereClauses[0];
Long primaryId = 0L;
PreparedStatement primaryPrepStmt = null;
PreparedStatement[] secondaryPrepStmts = null;
PreparedStatement deletePrepStmt = null;
Set<Long> deleteIds = new HashSet<>();
deletedCount = 0L;
startTime = new Date();
long defaultOffset = 0L;
try
{
connection.setAutoCommit(false);
primaryPrepStmt = connection.prepareStatement(createLimitPreparedSelectStatement(primaryTableName, primaryColumnName, primaryWhereClause));
primaryPrepStmt.setLong(1, primaryId);
primaryPrepStmt.setLong(2, tableUpperLimits[0]);
primaryPrepStmt.setInt(3, batchSize);
primaryPrepStmt.setLong(4, defaultOffset);
boolean hasResults = primaryPrepStmt.execute();
if (hasResults)
{
secondaryPrepStmts = new PreparedStatement[tableColumn.length];
for (int i = 1; i < tableColumn.length; i++)
{
PreparedStatement secStmt = connection.prepareStatement(createLimitPreparedSelectStatement(tableColumn[i].getFirst(), tableColumn[i].getSecond(), optionalWhereClauses[i]));
secStmt.setLong(1, primaryId);
secStmt.setLong(2, tableUpperLimits[i]);
secStmt.setInt(3, batchSize);
secStmt.setLong(4, defaultOffset);
secondaryPrepStmts[i] = secStmt;
}
deletePrepStmt = connection.prepareStatement(createPreparedDeleteStatement(primaryTableName, primaryColumnName, deleteBatchSize, primaryWhereClause));
// Timeout is only checked at each bach start.
// It can be further refined by being verified at each primary row processing.
while (hasResults && !isTimeoutExceeded())
{
// Process batch
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
connection.commit();
if (primaryId == null)
{
break;
}
// Prepare for next batch
primaryPrepStmt.setLong(1, primaryId);
primaryPrepStmt.setLong(2, tableUpperLimits[0]);
primaryPrepStmt.setInt(3, batchSize);
primaryPrepStmt.setLong(4, defaultOffset);
for (int i = 1; i < tableColumn.length; i++)
{
PreparedStatement secStmt = secondaryPrepStmts[i];
secStmt.setLong(1, primaryId);
secStmt.setLong(2, tableUpperLimits[i]);
secStmt.setInt(3, batchSize);
secStmt.setLong(4, defaultOffset);
}
hasResults = primaryPrepStmt.execute();
}
}
// Check if we have any more ids to delete
if (!deleteIds.isEmpty())
{
deleteFromPrimaryTable(deletePrepStmt, deleteIds, primaryTableName);
connection.commit();
}
if (logger.isDebugEnabled())
{
String msg = ((readOnly) ? "Script would have" : "Script") + " deleted a total of " + deletedCount + " items from table " + primaryTableName + ".";
logger.debug(msg);
}
}
finally
{
closeQuietly(deletePrepStmt);
closeQuietly(secondaryPrepStmts);
closeQuietly(primaryPrepStmt);
connection.setAutoCommit(true);
}
}
protected Long processPrimaryTableResultSet(PreparedStatement primaryPrepStmt, PreparedStatement[] secondaryPrepStmts, PreparedStatement deletePrepStmt, Set<Long> deleteIds,
String primaryTableName, String primaryColumnName, Pair<String, String>[] tableColumn) throws SQLException
{
int rowsProcessed = 0;
Long primaryId = null;
ResultSet[] secondaryResultSets = null;
try (ResultSet resultSet = primaryPrepStmt.getResultSet())
{
secondaryResultSets = getSecondaryResultSets(secondaryPrepStmts);
Long[] secondaryIds = getSecondaryIds(secondaryResultSets, tableColumn);
// Create and populate secondary tables offsets
Long[] secondaryOffsets = new Long[tableColumn.length];
for (int i = 1; i < tableColumn.length; i++)
{
secondaryOffsets[i] = 0L;
}
while (resultSet.next())
{
++rowsProcessed;
primaryId = resultSet.getLong(primaryColumnName);
while (isLess(primaryId, secondaryIds))
{
deleteIds.add(primaryId);
if (deleteIds.size() == deleteBatchSize)
{
deleteFromPrimaryTable(deletePrepStmt, deleteIds, primaryTableName);
connection.commit();
}
if (!resultSet.next())
{
break;
}
++rowsProcessed;
primaryId = resultSet.getLong(primaryColumnName);
}
if (logger.isTraceEnabled())
{
logger.trace("RowsProcessed " + rowsProcessed + " from primary table " + primaryTableName);
}
updateSecondaryIds(primaryId, secondaryIds, secondaryPrepStmts, secondaryOffsets, secondaryResultSets, tableColumn);
}
}
finally
{
closeQuietly(secondaryResultSets);
}
return primaryId;
}
private void updateSecondaryIds(Long primaryId, Long[] secondaryIds, PreparedStatement[] secondaryPrepStmts, Long[] secondaryOffsets, ResultSet[] secondaryResultSets,
Pair<String, String>[] tableColumn) throws SQLException
{
for (int i = 1; i < tableColumn.length; i++)
{
Long secondaryId = secondaryIds[i];
while (secondaryId != null && primaryId >= secondaryId)
{
ResultSet resultSet = secondaryResultSets[i];
String columnId = tableColumn[i].getSecond();
secondaryId = getColumnValueById(resultSet, columnId);
// Check if we reach the end of the first page
if (secondaryId == null)
{
// Close the previous result set
closeQuietly(resultSet);
// Set to use the next page
long offset = secondaryOffsets[i] + batchSize;
secondaryOffsets[i] = offset;
PreparedStatement secStmt = secondaryPrepStmts[i];
secStmt.setLong(4, offset);
// Check if any results were found
boolean secHasResults = secStmt.execute();
secondaryResultSets[i] = secHasResults ? secStmt.getResultSet() : null;
// Try again to get the next secondary id
secondaryId = getColumnValueById(secondaryResultSets[i], columnId);
}
secondaryIds[i] = secondaryId;
}
}
}
private String createLimitPreparedSelectStatement(String tableName, String columnName, String whereClause)
{
StringBuilder sqlBuilder = new StringBuilder("SELECT " + columnName + " FROM " + tableName + " WHERE ");
if (whereClause != null && !whereClause.isEmpty())
{
sqlBuilder.append(whereClause + " AND ");
}
sqlBuilder.append(columnName + " > ? AND " + columnName + " <= ? ORDER BY " + columnName + " ASC LIMIT ? OFFSET ?");
return sqlBuilder.toString();
}
}

View File

@@ -350,7 +350,7 @@ public class ScriptExecutorImpl implements ScriptExecutor
}
else if (sql.startsWith("--DELETE_NOT_EXISTS"))
{
DeleteNotExistsExecutor deleteNotExists = createDeleteNotExistsExecutor(dialect, connection, sql, line, scriptFile);
DeleteNotExistsExecutor deleteNotExists = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, globalProperties);
deleteNotExists.execute();
// Reset
@@ -538,16 +538,6 @@ public class ScriptExecutorImpl implements ScriptExecutor
}
}
private DeleteNotExistsExecutor createDeleteNotExistsExecutor(Dialect dialect, Connection connection, String sql, int line, File scriptFile)
{
if (dialect instanceof MySQLInnoDBDialect)
{
return new MySQLDeleteNotExistsExecutor(connection, sql, line, scriptFile, globalProperties, dataSource);
}
return new DeleteNotExistsExecutor(connection, sql, line, scriptFile, globalProperties);
}
/**
* Execute the given SQL statement, absorbing exceptions that we expect during
* schema creation or upgrade.

View File

@@ -54,6 +54,7 @@ import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -89,11 +90,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
protected DictionaryService dictionaryService;
private DescriptorService descriptorService;
private EventFilterRegistry eventFilterRegistry;
private Event2MessageProducer event2MessageProducer;
private TransactionService transactionService;
private PersonService personService;
protected NodeResourceHelper nodeResourceHelper;
private EventGeneratorQueue eventGeneratorQueue;
private NodeTypeFilter nodeTypeFilter;
private ChildAssociationTypeFilter childAssociationTypeFilter;
private EventUserFilter userFilter;
@@ -108,10 +109,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
PropertyCheck.mandatory(this, "descriptorService", descriptorService);
PropertyCheck.mandatory(this, "eventFilterRegistry", eventFilterRegistry);
PropertyCheck.mandatory(this, "event2MessageProducer", event2MessageProducer);
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "personService", personService);
PropertyCheck.mandatory(this, "nodeResourceHelper", nodeResourceHelper);
PropertyCheck.mandatory(this, "eventGeneratorQueue", eventGeneratorQueue);
this.nodeTypeFilter = eventFilterRegistry.getNodeTypeFilter();
this.childAssociationTypeFilter = eventFilterRegistry.getChildAssociationTypeFilter();
@@ -176,6 +177,12 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
this.eventFilterRegistry = eventFilterRegistry;
}
@SuppressWarnings("unused")
public void setEvent2MessageProducer(Event2MessageProducer event2MessageProducer)
{
this.event2MessageProducer = event2MessageProducer;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
@@ -191,11 +198,6 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
this.nodeResourceHelper = nodeResourceHelper;
}
public void setEventGeneratorQueue(EventGeneratorQueue eventGeneratorQueue)
{
this.eventGeneratorQueue = eventGeneratorQueue;
}
@Override
public void onCreateNode(ChildAssociationRef childAssocRef)
{
@@ -426,26 +428,20 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
protected void sendEvent(NodeRef nodeRef, EventConsolidator consolidator)
{
EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser());
eventGeneratorQueue.accept(()-> createEvent(nodeRef, consolidator, eventInfo));
}
private RepoEvent<?> createEvent(NodeRef nodeRef, EventConsolidator consolidator, EventInfo eventInfo)
{
String user = eventInfo.getPrincipal();
if (consolidator.isTemporaryNode())
{
if (LOGGER.isTraceEnabled())
{
LOGGER.trace("Ignoring temporary node: " + nodeRef);
}
return null;
return;
}
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
// Get the repo event before the filtering,
// so we can take the latest node info into account
final RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
final RepoEvent<?> event = consolidator.getRepoEvent(getEventInfo(user));
final QName nodeType = consolidator.getNodeType();
if (isFiltered(nodeType, user))
@@ -456,7 +452,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
+ ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString())
+ "' created by: " + user);
}
return null;
return;
}
if (event.getType().equals(EventType.NODE_UPDATED.getType()) && consolidator.isResourceBeforeAllFieldsNull())
@@ -465,34 +461,27 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
{
LOGGER.trace("Ignoring node updated event as no fields have been updated: " + nodeRef);
}
return null;
return;
}
logEvent(event, consolidator.getEventTypes());
return event;
logAndSendEvent(event, consolidator.getEventTypes());
}
protected void sendEvent(ChildAssociationRef childAssociationRef, ChildAssociationEventConsolidator consolidator)
{
EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser());
eventGeneratorQueue.accept(()-> createEvent(eventInfo, childAssociationRef, consolidator));
}
private RepoEvent<?> createEvent(EventInfo eventInfo, ChildAssociationRef childAssociationRef, ChildAssociationEventConsolidator consolidator)
{
String user = eventInfo.getPrincipal();
if (consolidator.isTemporaryChildAssociation())
{
if (LOGGER.isTraceEnabled())
{
LOGGER.trace("Ignoring temporary child association: " + childAssociationRef);
}
return null;
return;
}
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
// Get the repo event before the filtering,
// so we can take the latest association info into account
final RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
final RepoEvent<?> event = consolidator.getRepoEvent(getEventInfo(user));
final QName childAssocType = consolidator.getChildAssocType();
if (isFilteredChildAssociation(childAssocType, user))
@@ -503,7 +492,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
+ "' created by: " + user);
}
return null;
return;
} else if (childAssociationRef.isPrimary())
{
if (LOGGER.isTraceEnabled())
@@ -512,20 +501,13 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
+ "' created by: " + user);
}
return null;
return;
}
logEvent(event, consolidator.getEventTypes());
return event;
logAndSendEvent(event, consolidator.getEventTypes());
}
protected void sendEvent(AssociationRef peerAssociationRef, PeerAssociationEventConsolidator consolidator)
{
EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser());
eventGeneratorQueue.accept(()-> createEvent(eventInfo, peerAssociationRef, consolidator));
}
private RepoEvent<?> createEvent(EventInfo eventInfo, AssociationRef peerAssociationRef, PeerAssociationEventConsolidator consolidator)
{
if (consolidator.isTemporaryPeerAssociation())
{
@@ -533,21 +515,30 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
{
LOGGER.trace("Ignoring temporary peer association: " + peerAssociationRef);
}
return null;
return;
}
RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
logEvent(event, consolidator.getEventTypes());
return event;
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
// Get the repo event before the filtering,
// so we can take the latest association info into account
final RepoEvent<?> event = consolidator.getRepoEvent(getEventInfo(user));
logAndSendEvent(event, consolidator.getEventTypes());
}
private void logEvent(RepoEvent<?> event, Deque<EventType> listOfEvents)
protected void logAndSendEvent(RepoEvent<?> event, Deque<EventType> listOfEvents)
{
if (LOGGER.isTraceEnabled())
{
LOGGER.trace("List of Events:" + listOfEvents);
LOGGER.trace("Sending event:" + event);
}
// Need to execute this in another read txn because Camel expects it
transactionService.getRetryingTransactionHelper().doInTransaction((RetryingTransactionCallback<Void>) () -> {
event2MessageProducer.send(event);
return null;
}, true, false);
}
}

View File

@@ -1,179 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 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.event2;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.alfresco.repo.event.v1.model.RepoEvent;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/*
* This queue allows to create asynchronously the RepoEvent offloading the work to a ThreadPool but
* at the same time it preserves the order of the events
*/
public class EventGeneratorQueue implements InitializingBean
{
protected static final Log LOGGER = LogFactory.getLog(EventGeneratorQueue.class);
protected Executor enqueueThreadPoolExecutor;
protected Executor dequeueThreadPoolExecutor;
protected Event2MessageProducer event2MessageProducer;
protected BlockingQueue<EventInMaking> queue = new LinkedBlockingQueue<>();
protected Runnable listener = createListener();
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "enqueueThreadPoolExecutor", enqueueThreadPoolExecutor);
PropertyCheck.mandatory(this, "dequeueThreadPoolExecutor", dequeueThreadPoolExecutor);
PropertyCheck.mandatory(this, "event2MessageProducer", event2MessageProducer);
}
public void setEvent2MessageProducer(Event2MessageProducer event2MessageProducer)
{
this.event2MessageProducer = event2MessageProducer;
}
public void setEnqueueThreadPoolExecutor(Executor enqueueThreadPoolExecutor)
{
this.enqueueThreadPoolExecutor = enqueueThreadPoolExecutor;
}
public void setDequeueThreadPoolExecutor(Executor dequeueThreadPoolExecutor)
{
this.dequeueThreadPoolExecutor = dequeueThreadPoolExecutor;
dequeueThreadPoolExecutor.execute(listener);
}
/**
* Procedure to enqueue the callback functions that creates an event.
* @param maker Callback function that creates an event.
*/
public void accept(Callable<RepoEvent<?>> maker)
{
EventInMaking eventInMaking = new EventInMaking(maker);
queue.offer(eventInMaking);
enqueueThreadPoolExecutor.execute(() -> {
try
{
eventInMaking.make();
}
catch (Exception e)
{
LOGGER.error("Unexpected error while enqueuing maker function for repository event" + e);
}
});
}
/**
* Create listener task in charge of dequeuing and sending events ready to be sent.
* @return The task in charge of dequeuing and sending events ready to be sent.
*/
private Runnable createListener()
{
return new Runnable()
{
@Override
public void run()
{
try
{
while (!Thread.interrupted())
{
try
{
EventInMaking eventInMaking = queue.take();
RepoEvent<?> event = eventInMaking.getEventWhenReady();
if (event != null)
{
event2MessageProducer.send(event);
}
}
catch (Exception e)
{
LOGGER.error("Unexpected error while dequeuing and sending repository event" + e);
}
}
}
finally
{
LOGGER.warn("Unexpected: rescheduling the listener thread.");
dequeueThreadPoolExecutor.execute(listener);
}
}
};
}
/*
* Simple class that makes events and allows to retrieve them when ready
*/
private static class EventInMaking
{
private Callable<RepoEvent<?>> maker;
private volatile RepoEvent<?> event;
private CountDownLatch latch;
public EventInMaking(Callable<RepoEvent<?>> maker)
{
this.maker = maker;
this.latch = new CountDownLatch(1);
}
public void make() throws Exception
{
try
{
event = maker.call();
}
finally
{
latch.countDown();
}
}
public RepoEvent<?> getEventWhenReady() throws InterruptedException
{
latch.await(30, TimeUnit.SECONDS);
return event;
}
@Override
public String toString()
{
return maker.toString();
}
}
}

View File

@@ -0,0 +1,538 @@
/*
* #%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.rendition.executer;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.rendition.RenditionLocation;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.rendition.RenditionServiceException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.sax.ContentHandlerDecorator;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This class provides a way to turn documents supported by the
* {@link ContentService} standard transformers into basic, clean
* HTML.
* <P/>
* The HTML that is produced probably isn't going to be suitable
* for direct web publishing, as it's likely going to be too
* basic. Instead, it should be simple and clean HTML, suitable
* for being the basis of some web-friendly HTML once edited
* / further transformed.
*
* @author Nick Burch
* @since 3.4
*
* @deprecated The RenditionService is being replace by the simpler async RenditionService2.
*/
@Deprecated
public class HTMLRenderingEngine extends AbstractRenderingEngine
{
private static Log logger = LogFactory.getLog(HTMLRenderingEngine.class);
private TikaConfig tikaConfig;
/**
* This optional parameter, when set to true, causes only the
* contents of the HTML body to be written out as the rendition.
* By default, the whole of the HTML document is used.
*/
public static final String PARAM_BODY_CONTENTS_ONLY = "bodyContentsOnly";
/**
* This optional parameter, when set to true, causes any embedded
* images to be written into the same folder as the html, with
* a name prefix.
* By default, images are placed into a sub-folder.
*/
public static final String PARAM_IMAGES_SAME_FOLDER = "imagesSameFolder";
/*
* Action constants
*/
public static final String NAME = "htmlRenderingEngine";
@Override
protected Collection<ParameterDefinition> getParameterDefinitions() {
Collection<ParameterDefinition> paramList = super.getParameterDefinitions();
paramList.add(new ParameterDefinitionImpl(PARAM_BODY_CONTENTS_ONLY, DataTypeDefinition.BOOLEAN, false,
getParamDisplayLabel(PARAM_BODY_CONTENTS_ONLY)));
paramList.add(new ParameterDefinitionImpl(PARAM_IMAGES_SAME_FOLDER, DataTypeDefinition.BOOLEAN, false,
getParamDisplayLabel(PARAM_IMAGES_SAME_FOLDER)));
return paramList;
}
/**
* Injects the TikaConfig to use
*
* @param tikaConfig The Tika Config to use
*/
public void setTikaConfig(TikaConfig tikaConfig)
{
this.tikaConfig = tikaConfig;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org.alfresco.repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
*/
@Override
protected void render(RenderingContext context)
{
ContentReader contentReader = context.makeContentReader();
String sourceMimeType = contentReader.getMimetype();
// Check that Tika supports the supplied file
AutoDetectParser p = new AutoDetectParser(tikaConfig);
MediaType sourceMediaType = MediaType.parse(sourceMimeType);
if(! p.getParsers().containsKey(sourceMediaType))
{
throw new RenditionServiceException(
"Source mime type of " + sourceMimeType +
" is not supported by Tika for HTML conversions"
);
}
// Make the HTML Version using Tika
// This will also extract out any images as found
generateHTML(p, context);
}
private String getHtmlBaseName(RenderingContext context)
{
// Based on the name of the source node, which will
// also largely be the name of the html node
String baseName = nodeService.getProperty(
context.getSourceNode(),
ContentModel.PROP_NAME
).toString();
if(baseName.lastIndexOf('.') > -1)
{
baseName = baseName.substring(0, baseName.lastIndexOf('.'));
}
return baseName;
}
/**
* What name should be used for the images directory?
* Note this is only required if {@link #PARAM_IMAGES_SAME_FOLDER} is false (the default).
*/
private String getImagesDirectoryName(RenderingContext context)
{
// Based on the name of the source node, which will
// also largely be the name of the html node
String folderName = getHtmlBaseName(context);
folderName = folderName + "_files";
return folderName;
}
/**
* What prefix should be applied to the name of images?
*/
private String getImagesPrefixName(RenderingContext context)
{
if( context.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false) )
{
// Prefix with the name of the source node
return getHtmlBaseName(context) + "_";
}
else {
// They have their own folder, so no prefix is needed
return "";
}
}
/**
* Creates a directory to store the images in.
* The directory will be a sibling of the rendered
* HTML, and named similar to it.
* Note this is only required if {@link #PARAM_IMAGES_SAME_FOLDER} is false (the default).
*/
private NodeRef createImagesDirectory(RenderingContext context)
{
// It should be a sibling of the HTML in it's eventual location
// (not it's current temporary one!)
RenditionLocation location = resolveRenditionLocation(
context.getSourceNode(), context.getDefinition(), context.getDestinationNode()
);
NodeRef parent = location.getParentRef();
// Figure out what to call it, based on the HTML node
String folderName = getImagesDirectoryName(context);
// It is already there?
// (eg from when the rendition is being re-run)
NodeRef imgFolder = nodeService.getChildByName(
parent, ContentModel.ASSOC_CONTAINS, folderName
);
if(imgFolder != null)
return imgFolder;
// Create the directory
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
properties.put(ContentModel.PROP_NAME, folderName);
imgFolder = nodeService.createNode(
parent,
ContentModel.ASSOC_CONTAINS,
QName.createQName(folderName),
ContentModel.TYPE_FOLDER,
properties
).getChildRef();
return imgFolder;
}
private NodeRef createEmbeddedImage(NodeRef imgFolder, boolean primary,
String filename, String contentType, InputStream imageSource,
RenderingContext context)
{
// Create the node if needed
NodeRef img = nodeService.getChildByName(
imgFolder, ContentModel.ASSOC_CONTAINS, filename
);
if(img == null)
{
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
properties.put(ContentModel.PROP_NAME, filename);
img = nodeService.createNode(
imgFolder,
ContentModel.ASSOC_CONTAINS,
QName.createQName(filename),
ContentModel.TYPE_CONTENT,
properties
).getChildRef();
if (logger.isDebugEnabled())
{
logger.debug("Image node created: " + img);
}
}
// TODO Once composite content is properly supported,
// at this point we'll associate the new image with
// the rendered HTML node so the dependency is tracked.
// Put the image into the node
ContentWriter writer = contentService.getWriter(
img, ContentModel.PROP_CONTENT, true
);
writer.setMimetype(contentType);
writer.putContent(imageSource);
if (logger.isDebugEnabled())
{
logger.debug("Image content written into " + img);
}
// All done
return img;
}
/**
* Builds a Tika-compatible SAX content handler, which will
* be used to generate+capture the XHTML
*/
private ContentHandler buildContentHandler(Writer output, RenderingContext context)
{
// Create the main transformer
SAXTransformerFactory factory = (SAXTransformerFactory)
SAXTransformerFactory.newInstance();
TransformerHandler handler;
try {
handler = factory.newTransformerHandler();
} catch (TransformerConfigurationException e) {
throw new RenditionServiceException("SAX Processing isn't available - " + e);
}
handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
handler.setResult(new StreamResult(output));
handler.getTransformer().setOutputProperty(OutputKeys.METHOD, "xml");
// Change the image links as they go past
String dirName = null, imgPrefix = null;
if(context.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false))
{
imgPrefix = getImagesPrefixName(context);
}
else
{
dirName = getImagesDirectoryName(context);
}
ContentHandler contentHandler = new TikaImageRewritingContentHandler(
handler, dirName, imgPrefix
);
// If required, wrap it to only return the body
boolean bodyOnly = context.getParamWithDefault(PARAM_BODY_CONTENTS_ONLY, false);
if(bodyOnly) {
contentHandler = new BodyContentHandler(contentHandler);
}
// All done
return contentHandler;
}
/**
* Asks Tika to translate the contents into HTML
*/
private void generateHTML(Parser p, RenderingContext context)
{
ContentReader contentReader = context.makeContentReader();
// Setup things to parse with
StringWriter sw = new StringWriter();
ContentHandler handler = buildContentHandler(sw, context);
// Tell Tika what we're dealing with
Metadata metadata = new Metadata();
metadata.set(
Metadata.CONTENT_TYPE,
contentReader.getMimetype()
);
metadata.set(
Metadata.RESOURCE_NAME_KEY,
nodeService.getProperty(
context.getSourceNode(),
ContentModel.PROP_NAME
).toString()
);
// Our parse context needs to extract images
ParseContext parseContext = new ParseContext();
parseContext.set(Parser.class, new TikaImageExtractingParser(context));
// Parse
try {
p.parse(
contentReader.getContentInputStream(),
handler, metadata, parseContext
);
} catch(Exception e) {
throw new RenditionServiceException("Tika HTML Conversion Failed", e);
}
// As a string
String html = sw.toString();
// If we're doing body-only, remove all the html namespaces
// that will otherwise clutter up the document
boolean bodyOnly = context.getParamWithDefault(PARAM_BODY_CONTENTS_ONLY, false);
if(bodyOnly) {
html = html.replaceAll("<\\?xml.*?\\?>", "");
html = html.replaceAll("<p xmlns=\"http://www.w3.org/1999/xhtml\"","<p");
html = html.replaceAll("<h(\\d) xmlns=\"http://www.w3.org/1999/xhtml\"","<h\\1");
html = html.replaceAll("<div xmlns=\"http://www.w3.org/1999/xhtml\"","<div");
html = html.replaceAll("<table xmlns=\"http://www.w3.org/1999/xhtml\"","<table");
html = html.replaceAll("&#13;","");
}
// Save it
ContentWriter contentWriter = context.makeContentWriter();
contentWriter.setMimetype("text/html");
contentWriter.putContent( html );
}
/**
* A nested Tika parser which extracts out any
* images as they come past.
*/
@SuppressWarnings("serial")
private class TikaImageExtractingParser implements Parser {
private Set<MediaType> types;
private RenderingContext renderingContext;
private NodeRef imgFolder = null;
private int count = 0;
private TikaImageExtractingParser(RenderingContext renderingContext) {
this.renderingContext = renderingContext;
// Our expected types
types = new HashSet<MediaType>();
types.add(MediaType.image("bmp"));
types.add(MediaType.image("gif"));
types.add(MediaType.image("jpg"));
types.add(MediaType.image("jpeg"));
types.add(MediaType.image("png"));
types.add(MediaType.image("tiff"));
// Are images going in the same place as the HTML?
if( renderingContext.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false) )
{
RenditionLocation location = resolveRenditionLocation(
renderingContext.getSourceNode(), renderingContext.getDefinition(),
renderingContext.getDestinationNode()
);
imgFolder = location.getParentRef();
if (logger.isDebugEnabled())
{
logger.debug("Using imgFolder: " + imgFolder);
}
}
}
@Override
public Set<MediaType> getSupportedTypes(ParseContext context) {
return types;
}
@Override
public void parse(InputStream stream, ContentHandler handler,
Metadata metadata, ParseContext context) throws IOException,
SAXException, TikaException {
// Is it a supported image?
String filename = metadata.get(Metadata.RESOURCE_NAME_KEY);
String type = metadata.get(Metadata.CONTENT_TYPE);
boolean accept = false;
if(type != null) {
for(MediaType mt : types) {
if(mt.toString().equals(type)) {
accept = true;
}
}
}
if(filename != null) {
for(MediaType mt : types) {
String ext = "." + mt.getSubtype();
if(filename.endsWith(ext)) {
accept = true;
}
}
}
if(!accept)
return;
handleImage(stream, filename, type);
}
private void handleImage(InputStream stream, String filename, String type) {
count++;
// Do we already have the folder? If not, create it
if(imgFolder == null) {
imgFolder = createImagesDirectory(renderingContext);
}
// Give it a sensible name if needed
if(filename == null) {
filename = "image-" + count + ".";
filename += type.substring(type.indexOf('/')+1);
}
// Prefix the filename if needed
filename = getImagesPrefixName(renderingContext) + filename;
// Save the image
createEmbeddedImage(imgFolder, (count==1), filename, type, stream, renderingContext);
}
}
/**
* A content handler that re-writes image src attributes,
* and passes everything else on to the real one.
*/
private class TikaImageRewritingContentHandler extends ContentHandlerDecorator {
private String imageFolder;
private String imagePrefix;
private TikaImageRewritingContentHandler(ContentHandler handler, String imageFolder, String imagePrefix) {
super(handler);
this.imageFolder = imageFolder;
this.imagePrefix = imagePrefix;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes origAttrs) throws SAXException {
// If we have an image tag, re-write the src attribute
// if required
if("img".equals(localName)) {
AttributesImpl attrs;
if(origAttrs instanceof AttributesImpl) {
attrs = (AttributesImpl)origAttrs;
} else {
attrs = new AttributesImpl(origAttrs);
}
for(int i=0; i<attrs.getLength(); i++) {
if("src".equals(attrs.getLocalName(i))) {
String src = attrs.getValue(i);
if(src.startsWith("embedded:")) {
String newSrc = "";
if(imageFolder != null)
newSrc += imageFolder + "/";
if(imagePrefix != null)
newSrc += imagePrefix;
newSrc += src.substring(src.indexOf(':')+1);
attrs.setValue(i, newSrc);
}
}
}
super.startElement(uri, localName, qName, attrs);
} else {
// For any other tag, pass through as-is
super.startElement(uri, localName, qName, origAttrs);
}
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -52,7 +52,6 @@ import java.util.Set;
import java.util.StringJoiner;
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
import static org.alfresco.repo.content.transform.magick.ImageTransformationOptions.OPT_COMMAND_OPTIONS;
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALLOW_ENLARGEMENT;
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALLOW_PDF_ENLARGEMENT;
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALPHA_REMOVE;
@@ -123,7 +122,6 @@ public class TransformationOptionsConverter implements InitializingBean
IMAGE_OPTIONS.addAll(RESIZE_OPTIONS);
IMAGE_OPTIONS.add(AUTO_ORIENT);
IMAGE_OPTIONS.add(ALPHA_REMOVE);
IMAGE_OPTIONS.add(OPT_COMMAND_OPTIONS);
}
private static Set<String> PDF_OPTIONS = new HashSet<>(Arrays.asList(new String[]
@@ -286,8 +284,6 @@ public class TransformationOptionsConverter implements InitializingBean
}
opts.setSourceOptionsList(sourceOptionsList);
}
ifSet(options, OPT_COMMAND_OPTIONS, (v) -> opts.setCommandOptions(v));
}
}
else
@@ -365,11 +361,13 @@ public class TransformationOptionsConverter implements InitializingBean
{
ImageTransformationOptions opts = (ImageTransformationOptions) options;
// From a security viewpoint it would be better not to support the option of passing anything to
// ImageMagick. It might be possible to extract some of the well know values and add them to the
// T-Engine engine_config.
// TODO We don't support this any more for security reasons, however it might be possible to
// extract some of the well know values and add them to the newer ImageMagick transform options.
String commandOptions = opts.getCommandOptions();
ifSet(commandOptions != null && !commandOptions.isBlank(), map, OPT_COMMAND_OPTIONS, commandOptions);
if (commandOptions != null && !commandOptions.isBlank())
{
logger.error("ImageMagick commandOptions are no longer supported for security reasons: " + commandOptions);
}
ImageResizeOptions imageResizeOptions = opts.getResizeOptions();
if (imageResizeOptions != null)

View File

@@ -26,9 +26,6 @@
package org.alfresco.repo.search;
import org.alfresco.error.AlfrescoRuntimeException;
import org.apache.http.HttpStatus;
import java.util.List;
/**
* @author Andy
@@ -36,10 +33,11 @@ import java.util.List;
*/
public class QueryParserException extends AlfrescoRuntimeException
{
/** Serial version UUID. */
/**
*
*/
private static final long serialVersionUID = 4886993838297301968L;
/** Http Status Code that should be returned by Remote API. */
private int httpStatusCode;
/**
* @param msgId
@@ -47,6 +45,7 @@ public class QueryParserException extends AlfrescoRuntimeException
public QueryParserException(String msgId)
{
super(msgId);
// TODO Auto-generated constructor stub
}
/**
@@ -56,6 +55,7 @@ public class QueryParserException extends AlfrescoRuntimeException
public QueryParserException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
// TODO Auto-generated constructor stub
}
/**
@@ -65,6 +65,7 @@ public class QueryParserException extends AlfrescoRuntimeException
public QueryParserException(String msgId, Throwable cause)
{
super(msgId, cause);
// TODO Auto-generated constructor stub
}
/**
@@ -75,22 +76,7 @@ public class QueryParserException extends AlfrescoRuntimeException
public QueryParserException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
// TODO Auto-generated constructor stub
}
/**
* Constructor for exception that allows setting an HTTP status code.
*
* @param msgId Message for the exception
* @param httpStatusCode Status code to return for exception
*/
public QueryParserException(String msgId, int httpStatusCode)
{
super(msgId);
this.httpStatusCode = httpStatusCode;
}
public int getHttpStatusCode()
{
return httpStatusCode;
}
}

View File

@@ -35,7 +35,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
@@ -47,7 +46,6 @@ import org.alfresco.repo.cache.lookup.EntityLookupCache;
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor;
import org.alfresco.repo.domain.node.Node;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.StoreEntity;
import org.alfresco.repo.domain.permissions.AclCrudDAO;
import org.alfresco.repo.domain.permissions.Authority;
import org.alfresco.repo.domain.qname.QNameDAO;
@@ -112,12 +110,8 @@ public class DBQueryEngine implements QueryEngine
private long maxPermissionCheckTimeMillis;
private boolean maxPermissionCheckEnabled;
protected EntityLookupCache<Long, Node, NodeRef> nodesCache;
private List<Pair<Long, StoreRef>> stores;
AclCrudDAO aclCrudDAO;
public void setAclCrudDAO(AclCrudDAO aclCrudDAO)
@@ -135,11 +129,6 @@ public class DBQueryEngine implements QueryEngine
this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis;
}
public void setMaxPermissionCheckEnabled(boolean maxPermissionCheckEnabled)
{
this.maxPermissionCheckEnabled = maxPermissionCheckEnabled;
}
public void setTemplate(SqlSessionTemplate template)
{
this.template = template;
@@ -324,9 +313,6 @@ public class DBQueryEngine implements QueryEngine
FilteringResultSet acceleratedNodeSelection(QueryOptions options, DBQuery dbQuery, NodePermissionAssessor permissionAssessor)
{
// get list of stores from database
stores = nodeDAO.getStores();
List<Node> nodes = new ArrayList<>();
int requiredNodes = computeRequiredNodesCount(options);
@@ -336,16 +322,21 @@ public class DBQueryEngine implements QueryEngine
@Override
public void handleResult(ResultContext<? extends Node> context)
{
if (!maxPermissionCheckEnabled && nodes.size() >= requiredNodes)
doHandleResult(permissionAssessor, nodes, requiredNodes, context);
}
private void doHandleResult(NodePermissionAssessor permissionAssessor, List<Node> nodes,
int requiredNodes, ResultContext<? extends Node> context)
{
if (nodes.size() >= requiredNodes)
{
context.stop();
return;
}
Node node = context.getResultObject();
addStoreInfo(node);
boolean shouldCache = shouldCache(options, nodes, requiredNodes);
boolean shouldCache = nodes.size() >= options.getSkipCount();
if(shouldCache)
{
logger.debug("- selected node "+nodes.size()+": "+node.getUuid()+" "+node.getId());
@@ -358,14 +349,7 @@ public class DBQueryEngine implements QueryEngine
if (permissionAssessor.isIncluded(node))
{
if (nodes.size() > requiredNodes)
{
nodes.add(node);
}
else
{
nodes.add(shouldCache ? node : null);
}
nodes.add(shouldCache ? node : null);
}
if (permissionAssessor.shouldQuitChecks())
@@ -374,18 +358,6 @@ public class DBQueryEngine implements QueryEngine
return;
}
}
private boolean shouldCache(QueryOptions options, List<Node> nodes, int requiredNodes)
{
if (nodes.size() > requiredNodes)
{
return false;
}
else
{
return nodes.size() >= options.getSkipCount();
}
}
});
int numberFound = nodes.size();
@@ -485,21 +457,4 @@ public class DBQueryEngine implements QueryEngine
return value.getNodeRef();
}
}
private void addStoreInfo(Node node)
{
StoreEntity storeEntity = node.getStore();
logger.debug("Adding store info for store id " + storeEntity.getId());
for (Pair<Long, StoreRef> storeRefPair : stores)
{
if (Objects.equals(storeEntity.getId(), storeRefPair.getFirst()))
{
StoreRef storeRef = storeRefPair.getSecond();
storeEntity.setIdentifier(storeRef.getIdentifier());
storeEntity.setProtocol(storeRef.getProtocol());
logger.debug("Added store info" + storeEntity.toString());
break;
}
}
}
}

View File

@@ -41,13 +41,9 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class NodePermissionAssessor
{
protected static final Log logger = LogFactory.getLog(NodePermissionAssessor.class);
private final boolean isSystemReading;
private final boolean isAdminReading;
private final boolean isNullReading;
@@ -142,31 +138,24 @@ public class NodePermissionAssessor
public void setMaxPermissionChecks(int maxPermissionChecks)
{
if (maxPermissionChecks == Integer.MAX_VALUE)
{
this.maxPermissionChecks = maxPermissionChecks;
}
else
{
this.maxPermissionChecks = maxPermissionChecks + 1;
}
this.maxPermissionChecks = maxPermissionChecks;
}
public boolean shouldQuitChecks()
{
boolean result = false;
if (checksPerformed >= maxPermissionChecks)
{
logger.warn("Maximum permission checks exceeded (" + maxPermissionChecks + ")");
return true;
result = true;
}
if ((System.currentTimeMillis() - startTime) >= maxPermissionCheckTimeMillis)
{
logger.warn("Maximum permission checks time exceeded (" + maxPermissionCheckTimeMillis + ")");
return true;
result = true;
}
return false;
return result;
}
public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis)

View File

@@ -29,29 +29,26 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.search.QueryParserException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public abstract class AbstractSolrQueryHTTPClient
{
/** Logger for the class. */
private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class);
public static final int DEFAULT_SAVEPOST_BUFFER = 4096;
// Constants copied from org.apache.solr.common.params.HighlightParams (solr-solrj:1.4.1)
@@ -83,12 +80,10 @@ public abstract class AbstractSolrQueryHTTPClient
public static final String HIGHLIGHT_PARAMS_PATTERN = HIGHLIGHT_PARAMS_HIGHLIGHT + "." + HIGHLIGHT_PARAMS_REGEX + ".pattern";
public static final String HIGHLIGHT_PARAMS_MAX_RE_CHARS = HIGHLIGHT_PARAMS_HIGHLIGHT + "." + HIGHLIGHT_PARAMS_REGEX + ".maxAnalyzedChars";
/** List of SOLR Exceptions that should be returning HTTP 501 status code in Remote API. */
private static final List<String> STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException");
protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException
protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws UnsupportedEncodingException,
IOException, HttpException, URIException, JSONException
{
PostMethod post = createNewPostMethod(url);
PostMethod post = new PostMethod(url);
if (body.toString().length() > DEFAULT_SAVEPOST_BUFFER)
{
post.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true);
@@ -108,33 +103,9 @@ public abstract class AbstractSolrQueryHTTPClient
httpClient.executeMethod(post);
}
}
String responseBodyStr = post.getResponseBodyAsString();
if (post.getStatusCode() != HttpServletResponse.SC_OK)
{
String trace = null;
try
{
trace = new JSONObject(responseBodyStr).getJSONObject("error").getString("trace");
}
catch (JSONException jsonException)
{
LOGGER.warn("Node 'error.trace' is not present in Search Services error response: " + responseBodyStr);
LOGGER.warn("A generic error message will be provided. Check SOLR log file in order to find the root cause for this issue");
}
int httpStatusCode = post.getStatusCode();
String message = "Solr request failed with " + httpStatusCode + " " + url;
// Override the status code for certain exceptions with 501.
if (trace != null)
{
String traceException = trace.substring(0, trace.indexOf(":")).trim();
if (STATUS_CODE_501_EXCEPTIONS.contains(traceException))
{
httpStatusCode = org.apache.http.HttpStatus.SC_NOT_IMPLEMENTED;
}
}
throw new QueryParserException(message, httpStatusCode);
throw new QueryParserException("Request failed " + post.getStatusCode() + " " + url.toString());
}
Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream(), post.getResponseCharSet()));
@@ -147,10 +118,4 @@ public abstract class AbstractSolrQueryHTTPClient
post.releaseConnection();
}
}
/** Helper method that can be overridden by unit tests. */
protected PostMethod createNewPostMethod(String url)
{
return new PostMethod(url);
}
}

View File

@@ -456,20 +456,12 @@ public class RepoUsageComponentImpl implements RepoUsageComponent
}
}
// Check the license expiration
// Check the license expiry
Long licenseExpiryDate = restrictions.getLicenseExpiryDate();
if (licenseExpiryDate != null)
{
//For informational purposes, get the remaining number of days, counting from the beginning of the day of each date (now and expiration date)
int remainingDays = DateUtil.calculateDays(System.currentTimeMillis(), licenseExpiryDate);
int remainingMills = 0;
if (remainingDays == 0)
{
//Get exact number of milliseconds between license expiration time and now to see if is expired
remainingMills = DateUtil.calculateMs(System.currentTimeMillis(), licenseExpiryDate);
}
if (remainingDays < 0 || remainingMills < 0)
if (remainingDays <= 0)
{
errors.add(I18NUtil.getMessage("system.usage.err.limit_license_expired"));
level = RepoUsageLevel.LOCKED_DOWN;

View File

@@ -322,7 +322,7 @@ public class CombinedConfig
{
combinedTransformers.remove(indexToRemove);
// this may also require the current index i to be changed so we don't skip one.
if (i >= indexToRemove)
if (i <= indexToRemove)
{
i--;
}

View File

@@ -71,34 +71,4 @@ public class DateUtil
}
return days;
}
/**
* Calculate the number of milliseconds between start and end dates based on the <b>default</b> timezone.
* If the end date is before the start date, the returned value is negative.
*
* @param startMs start date in milliseconds
* @param endMs end date in milliseconds
* @return number milliseconds between
*/
public static int calculateMs(long startMs, long endMs)
{
DateTime startDateTime = new DateTime(startMs);
DateTime endDateTime = new DateTime(endMs);
int milliseconds;
if (endDateTime.isBefore(startDateTime))
{
Interval interval = new Interval(endDateTime, startDateTime);
Period period = interval.toPeriod(PeriodType.millis());
milliseconds = 0 - period.getMillis();
}
else
{
Interval interval = new Interval(startDateTime, endDateTime);
Period period = interval.toPeriod(PeriodType.millis());
milliseconds = period.getMillis();
}
return milliseconds;
}
}

View File

@@ -38,10 +38,9 @@
<property name="dictionaryService" ref="dictionaryService"/>
<property name="descriptorService" ref="descriptorComponent"/>
<property name="eventFilterRegistry" ref="event2FilterRegistry"/>
<property name="event2MessageProducer" ref="event2MessageProducer"/>
<property name="transactionService" ref="transactionService"/>
<property name="personService" ref="personService"/>
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
<property name="eventGeneratorQueue" ref="eventGeneratorQueue"/>
</bean>
<bean id="baseNodeResourceHelper" abstract="true">
@@ -55,45 +54,7 @@
<bean id="nodeResourceHelper" class="org.alfresco.repo.event2.NodeResourceHelper" parent="baseNodeResourceHelper"/>
<bean id="eventGeneratorV2" class="org.alfresco.repo.event2.EventGenerator" parent="baseEventGeneratorV2"/>
<bean id="eventGeneratorQueue" class="org.alfresco.repo.event2.EventGeneratorQueue" >
<property name="enqueueThreadPoolExecutor">
<ref bean="eventAsyncEnqueueThreadPool" />
</property>
<property name="dequeueThreadPoolExecutor">
<ref bean="eventAsyncDequeueThreadPool" />
</property>
<property name="event2MessageProducer" ref="event2MessageProducer"/>
</bean>
<bean id="eventAsyncEnqueueThreadPool" class="org.alfresco.util.ThreadPoolExecutorFactoryBean">
<property name="poolName">
<value>eventAsyncEnqueueThreadPool</value>
</property>
<property name="corePoolSize">
<value>${repo.event2.queue.enqueueThreadPool.coreSize}</value>
</property>
<property name="maximumPoolSize">
<value>${repo.event2.queue.enqueueThreadPool.maximumSize}</value>
</property>
<property name="threadPriority">
<value>${repo.event2.queue.enqueueThreadPool.priority}</value>
</property>
</bean>
<bean id="eventAsyncDequeueThreadPool" class="org.alfresco.util.ThreadPoolExecutorFactoryBean">
<property name="poolName">
<value>eventAsyncDequeueThreadPool</value>
</property>
<property name="corePoolSize">
<value>${repo.event2.queue.dequeueThreadPool.coreSize}</value>
</property>
<property name="maximumPoolSize">
<value>${repo.event2.queue.dequeueThreadPool.maximumSize}</value>
</property>
<property name="threadPriority">
<value>${repo.event2.queue.dequeueThreadPool.priority}</value>
</property>
<bean id="eventGeneratorV2" class="org.alfresco.repo.event2.EventGenerator" parent="baseEventGeneratorV2">
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
</bean>
</beans>

View File

@@ -178,6 +178,14 @@
</property>
</bean>
<bean id="htmlRenderingEngine"
class="org.alfresco.repo.rendition.executer.HTMLRenderingEngine"
parent="baseRenderingAction">
<property name="tikaConfig">
<ref bean="tikaConfig"/>
</property>
</bean>
<bean id="compositeRenderingEngine"
class="org.alfresco.repo.rendition.executer.CompositeRenderingEngine"
parent="baseRenderingAction">

View File

@@ -9,9 +9,7 @@
{"name": "allowEnlargement", "value": true},
{"name": "maintainAspectRatio", "value": true},
{"name": "autoOrient", "value": true},
{"name": "thumbnail", "value": true},
{"name": "startPage", "value": "0"},
{"name": "endPage", "value": "0"}
{"name": "thumbnail", "value": true}
]
},
{
@@ -23,9 +21,7 @@
{"name": "allowEnlargement", "value": false},
{"name": "maintainAspectRatio", "value": true},
{"name": "autoOrient", "value": true},
{"name": "thumbnail", "value": true},
{"name": "startPage", "value": "0"},
{"name": "endPage", "value": "0"}
{"name": "thumbnail", "value": true}
]
},
{
@@ -37,9 +33,7 @@
{"name": "allowEnlargement", "value": false},
{"name": "maintainAspectRatio", "value": true},
{"name": "autoOrient", "value": true},
{"name": "thumbnail", "value": true},
{"name": "startPage", "value": "0"},
{"name": "endPage", "value": "0"}
{"name": "thumbnail", "value": true}
]
},
{
@@ -51,9 +45,7 @@
{"name": "allowEnlargement", "value": false},
{"name": "maintainAspectRatio", "value": true},
{"name": "autoOrient", "value": true},
{"name": "thumbnail", "value": true},
{"name": "startPage", "value": "0"},
{"name": "endPage", "value": "0"}
{"name": "thumbnail", "value": true}
]
},
{
@@ -65,9 +57,7 @@
{"name": "allowEnlargement", "value": false},
{"name": "maintainAspectRatio", "value": true},
{"name": "autoOrient", "value": true},
{"name": "thumbnail", "value": true},
{"name": "startPage", "value": "0"},
{"name": "endPage", "value": "0"}
{"name": "thumbnail", "value": true}
]
},
{

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
version.schema=14200
version.schema=14100
# Directory configuration
@@ -153,7 +153,6 @@ system.cache.parentAssocs.limitFactor=8
system.acl.maxPermissionCheckTimeMillis=10000
# The maximum number of search results to perform permission checks against
system.acl.maxPermissionChecks=1000
system.acl.maxPermissionCheckEnabled=false
# The maximum number of filefolder list results
system.filefolderservice.defaultListMaxResults=5000
@@ -221,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?
@@ -481,7 +482,7 @@ system.thumbnail.definition.default.timeoutMs=-1
system.thumbnail.definition.default.readLimitTimeMs=-1
system.thumbnail.definition.default.maxSourceSizeKBytes=-1
system.thumbnail.definition.default.readLimitKBytes=-1
system.thumbnail.definition.default.pageLimit=-1
system.thumbnail.definition.default.pageLimit=1
system.thumbnail.definition.default.maxPages=-1
# Max mimetype sizes to create thumbnail icons
@@ -1207,18 +1208,9 @@ 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
# Thread pool for async enqueue of repo events
repo.event2.queue.enqueueThreadPool.priority=1
repo.event2.queue.enqueueThreadPool.coreSize=8
repo.event2.queue.enqueueThreadPool.maximumSize=10
# Thread pool for async dequeue and delivery of repo events
repo.event2.queue.dequeueThreadPool.priority=1
repo.event2.queue.dequeueThreadPool.coreSize=1
repo.event2.queue.dequeueThreadPool.maximumSize=1
# MNT-21083
# --DELETE_NOT_EXISTS - default settings

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

@@ -126,9 +126,6 @@
<property name="maxPermissionCheckTimeMillis">
<value>${system.acl.maxPermissionCheckTimeMillis}</value>
</property>
<property name="maxPermissionCheckEnabled">
<value>${system.acl.maxPermissionCheckEnabled}</value>
</property>
</bean>
<bean id="search.dbQueryEngine" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -165,8 +165,6 @@
<property name="keyResourceLoader" ref="springKeyResourceLoader"/>
<property name="keyStoreParameters" ref="keyStoreParameters"/>
<property name="encryptionParameters" ref="md5EncryptionParameters"/>
<property name="sharedSecret" value="${solr.sharedSecret}"/>
<property name="sharedSecretHeader" value="${solr.sharedSecret.header}"/>
<property name="host" value="${solr.host}"/>
<property name="port" value="${solr.port}"/>
<property name="sslPort" value="${solr.port.ssl}"/>

View File

@@ -117,6 +117,31 @@
"imageMagickOptions"
]
},
{
"transformerName": "htmlToPdfViaOdt",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/vnd.oasis.opendocument.text"},
{"transformerName": "libreoffice"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/html", "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "htmlToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "htmlToPdfViaOdt", "targetMediaType": "application/pdf"},
{"transformerName": "pdfToImageViaPng"}
],
"supportedSourceAndTargetList": [
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
},
{
"transformerName": "ooXmlToImageViaText",
"transformerPipeline" : [
@@ -173,66 +198,42 @@
"archiveOptions"
]
},
{
"transformerName": "libreofficeHtmlToPdfViaOdt",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/vnd.oasis.opendocument.text"},
{"transformerName": "libreoffice"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/html", "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "libreofficeToPdf",
"transformerFailover" : [ "libreoffice", "libreofficeHtmlToPdfViaOdt" ],
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "text/tab-separated-values", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.visio2013", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/wordperfect", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.sun.xml.calc", "priority": 150, "targetMediaType": "application/pdf" },
{"sourceMediaType": "application/vnd.sun.xml.impress", "priority": 150, "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "libreofficeToPdfBoxViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "libreofficeToPdf", "targetMediaType": "application/pdf"},
{"transformerName": "PdfBox"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.oasis.opendocument.graphics", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.sun.xml.calc.template", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.sun.xml.impress.template", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.sun.xml.writer.template", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "text/tab-separated-values", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "text/tab-separated-values", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "text/tab-separated-values", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "text/tab-separated-values", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "text/tab-separated-values", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.visio2013", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.visio2013", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.visio2013", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.visio2013", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.visio2013", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/wordperfect", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/wordperfect", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/wordperfect", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/wordperfect", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/wordperfect", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.sun.xml.calc", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.sun.xml.calc", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.sun.xml.calc", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.sun.xml.calc", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.sun.xml.calc", "priority": 150, "targetMediaType": "text/xml"},
{"sourceMediaType": "application/vnd.sun.xml.impress", "priority": 150, "targetMediaType": "text/csv"},
{"sourceMediaType": "application/vnd.sun.xml.impress", "priority": 150, "targetMediaType": "text/html"},
{"sourceMediaType": "application/vnd.sun.xml.impress", "maxSourceSizeBytes": 26214400, "priority": 150, "targetMediaType": "text/plain"},
{"sourceMediaType": "application/vnd.sun.xml.impress", "priority": 150, "targetMediaType": "application/xhtml+xml"},
{"sourceMediaType": "application/vnd.sun.xml.impress", "priority": 150, "targetMediaType": "text/xml"}
],
"transformOptions": [
"pdfboxOptions"
@@ -262,32 +263,6 @@
"transformOptions": [
"tikaOptions"
]
},
{
"transformerName": "htmlToPdfViaTXT",
"transformerPipeline" : [
{"transformerName": "string", "targetMediaType": "text/plain"},
{"transformerName": "libreoffice"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/html", "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "htmlToImageViaTXT",
"transformerPipeline" : [
{"transformerName": "string", "targetMediaType": "text/plain"},
{"transformerName": "textToImageViaPdf"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/html", "targetMediaType": "image/png" }
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
}
]
}

View File

@@ -82,9 +82,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.node.db.DbNodeServiceImplTest.class,
org.alfresco.repo.node.cleanup.TransactionCleanupTest.class,
org.alfresco.repo.security.person.GetPeopleCannedQueryTest.class,
org.alfresco.repo.domain.schema.script.DeleteNotExistsExecutorTest.class
org.alfresco.repo.security.person.GetPeopleCannedQueryTest.class
})
public class AllDBTestsTestSuite
{

View File

@@ -111,15 +111,14 @@ import org.junit.runners.Suite;
org.alfresco.util.schemacomp.validator.SchemaVersionValidatorTest.class,
org.alfresco.util.schemacomp.validator.TypeNameOnlyValidatorTest.class,
org.alfresco.util.test.junitrules.TemporaryMockOverrideTest.class,
org.alfresco.repo.search.impl.solr.AbstractSolrQueryHTTPClientTest.class,
org.alfresco.repo.search.impl.solr.SpellCheckDecisionManagerTest.class,
org.alfresco.repo.search.impl.solr.SolrStoreMappingWrapperTest.class,
org.alfresco.repo.search.impl.solr.SolrQueryHTTPClientTest.class,
org.alfresco.repo.search.impl.solr.SolrSQLHttpClientTest.class,
org.alfresco.repo.search.impl.solr.SolrStatsResultTest.class,
org.alfresco.repo.search.impl.solr.facet.SolrFacetComparatorTest.class,
org.alfresco.repo.search.impl.solr.facet.FacetQNameUtilsTest.class,
org.alfresco.util.BeanExtenderUnitTest.class,
org.alfresco.repo.search.impl.solr.SpellCheckDecisionManagerTest.class,
org.alfresco.repo.search.impl.solr.SolrStoreMappingWrapperTest.class,
org.alfresco.repo.security.authentication.CompositePasswordEncoderTest.class,
org.alfresco.repo.security.authentication.PasswordHashingTest.class,
org.alfresco.traitextender.TraitExtenderIntegrationTest.class,
@@ -171,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

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -66,9 +66,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.content.RoutingContentStoreTest.class,
org.alfresco.encryption.EncryptionTests.class,
org.alfresco.encryption.KeyStoreTests.class,
org.alfresco.repo.content.MimetypeMapContentTest.class
org.alfresco.encryption.KeyStoreTests.class
// TODO REPO-2791 org.alfresco.repo.content.routing.StoreSelectorAspectContentStoreTest.class,
})

View File

@@ -56,6 +56,7 @@ import org.junit.runners.Suite;
// This test opens, closes and again opens the alfresco application context.
org.alfresco.repo.dictionary.CustomModelRepoRestartTest.class,
org.alfresco.repo.rendition.executer.HTMLRenderingEngineTest.class,
org.alfresco.repo.rendition.executer.XSLTFunctionsTest.class,
org.alfresco.repo.rendition.executer.XSLTRenderingEngineTest.class,
org.alfresco.repo.replication.ReplicationServiceIntegrationTest.class,

View File

@@ -75,6 +75,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.site.SiteServiceImplTest.class,
// [classpath:alfresco/application-context.xml, classpath:scriptexec/script-exec-test.xml]
org.alfresco.repo.domain.schema.script.DeleteNotExistsExecutorTest.class,
org.alfresco.repo.domain.schema.script.ScriptExecutorImplIntegrationTest.class,
org.alfresco.repo.domain.schema.script.ScriptBundleExecutorImplIntegrationTest.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

@@ -78,7 +78,6 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
@@ -108,13 +107,7 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.security.PersonService.PersonInfo;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionService;
@@ -128,6 +121,7 @@ import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.alfresco.util.testing.category.FrequentlyFailingTests;
import org.alfresco.util.testing.category.LuceneTests;
import org.alfresco.util.testing.category.PerformanceTests;
import org.alfresco.util.testing.category.RedundantTests;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Ace;
@@ -219,9 +213,6 @@ public class CMISTest
private SearchService searchService;
private java.util.Properties globalProperties;
private AuditComponentImpl auditComponent;
private PersonService personService;
private SiteService siteService;
private MutableAuthenticationService authenticationService;
private AlfrescoCmisServiceFactory factory;
@@ -347,9 +338,6 @@ public class CMISTest
this.tenantService = (TenantService) ctx.getBean("tenantService");
this.searchService = (SearchService) ctx.getBean("SearchService");
this.auditComponent = (AuditComponentImpl) ctx.getBean("auditComponent");
this.personService = (PersonService) ctx.getBean("personService");
this.siteService = (SiteService) ctx.getBean("siteService");
this.authenticationService = (MutableAuthenticationService) ctx.getBean("AuthenticationService");
this.globalProperties = (java.util.Properties) ctx.getBean("global-properties");
this.globalProperties.setProperty(VersionableAspectTest.AUTO_VERSION_PROPS_KEY, "true");
@@ -731,17 +719,12 @@ public class CMISTest
}
private <T extends Object> T withCmisService(CmisServiceCallback<T> callback, CmisVersion cmisVersion)
{
return withCmisService("admin", "admin", callback, cmisVersion);
}
private <T extends Object> T withCmisService(String username, String password, CmisServiceCallback<T> callback, CmisVersion cmisVersion)
{
CmisService cmisService = null;
try
{
CallContext context = new SimpleCallContext(username, password, cmisVersion);
CallContext context = new SimpleCallContext("admin", "admin", cmisVersion);
cmisService = factory.getService(context);
T ret = callback.execute(cmisService);
return ret;
@@ -4118,108 +4101,6 @@ public class CMISTest
}
}
/**
* This test ensures that a non member user of a private site, can edit metadata on a document (where the non member user
* has "SiteCollaborator" role) placed on the site.
*
* @throws Exception
*/
@Test
public void testMNT20006() throws Exception
{
AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
final String nonMemberUsername = "user" + System.currentTimeMillis();
final String nonMemberPassword = "pass" + System.currentTimeMillis();
final String siteId = "site" + System.currentTimeMillis();
final String originalDescription = "my description";
NodeRef fileNode;
try
{
fileNode = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
// Create user
authenticationService.createAuthentication(nonMemberUsername, nonMemberPassword.toCharArray());
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
String email = nonMemberUsername + "@testcmis.com";
props.put(ContentModel.PROP_USERNAME, nonMemberUsername);
props.put(ContentModel.PROP_FIRSTNAME, nonMemberUsername);
props.put(ContentModel.PROP_LASTNAME, nonMemberUsername);
props.put(ContentModel.PROP_EMAIL, email);
PersonInfo personInfo = personService.getPerson(personService.createPerson(props));
assertNotNull("Null person info", personInfo);
// Create site
SiteInfo siteInfo = siteService.createSite("myPreset", siteId, "myTitle", "myDescription", SiteVisibility.PRIVATE);
assertNotNull("Null site info", siteInfo);
NodeRef siteDocLib = siteService.createContainer(siteId, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null);
assertNotNull("Null site doclib", siteDocLib);
// Create node in site
String nodeName = "node" + System.currentTimeMillis() + ".txt";
NodeRef fileNode = nodeService.createNode(siteDocLib, ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS, ContentModel.TYPE_CONTENT).getChildRef();
ContentWriter writer = contentService.getWriter(fileNode, ContentModel.PROP_CONTENT, true);
writer.putContent("my node content");
nodeService.setProperty(fileNode, ContentModel.PROP_TITLE, nodeName);
nodeService.setProperty(fileNode, ContentModel.PROP_DESCRIPTION, originalDescription);
assertNotNull("Null file node", fileNode);
assertTrue(nodeService.exists(fileNode));
// Sets node permissions to the user who is not member of the site and get site activities
permissionService.setPermission(fileNode, nonMemberUsername, SiteModel.SITE_COLLABORATOR, true);
return fileNode;
}
});
}
finally
{
AuthenticationUtil.popAuthentication();
}
// Edit metadata
final String newDescription = "new node description";
Boolean updated = withCmisService(nonMemberUsername, nonMemberPassword, new CmisServiceCallback<Boolean>()
{
@Override
public Boolean execute(CmisService cmisService)
{
Boolean updated = true;
try
{
// Obtain repository id
List<RepositoryInfo> repositories = cmisService.getRepositoryInfos(null);
assertTrue(repositories.size() > 0);
RepositoryInfo repo = repositories.get(0);
String repositoryId = repo.getId();
// Id holder
Holder<String> objectIdHolder = new Holder<String>(fileNode.toString());
// New Properties
PropertiesImpl newProperties = new PropertiesImpl();
newProperties.addProperty(new PropertyStringImpl(PropertyIds.DESCRIPTION, newDescription));
cmisService.updateProperties(repositoryId, objectIdHolder, null, newProperties, null);
}
catch (Exception e)
{
updated = false;
}
return updated;
};
}, CmisVersion.CMIS_1_1);
assertTrue("Document metadata not updated", updated);
}
private NodeRef createFolder(NodeRef parentNodeRef, String folderName, QName folderType) throws IOException
{
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* 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
@@ -36,7 +36,7 @@ import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.DataModelTestApplicationContextHelper;
import org.apache.poi.util.IOUtils;
import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext;
@@ -47,10 +47,10 @@ import org.springframework.context.ApplicationContext;
* @see org.alfresco.repo.content.MimetypeMap
* @see org.alfresco.repo.content.MimetypeMapTest
*/
@Category({OwnJVMTestsCategory.class})
@Category(OwnJVMTestsCategory.class)
public class MimetypeMapContentTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private static ApplicationContext ctx = DataModelTestApplicationContextHelper.getApplicationContext();
private MimetypeService mimetypeService;
@@ -60,18 +60,6 @@ public class MimetypeMapContentTest extends TestCase
mimetypeService = (MimetypeService)ctx.getBean("mimetypeService");
}
public void testGuessPdfMimetype() throws Exception
{
assertEquals(
"application/pdf",
mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.pdf"))
);
assertEquals(
"application/pdf",
mimetypeService.guessMimetype(null, openQuickTestFile("quick.pdf"))
);
}
public void testGuessMimetypeForFile() throws Exception
{
// Correct ones
@@ -89,6 +77,10 @@ public class MimetypeMapContentTest extends TestCase
"application/msword",
mimetypeService.guessMimetype("something.pdf", openQuickTestFile("quick.doc"))
);
assertEquals(
"application/pdf",
mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.pdf"))
);
// Ones where we use a different mimetype to the canonical one
assertEquals(
@@ -102,14 +94,12 @@ public class MimetypeMapContentTest extends TestCase
mimetypeService.guessMimetype("concept.dita", openQuickTestFile("quickConcept.dita"))
);
// Commented out when the test class was reintroduced after many years of not being run. Failed as the type was
// identified as a zip. Reintroduced to check guessMimetype works without pdfbox libraries.
//
// // Alfresco Specific ones, that Tika doesn't know about
// assertEquals(
// "application/acp",
// mimetypeService.guessMimetype("something.acp", openQuickTestFile("quick.acp"))
// );
// Alfresco Specific ones, that Tika doesn't know about
assertEquals(
"application/acp",
mimetypeService.guessMimetype("something.acp", openQuickTestFile("quick.acp"))
);
// Where the file is corrupted
File tmp = File.createTempFile("alfresco", ".tmp");
@@ -130,15 +120,12 @@ public class MimetypeMapContentTest extends TestCase
"application/x-tika-msoffice",
mimetypeService.guessMimetype(null, truncReader)
);
// Commented out when the test class was reintroduced after many years of not being run. Failed to open a
// stream onto the channel. Reintroduced to check guessMimetype works without pdfbox libraries.
//
// // But with the filename it'll be able to use the .doc extension
// // to guess at it being a .Doc file
// assertEquals(
// "application/msword",
// mimetypeService.guessMimetype("something.doc", truncReader)
// );
// But with the filename it'll be able to use the .doc extension
// to guess at it being a .Doc file
assertEquals(
"application/msword",
mimetypeService.guessMimetype("something.doc", truncReader)
);
// Lotus notes EML files (ALF-16381 / TIKA-1042)
assertEquals(

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

@@ -35,14 +35,10 @@ import java.util.Properties;
import javax.sql.DataSource;
import org.alfresco.repo.domain.dialect.Dialect;
import org.alfresco.repo.domain.dialect.MySQLInnoDBDialect;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.testing.category.DBTests;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mockito;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -52,13 +48,11 @@ import org.springframework.jdbc.core.JdbcTemplate;
*
* @author Cristian Turlica
*/
@Category({DBTests.class})
public class DeleteNotExistsExecutorTest
{
private static ApplicationContext ctx;
private ScriptExecutor scriptExecutor;
private DataSource dataSource;
private Dialect dialect;
private JdbcTemplate jdbcTmpl;
@BeforeClass
@@ -73,20 +67,9 @@ public class DeleteNotExistsExecutorTest
{
scriptExecutor = ctx.getBean("simpleScriptExecutor", ScriptExecutorImpl.class);
dataSource = ctx.getBean("dataSource", DataSource.class);
dialect = ctx.getBean("dialect", Dialect.class);
jdbcTmpl = new JdbcTemplate(dataSource);
}
private DeleteNotExistsExecutor createDeleteNotExistsExecutor(Connection connection, String sql, int line, File scriptFile, Properties properties)
{
if (dialect instanceof MySQLInnoDBDialect)
{
return new MySQLDeleteNotExistsExecutor(connection, sql, line, scriptFile, properties, dataSource);
}
return new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
}
@Test()
public void testDefaultBehaviour() throws Exception
{
@@ -107,7 +90,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("true");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = createDeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -117,7 +100,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = createDeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -150,7 +133,7 @@ public class DeleteNotExistsExecutorTest
{
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_DELETE_BATCH_SIZE)).thenReturn("1");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
DeleteNotExistsExecutor deleteNotExistsExecutor = createDeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);
@@ -184,7 +167,7 @@ public class DeleteNotExistsExecutorTest
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_BATCH_SIZE)).thenReturn("2");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_READ_ONLY)).thenReturn("false");
when(properties.getProperty(DeleteNotExistsExecutor.PROPERTY_TIMEOUT_SECONDS)).thenReturn("-1");
DeleteNotExistsExecutor deleteNotExistsExecutor = createDeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
DeleteNotExistsExecutor deleteNotExistsExecutor = new DeleteNotExistsExecutor(connection, sql, line, scriptFile, properties);
deleteNotExistsExecutor.execute();
List<String> res = jdbcTmpl.queryForList(select, String.class);

View File

@@ -30,7 +30,6 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.jms.ConnectionFactory;
@@ -78,14 +77,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
{
protected static final boolean DEBUG = false;
protected static final String TEST_NAMESPACE = "http://www.alfresco.org/test/ContextAwareRepoEvent";
protected static final RepoEventContainer EVENT_CONTAINER = new RepoEventContainer();
private static final String BROKER_URL = "tcp://localhost:61616";
private static final String TOPIC_NAME = "alfresco.repo.event2";
private static final String CAMEL_ROUTE = "jms:topic:" + TOPIC_NAME;
private static final RepoEventContainer EVENT_CONTAINER = new RepoEventContainer();
private static final CamelContext CAMEL_CONTEXT = new DefaultCamelContext();
private static boolean isCamelConfigured;
@@ -107,13 +104,6 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
@Autowired
protected ObjectMapper event2ObjectMapper;
@Autowired @Qualifier("eventGeneratorV2")
protected EventGenerator eventGenerator;
@Autowired
@Qualifier("eventGeneratorQueue")
protected EventGeneratorQueue eventQueue;
protected NodeRef rootNodeRef;
@BeforeClass
@@ -151,33 +141,6 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
}
return nodeService.getRootNode(storeRef);
});
flushSpuriousEvents();
}
/*
* When running with an empty database some events related to the creation may
* creep up here making the test fails. After attempting several other
* strategies, a smart sleep seems to do the work.
*/
protected void flushSpuriousEvents() throws InterruptedException
{
int maxloops = 5;
int count = maxloops;
do
{
Thread.sleep(165l);
if (EVENT_CONTAINER.isEmpty())
{
count--;
} else
{
EVENT_CONTAINER.reset();
count = maxloops;
}
} while (count > 0);
}
@After
@@ -216,16 +179,6 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
propertyMap).getChildRef());
}
protected NodeRef updateNodeName(NodeRef nodeRef, String newName)
{
PropertyMap propertyMap = new PropertyMap();
propertyMap.put(ContentModel.PROP_NAME, newName);
return retryingTransactionHelper.doInTransaction(() -> {
nodeService.addProperties(nodeRef, propertyMap);
return null;
});
}
protected void deleteNode(NodeRef nodeRef)
{
retryingTransactionHelper.doInTransaction(() -> {
@@ -423,18 +376,13 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
public static class RepoEventContainer implements Processor
{
private final List<RepoEvent<?>> events = Collections.synchronizedList(new ArrayList<>());
private final List<RepoEvent<?>> events = new ArrayList<>();
@Override
public void process(Exchange exchange)
{
Object object = exchange.getIn().getBody();
events.add((RepoEvent<?>) object);
if (DEBUG)
{
System.err.println("XX: "+object);
}
}
public List<RepoEvent<?>> getEvents()
@@ -456,12 +404,6 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
{
events.clear();
}
public boolean isEmpty()
{
return events.isEmpty();
}
}
@SuppressWarnings("unchecked")

View File

@@ -1,290 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 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.event2;
import static java.lang.Thread.sleep;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.alfresco.repo.event.v1.model.RepoEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class EventGeneratorQueueUnitTest
{
private EventGeneratorQueue queue;
private Event2MessageProducer bus;
private ExecutorService enqueuePool;
private ExecutorService dequeuePool;
private List<RepoEvent<?>> recordedEvents;
private Map<String, RepoEvent<?>> events;
@Before
public void setup()
{
queue = new EventGeneratorQueue();
enqueuePool = newThreadPool();
queue.setEnqueueThreadPoolExecutor(enqueuePool);
dequeuePool = newThreadPool();
queue.setDequeueThreadPoolExecutor(dequeuePool);
bus = mock(Event2MessageProducer.class);
queue.setEvent2MessageProducer(bus);
events = new HashMap<>();
setupEventsRecorder();
}
@After
public void teardown()
{
enqueuePool.shutdown();
}
private void setupEventsRecorder()
{
recordedEvents = new CopyOnWriteArrayList<>();
Mockito.doAnswer(new Answer<Void>()
{
@Override
public Void answer(InvocationOnMock invocation) throws Throwable
{
RepoEvent<?> event = invocation.getArgument(0, RepoEvent.class);
recordedEvents.add(event);
return null;
}
}).when(bus).send(any());
}
@Test
public void shouldReceiveSingleQuickMessage() throws Exception
{
queue.accept(messageWithDelay("A", 55l));
sleep(150l);
assertEquals(1, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
}
@Test
public void shouldNotReceiveEventsWhenMessageIsNull() throws Exception
{
queue.accept(() -> { return null; });
sleep(150l);
assertEquals(0, recordedEvents.size());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderScenarioOne() throws Exception {
queue.accept(messageWithDelay("A", 0l));
queue.accept(messageWithDelay("B", 100l));
queue.accept(messageWithDelay("C", 200l));
sleep(450l);
assertEquals(3, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("B", recordedEvents.get(1).getId());
assertEquals("C", recordedEvents.get(2).getId());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderScenarioTwo() throws Exception
{
queue.accept(messageWithDelay("A", 300l));
queue.accept(messageWithDelay("B", 150l));
queue.accept(messageWithDelay("C", 0l));
sleep(950l);
assertEquals(3, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("B", recordedEvents.get(1).getId());
assertEquals("C", recordedEvents.get(2).getId());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderEvenWhenMakerPoisoned() throws Exception
{
queue.accept(messageWithDelay("A", 300l));
queue.accept(() -> {throw new RuntimeException("Boom! (not to worry, this is a test)");});
queue.accept(messageWithDelay("B", 55l));
queue.accept(messageWithDelay("C", 0l));
sleep(950l);
assertEquals(3, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("B", recordedEvents.get(1).getId());
assertEquals("C", recordedEvents.get(2).getId());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderEvenWhenSenderPoisoned() throws Exception
{
Callable<RepoEvent<?>> makerB = messageWithDelay("B", 55l);
RepoEvent<?> messageB = makerB.call();
doThrow(new RuntimeException("Boom! (not to worry, this is a test)")).when(bus).send(messageB);
queue.accept(messageWithDelay("A", 300l));
queue.accept(makerB);
queue.accept(messageWithDelay("C", 0l));
sleep(950l);
assertEquals(2, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("C", recordedEvents.get(1).getId());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderEvenWhenMakerPoisonedWithError() throws Exception
{
queue.accept(messageWithDelay("A", 300l));
queue.accept(() -> {throw new OutOfMemoryError("Boom! (not to worry, this is a test)");});
queue.accept(messageWithDelay("B", 55l));
queue.accept(messageWithDelay("C", 0l));
sleep(950l);
assertEquals(3, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("B", recordedEvents.get(1).getId());
assertEquals("C", recordedEvents.get(2).getId());
}
@Test
public void shouldReceiveMultipleMessagesPreservingOrderEvenWhenSenderPoisonedWithError() throws Exception
{
Callable<RepoEvent<?>> makerB = messageWithDelay("B", 55l);
RepoEvent<?> messageB = makerB.call();
doThrow(new OutOfMemoryError("Boom! (not to worry, this is a test)")).when(bus).send(messageB);
queue.accept(messageWithDelay("A", 300l));
queue.accept(makerB);
queue.accept(messageWithDelay("C", 0l));
sleep(950l);
assertEquals(2, recordedEvents.size());
assertEquals("A", recordedEvents.get(0).getId());
assertEquals("C", recordedEvents.get(1).getId());
}
private Callable<RepoEvent<?>> messageWithDelay(String id, long delay)
{
Callable<RepoEvent<?>> res = new Callable<RepoEvent<?>>() {
@Override
public RepoEvent<?> call() throws Exception
{
if(delay != 0)
{
sleep(delay);
}
return newRepoEvent(id);
}
@Override
public String toString()
{
return id;
}
};
return res;
}
private RepoEvent<?> newRepoEvent(String id)
{
RepoEvent<?> ev = events.get(id);
if (ev!=null)
return ev;
ev = mock(RepoEvent.class);
when(ev.getId()).thenReturn(id);
when(ev.toString()).thenReturn(id);
events.put(id, ev);
return ev;
}
public static ExecutorService newThreadPool()
{
return new ThreadPoolExecutor(2, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static final Executor SYNC_EXECUTOR_SAME_THREAD = new Executor()
{
@Override
public void execute(Runnable command)
{
command.run();
}
};
public static final Executor SYNC_EXECUTOR_NEW_THREAD = new Executor()
{
@Override
public void execute(Runnable command)
{
Thread t = new Thread(command);
t.start();
try
{
t.join();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
};
}

View File

@@ -1,249 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2020 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.event2;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.event.databind.ObjectMapperFactory;
import org.alfresco.repo.event.v1.model.RepoEvent;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.advisory.DestinationSource;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.apache.activemq.command.ActiveMQTopic;
import org.awaitility.Awaitility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.fasterxml.jackson.databind.ObjectMapper;
public class EventGeneratorTest extends AbstractContextAwareRepoEvent
{
private static final String EVENT2_TOPIC_NAME = "alfresco.repo.event2";
private static final long DUMP_BROKER_TIMEOUT = 50000000l;
@Autowired @Qualifier("event2ObjectMapper")
private ObjectMapper objectMapper;
private ActiveMQConnection connection;
protected List<RepoEvent<?>> receivedEvents;
@Before
public void startupTopicListener() throws Exception
{
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = (ActiveMQConnection) connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createTopic(EVENT2_TOPIC_NAME);
MessageConsumer consumer = session.createConsumer(destination);
receivedEvents = Collections.synchronizedList(new LinkedList<>());
consumer.setMessageListener(new MessageListener()
{
@Override
public void onMessage(Message message)
{
String text = getText(message);
RepoEvent<?> event = toRepoEvent(text);
if (DEBUG)
{
System.err.println("RX: " + event);
}
receivedEvents.add(event);
}
private RepoEvent<?> toRepoEvent(String json)
{
try
{
return objectMapper.readValue(json, RepoEvent.class);
} catch (Exception e)
{
e.printStackTrace();
return null;
}
}
});
if (DEBUG)
{
System.err.println("Now actively listening on topic " + EVENT2_TOPIC_NAME);
}
}
protected ObjectMapper createObjectMapper()
{
return ObjectMapperFactory.createInstance();
}
@After
public void shutdownTopicListener() throws Exception
{
connection.close();
connection = null;
}
@Test
public void shouldReceiveEvent2EventsOnNodeCreation() throws Exception
{
createNode(ContentModel.TYPE_CONTENT);
Awaitility.await().atMost(6, TimeUnit.SECONDS).until(() -> receivedEvents.size() == 1);
RepoEvent<?> sent = getRepoEvent(1);
RepoEvent<?> received = receivedEvents.get(0);
assertEventsEquals("Events are different!", sent, received);
}
private void assertEventsEquals(String message, RepoEvent<?> expected, RepoEvent<?> current)
{
if (DEBUG)
{
System.err.println("XP: " + expected);
System.err.println("CU: " + current);
}
assertEquals(message, expected, current);
}
@Test
public void shouldReceiveEvent2EventsInOrder() throws Exception
{
NodeRef nodeRef = createNode(ContentModel.TYPE_CONTENT);
updateNodeName(nodeRef, "TestFile-" + System.currentTimeMillis() + ".txt");
deleteNode(nodeRef);
Awaitility.await().atMost(6, TimeUnit.SECONDS).until(() -> receivedEvents.size() == 3);
RepoEvent<?> sentCreation = getRepoEvent(1);
RepoEvent<?> sentUpdate = getRepoEvent(2);
RepoEvent<?> sentDeletion = getRepoEvent(3);
assertEquals("Expected create event!", sentCreation, (RepoEvent<?>) receivedEvents.get(0));
assertEquals("Expected update event!", sentUpdate, (RepoEvent<?>) receivedEvents.get(1));
assertEquals("Expected delete event!", sentDeletion, (RepoEvent<?>) receivedEvents.get(2));
}
private static String getText(Message message)
{
try
{
ActiveMQTextMessage am = (ActiveMQTextMessage) message;
return am.getText();
} catch (JMSException e)
{
return null;
}
}
// a simple main to investigate the contents of the local broker
public static void main(String[] args) throws Exception
{
dumpBroker("tcp://localhost:61616", DUMP_BROKER_TIMEOUT);
System.exit(0);
}
private static void dumpBroker(String url, long timeout) throws Exception
{
System.out.println("Broker at url: '" + url + "'");
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection();
try
{
connection.start();
DestinationSource ds = connection.getDestinationSource();
Set<ActiveMQQueue> queues = ds.getQueues();
System.out.println("\nFound " + queues.size() + " queues:");
for (ActiveMQQueue queue : queues)
{
try
{
System.out.println("- " + queue.getQueueName());
} catch (JMSException e)
{
e.printStackTrace();
}
}
Set<ActiveMQTopic> topics = ds.getTopics();
System.out.println("\nFound " + topics.size() + " topics:");
for (ActiveMQTopic topic : topics)
{
try
{
System.out.println("- " + topic.getTopicName());
} catch (JMSException e)
{
e.printStackTrace();
}
}
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createTopic(EVENT2_TOPIC_NAME);
MessageConsumer consumer = session.createConsumer(destination);
System.out.println("\nListening to topic " + EVENT2_TOPIC_NAME + "...");
consumer.setMessageListener(new MessageListener()
{
@Override
public void onMessage(Message message)
{
String text = getText(message);
System.out.println("Received message " + message + "\n" + text + "\n");
}
});
Thread.sleep(timeout);
} finally
{
connection.close();
}
}
}

View File

@@ -34,8 +34,7 @@ import org.junit.runners.Suite.SuiteClasses;
UpdateRepoEventIT.class,
DeleteRepoEventIT.class,
ChildAssociationRepoEventIT.class,
PeerAssociationRepoEventIT.class,
EventGeneratorTest.class
PeerAssociationRepoEventIT.class
})
public class RepoEvent2ITSuite
{

View File

@@ -33,8 +33,7 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ EventFilterUnitTest.class,
EventConsolidatorUnitTest.class,
EventJSONSchemaUnitTest.class,
EventGeneratorQueueUnitTest.class
EventJSONSchemaUnitTest.class
})
public class RepoEvent2UnitSuite
{

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

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* 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
@@ -25,6 +25,7 @@
*/
package org.alfresco.repo.rendition;
import org.alfresco.repo.rendition.executer.HTMLRenderingEngineTest;
import org.alfresco.repo.thumbnail.ThumbnailServiceImplParameterTest;
import org.alfresco.repo.thumbnail.ThumbnailServiceImplTest;
import org.alfresco.repo.thumbnail.conditions.NodeEligibleForRethumbnailingEvaluatorTest;
@@ -48,6 +49,7 @@ import org.junit.runners.Suite;
RenditionServiceIntegrationTest.class,
RenditionServicePermissionsTest.class,
RenditionNodeManagerTest.class,
HTMLRenderingEngineTest.class,
MultiUserRenditionTest.class
})
public class AllRenditionTests

View File

@@ -0,0 +1,543 @@
/*
* #%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.rendition.executer;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.rendition.RenditionDefinitionPersisterImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.test_category.BaseSpringTestsCategory;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.BaseAlfrescoSpringTest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.transaction.annotation.Transactional;
/**
* Unit tests for the HTML Rendering Engine
*
* @author Nick Burch
*
* @deprecated We are introducing the new async RenditionService2.
*/
@Deprecated
@Category(BaseSpringTestsCategory.class)
@Transactional
public class HTMLRenderingEngineTest extends BaseAlfrescoSpringTest
{
private final static Log log = LogFactory.getLog(HTMLRenderingEngineTest.class);
private NodeRef companyHome;
private DictionaryService dictionaryService;
private RenditionService renditionService;
private Repository repositoryHelper;
private NodeRef sourceDoc;
private NodeRef targetFolder;
private String targetFolderPath;
private RenditionDefinition def;
private static final String MIMETYPE_DOC = "application/msword";
private static final String MIMETYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
@Before
public void before() throws Exception
{
super.before();
this.nodeService = (NodeService) this.applicationContext.getBean("NodeService");
this.contentService = (ContentService) this.applicationContext.getBean("ContentService");
this.renditionService = (RenditionService) this.applicationContext.getBean("RenditionService");
this.repositoryHelper = (Repository) this.applicationContext.getBean("repositoryHelper");
this.dictionaryService = (DictionaryService) this.applicationContext.getBean("dictionaryService");
this.companyHome = repositoryHelper.getCompanyHome();
createTargetFolder();
// Setup the basic rendition definition
QName renditionName = QName.createQName("Test");
RenditionDefinition rd = renditionService.loadRenditionDefinition(renditionName);
if(rd != null)
{
RenditionDefinitionPersisterImpl rdp = new RenditionDefinitionPersisterImpl();
rdp.setNodeService(nodeService);
rdp.deleteRenditionDefinition(rd);
}
def = renditionService.createRenditionDefinition(renditionName, HTMLRenderingEngine.NAME);
}
@After
public void after() throws Exception
{
super.after();
tidyUpSourceDoc();
}
private void createTargetFolder()
{
// Set the current security context as admin
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
properties.put(ContentModel.PROP_NAME, "TestFolder");
targetFolder = nodeService.createNode(
companyHome, ContentModel.ASSOC_CONTAINS,
QName.createQName("TestFolder"),
ContentModel.TYPE_FOLDER,
properties
).getChildRef();
targetFolderPath = "/" +
(String) nodeService.getProperty(companyHome, ContentModel.PROP_NAME) +
"/" +
(String) nodeService.getProperty(targetFolder, ContentModel.PROP_NAME)
;
}
private void tidyUpSourceDoc()
{
// Set the current security context as admin
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
// Clean up the source
if(sourceDoc != null)
{
nodeService.deleteNode(sourceDoc);
}
// Clean up the target folder
nodeService.deleteNode(targetFolder);
targetFolder = null;
// All done
sourceDoc = null;
createTargetFolder();
}
private NodeRef createForDoc(String docname) throws IOException
{
// Create the node
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
properties.put(ContentModel.PROP_NAME, docname);
NodeRef node = nodeService.createNode(
companyHome, ContentModel.ASSOC_CONTAINS,
QName.createQName(docname),
ContentModel.TYPE_CONTENT,
properties
).getChildRef();
// Put the sample doc into it
File f = AbstractContentTransformerTest.loadNamedQuickTestFile(docname);
if(f == null) {
fail("Unable to find test file for " + docname);
}
ContentWriter writer = contentService.getWriter(
node, ContentModel.PROP_CONTENT, true
);
if(docname.endsWith(".doc")) {
writer.setMimetype(MIMETYPE_DOC);
}
if(docname.endsWith(".docx")) {
writer.setMimetype(MIMETYPE_DOCX);
}
writer.putContent(f);
if (log.isDebugEnabled())
{
log.debug("Created document with name: " + docname + ", nodeRef: " + node + ", mimetype: " + writer.getMimetype());
}
// All done
return node;
}
@Test
public void testBasics() throws Exception
{
def.setParameterValue(
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
targetFolderPath + "/${name}.html"
);
sourceDoc = createForDoc("quick.doc");
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
assertNotNull(rendition);
// Check it was created
NodeRef htmlNode = rendition.getChildRef();
assertEquals(true, nodeService.exists(htmlNode));
// Check it got the right name
assertEquals(
"quick.html",
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
);
// Check it got the right contents
ContentReader reader = contentService.getReader(
htmlNode, ContentModel.PROP_CONTENT
);
String html = reader.getContentString();
assertEquals("<?xml", html.substring(0, 5));
assertTrue("HTML wrong:\n"+html, html.contains("<html"));
assertTrue("HTML wrong:\n"+html, html.contains("<head>"));
assertTrue("HTML wrong:\n"+html, html.contains("<body>"));
assertTrue("HTML wrong:\n"+html, html.contains("<p>The quick brown fox"));
// Now do a body-only one, check that we still got the
// contents, but not the html surround
def.setParameterValue(
HTMLRenderingEngine.PARAM_BODY_CONTENTS_ONLY, Boolean.TRUE
);
rendition = renditionService.render(sourceDoc, def);
assertNotNull(rendition);
htmlNode = rendition.getChildRef();
assertEquals(true, nodeService.exists(htmlNode));
reader = contentService.getReader(
htmlNode, ContentModel.PROP_CONTENT
);
html = reader.getContentString();
assertFalse("Body wrong:\n"+html, html.contains("<?xml"));
assertFalse("Body wrong:\n"+html, html.contains("<html"));
assertFalse("Body wrong:\n"+html, html.contains("<head>"));
assertFalse("Body wrong:\n"+html, html.contains("<body>"));
assertTrue("HTML wrong:\n"+html, html.contains("<p>The quick brown fox"));
assertTrue("HTML wrong:\n"+html, html.contains("</p>"));
}
/**
* Test for a .doc and a .docx, neither of which have images
*/
@Test
public void testDocWithoutImages() throws Exception
{
def.setParameterValue(
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
targetFolderPath + "/${name}.html"
);
for(String name : new String[] {"quick.doc","quick.docx"})
{
sourceDoc = createForDoc(name);
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
assertNotNull(rendition);
// Check it was created
NodeRef htmlNode = rendition.getChildRef();
assertEquals(true, nodeService.exists(htmlNode));
// Check it got the right name
assertEquals(
name.substring(0, name.lastIndexOf('.')) + ".html",
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
);
// Check it ended up in the right place
assertEquals(
"Should have been in " + targetFolderPath + " but was in" +
nodeService.getPath(htmlNode),
targetFolder,
nodeService.getPrimaryParent(htmlNode).getParentRef()
);
// Check it got the right contents
ContentReader reader = contentService.getReader(
htmlNode, ContentModel.PROP_CONTENT
);
String html = reader.getContentString();
assertEquals("<?xml", html.substring(0, 5));
// Check we didn't get an image folder, only the html
int numItems = nodeService.getChildAssocs(targetFolder).size();
assertEquals(numItemsStart+1, numItems);
// Check that the html lacks img tags
assertEquals(
"Unexpected img tag in html:\n" + html,
false, html.contains("<img")
);
// Check we didn't get any images
for(ChildAssociationRef ref : nodeService.getChildAssocs(htmlNode))
{
// TODO Check against composite content associations when present
// if(ref.getTypeQName().equals(HTMLRenderingEngine.PRIMARY_IMAGE))
// fail("Found unexpected primary image of rendered html");
// if(ref.getTypeQName().equals(HTMLRenderingEngine.SECONDARY_IMAGE))
// fail("Found unexpected secondary image of rendered html");
}
// All done
tidyUpSourceDoc();
}
}
/**
* Test for a .doc and a .docx, both of which have
* images in them
*/
@Test
public void testDocWithImages() throws Exception
{
def.setParameterValue(
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
targetFolderPath + "/${name}.html"
);
String[] files = new String[] {"quickImg1.doc","quickImg1.docx", "quickImg3.doc","quickImg3.docx"};
int[] imgCounts = new int[] {1,1, 3,3};
for(int i=0; i<files.length; i++)
{
String name = files[i];
sourceDoc = createForDoc(name);
String baseName = name.substring(0, name.lastIndexOf('.'));
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
assertNotNull(rendition);
// Check it was created
NodeRef htmlNode = rendition.getChildRef();
assertEquals(true, nodeService.exists(htmlNode));
// Check it got the right name
assertEquals(
baseName + ".html",
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
);
// Check it ended up in the right place
assertEquals(
"Should have been in " + targetFolderPath + " but was in" +
nodeService.getPath(htmlNode),
targetFolder,
nodeService.getPrimaryParent(htmlNode).getParentRef()
);
// Check it got the right contents
ContentReader reader = contentService.getReader(
htmlNode, ContentModel.PROP_CONTENT
);
String html = reader.getContentString();
assertEquals("<?xml", html.substring(0, 5));
// Check that the html has the img tags
assertEquals(
"Couldn't find img tag in html:\n" + html,
true, html.contains("<img")
);
// Check that it has the right img src
String expSource = "src=\""+ baseName + "_files" + "/image";
assertEquals(
"Couldn't find correct img src in html:\n" + expSource + "\n" + html,
true, html.contains(expSource)
);
// Check we got an image folder
int numItems = nodeService.getChildAssocs(targetFolder).size();
assertEquals(numItemsStart+2, numItems);
// Check the name of the image folder
NodeRef imgFolder = null;
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
if(nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME).equals(
baseName + "_files"
)) {
imgFolder = ref.getChildRef();
}
}
assertNotNull("Couldn't find new folder named " + baseName + "_files", imgFolder);
// Check the contents
assertEquals(imgCounts[i], nodeService.getChildAssocs(imgFolder).size());
// TODO Check against composite content associations when present
// Check the associations if supported
// if(dictionaryService.getAssociation(HTMLRenderingEngine.PRIMARY_IMAGE) != null)
// {
// boolean hasPrimary = false;
// boolean hasSecondary = false;
// for(ChildAssociationRef ref : nodeService.getChildAssocs(htmlNode))
// {
// if(ref.getTypeQName().equals(HTMLRenderingEngine.PRIMARY_IMAGE))
// hasPrimary = true;
// if(ref.getTypeQName().equals(HTMLRenderingEngine.SECONDARY_IMAGE))
// hasSecondary = true;
// }
// assertEquals(true, hasPrimary);
// assertEquals(false, hasSecondary);
// }
// All done
tidyUpSourceDoc();
}
}
/**
* Test for the option to have the images written to the
* same folder as the html, with a name prefix to them.
*
* TODO Re-enable when we've figured out why the rendition service sulkts
*/
@Test
public void testImagesSameFolder() throws Exception
{
def.setParameterValue(
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
targetFolderPath + "/${name}.html"
);
def.setParameterValue(
HTMLRenderingEngine.PARAM_IMAGES_SAME_FOLDER,
true
);
// The documents listed below have 3 embedded images each.
final int expectedImageCount = 3;
for(String name : new String[] {"quickImg3.doc","quickImg3.docx"})
{
sourceDoc = createForDoc(name);
String baseName = name.substring(0, name.lastIndexOf('.'));
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
if (log.isDebugEnabled())
{
log.debug("targetFolder " + targetFolder + " has " + numItemsStart + " children at start.");
}
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
assertNotNull(rendition);
// Check it was created
NodeRef htmlNode = rendition.getChildRef();
assertEquals(true, nodeService.exists(htmlNode));
// Check it got the right name
assertEquals(
baseName + ".html",
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
);
// Check it ended up in the right place
assertEquals(
"Should have been in " + targetFolderPath + " but was in" +
nodeService.getPath(htmlNode),
targetFolder,
nodeService.getPrimaryParent(htmlNode).getParentRef()
);
// Check it got the right contents
ContentReader reader = contentService.getReader(
htmlNode, ContentModel.PROP_CONTENT
);
String html = reader.getContentString();
assertEquals("<?xml", html.substring(0, 5));
// Check that the html has the img tags
assertEquals(
"Couldn't find img tag in html:\n" + html,
true, html.contains("<img")
);
// Check that it has the right img src
String expSource = "src=\""+ baseName + "_image";
assertEquals(
"Couldn't find correct img src in html:\n" + expSource + "\n" + html,
true, html.contains(expSource)
);
// Check we got an image folder
int numItems = nodeService.getChildAssocs(targetFolder).size();
// We expect a number of images and one text/html node to be created.
final int additionalItems = expectedImageCount + 1;
assertEquals(numItemsStart+additionalItems, numItems);
// There shouldn't be an image folder created
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
if(nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME).equals(
baseName + "_files"
)) {
fail("Image folder was created but shouldn't be there");
}
}
// Check we got the images in the same directory as the html
int images = 0;
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
String childName = (String)nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME);
if(childName.startsWith(baseName + "_image")) {
images++;
}
}
assertEquals(expectedImageCount, images);
// Until the rendition service supports a forced overwrite of other renditions, we must
// delete the old rendition node & the images.
nodeService.deleteNode(rendition.getChildRef());
for (ChildAssociationRef chAssRef : nodeService.getChildAssocs(targetFolder))
{
nodeService.deleteNode(chAssRef.getChildRef());
}
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -32,13 +32,10 @@ import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.repo.thumbnail.ThumbnailRenditionConvertor;
import org.alfresco.service.cmr.rendition.RenditionDefinition;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.PagedSourceOptions;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.repository.TransformationSourceOptions;
import org.alfresco.util.BaseSpringTest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -129,27 +126,6 @@ public class RenditionDefinitionTest extends BaseSpringTest
// than checking transformationOptions is equal to transformationOptions2.
if (!renditionName.equals("pdf") && !renditionName.equals("webpreview"))
{
// MNT-22409: We no longer have system.thumbnail.definition.default.pageLimit=1 as a default.
// It is -1 (unlimited), but to compensate for that the new OOTB renditions defined in
// 0100-baseRenditions now have startPage and endPage transform options. The following code modifies
// the transformationOptions so that they will be the same if there are no bugs.
Collection<TransformationSourceOptions> sourceOptionsList = transformationOptions2.getSourceOptionsList();
if (sourceOptionsList != null && sourceOptionsList.size() == 1)
{
TransformationSourceOptions sourceOptions = sourceOptionsList.iterator().next();
if (sourceOptions instanceof PagedSourceOptions)
{
PagedSourceOptions pagedSourceOptions = (PagedSourceOptions)sourceOptions;
if (pagedSourceOptions.getStartPageNumber() == 1 && pagedSourceOptions.getEndPageNumber() == 1)
{
if (transformationOptions.getSourceOptionsList() == null)
{
transformationOptions.setSourceOptionsList(sourceOptionsList);
}
}
}
}
assertEquals("The TransformationOptions used in transforms for " + renditionName + " should be the same",
transformationOptions.toStringAll(), transformationOptions2.toStringAll());
assertEquals("The transformationOptionsConverter back to the newer format was not the same for " +

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -565,18 +565,4 @@ public class TransformationOptionsConverterTest
"timeout=-1 "
);
}
@Test
public void testCommandOptionsFromOldOptions()
{
ImageTransformationOptions oldOptions = new ImageTransformationOptions();
oldOptions.setCommandOptions("-resize 350x50> -background none -gravity center");
assertConverterToMapAndBack(oldOptions, MIMETYPE_IMAGE_JPEG, MIMETYPE_IMAGE_PNG,
"ImageTransformationOptions [commandOptions=-resize 350x50> -background none -gravity center, " +
"resizeOptions=null, autoOrient=true]]",
"autoOrient=true " + // this is a default - so is also set when uploading a logo
"commandOptions=-resize 350x50> -background none -gravity center " +
"timeout=-1 ");
}
}

View File

@@ -159,19 +159,6 @@ public class DBQueryEngineTest
assertNodePresent(7, result);
}
@Test
public void shouldResultSetLengthMatchTheAmountOfAllAccessibleNodesWhenMaxPermissionCheckEnabled()
{
withMaxItems(5);
prepareTemplate(dbQuery, createNodes(10));
when(assessor.isIncluded(any(Node.class))).thenReturn(true);
engine.setMaxPermissionCheckEnabled(true);
FilteringResultSet result = engine.acceleratedNodeSelection(options, dbQuery, assessor);
assertEquals(10, result.length());
}
@Test
public void shouldNotConsiderInaccessibleNodesInResultSetWhenSkippingNodes()
{

View File

@@ -1,155 +0,0 @@
/*
* #%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.search.impl.solr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import org.alfresco.repo.search.QueryParserException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
/** Tests for the {@link AbstractSolrQueryHTTPClient}. */
public class AbstractSolrQueryHTTPClientTest
{
/** A URL for use in the tests. */
private static final String URL = "http://this/is/a/url";
/** The abstract class under test. */
private AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class);
@Mock
private HttpClient httpClient;
@Mock
private JSONObject body;
@Mock
private PostMethod postMethod;
@Mock
private Header header;
@Before
public void setUp() throws Exception
{
openMocks(this);
doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL);
when(postMethod.getResponseCharSet()).thenReturn("UTF-8");
}
/** Check postQuery works as expected for the success case. */
@Test
public void testPostQuery_success() throws Exception
{
when(body.toString()).thenReturn("Example body");
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
assertEquals("Unexpected JSON response received.", "{}", response.toString());
}
/** Check that the status code is usually passed through from Solr. */
@Test
public void testPostQuery_failure() throws Exception
{
String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}";
when(body.toString()).thenReturn("Example body");
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
try
{
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
fail("Expected a QueryParserException to be thrown.");
}
catch (QueryParserException e)
{
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND);
verify(postMethod).releaseConnection();
}
}
/** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */
@Test
public void testPostQuery_unsupportedOperation() throws Exception
{
String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}";
when(body.toString()).thenReturn("Example body");
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
try
{
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
fail("Expected a QueryParserException to be thrown.");
}
catch (QueryParserException e)
{
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED);
}
}
/** Check that a redirect can be followed if the endpoint reports that it's moved. */
@Test
public void testPostQuery_moved() throws Exception
{
when(body.toString()).thenReturn("Example body");
// Report "moved" for the first invocation and then OK for subsequent requests.
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_MOVED_PERMANENTLY).thenReturn(HttpServletResponse.SC_OK);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
when(postMethod.getResponseHeader("location")).thenReturn(header);
when(header.getValue()).thenReturn("http://new/URL");
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
verify(postMethod).setURI(new URI("http://new/URL", true));
assertEquals("Unexpected JSON response received.", "{}", response.toString());
}
/** Create an input stream containing the given string. */
private ByteArrayInputStream convertStringToInputStream(String message)
{
return new ByteArrayInputStream(message.getBytes());
}
}

View File

@@ -31,16 +31,14 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import java.io.UnsupportedEncodingException;
import org.alfresco.httpclient.HttpClientFactory;
import org.alfresco.httpclient.RequestHeadersHttpClient;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.Pair;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,6 +46,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
import java.io.UnsupportedEncodingException;
/**
* @author Andy
*
@@ -64,34 +64,34 @@ public class SolrStoreMappingWrapperTest
HttpClientFactory httpClientFactory;
@Mock
RequestHeadersHttpClient httpClientCommon;
HttpClient httpClientCommon;
@Mock
RequestHeadersHttpClient httpClient1;
HttpClient httpClient1;
@Mock
RequestHeadersHttpClient httpClient2;
HttpClient httpClient2;
@Mock
RequestHeadersHttpClient httpClient3;
HttpClient httpClient3;
@Mock
RequestHeadersHttpClient httpClient4;
HttpClient httpClient4;
@Mock
RequestHeadersHttpClient httpClient5;
HttpClient httpClient5;
@Mock
RequestHeadersHttpClient httpClient6;
HttpClient httpClient6;
@Mock
RequestHeadersHttpClient httpClient7;
HttpClient httpClient7;
@Mock
RequestHeadersHttpClient httpClient8;
HttpClient httpClient8;
@Mock
RequestHeadersHttpClient httpClient9;
HttpClient httpClient9;
@Mock
HostConfiguration hostConfigurationCommon;

View File

@@ -25,10 +25,10 @@
*/
package org.alfresco.repo.usage;
import java.util.concurrent.TimeUnit;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
@@ -37,7 +37,6 @@ import org.alfresco.service.cmr.admin.RepoUsage;
import org.alfresco.service.cmr.admin.RepoUsage.LicenseMode;
import org.alfresco.service.cmr.admin.RepoUsage.UsageType;
import org.alfresco.service.cmr.admin.RepoUsageStatus;
import org.alfresco.service.cmr.admin.RepoUsageStatus.RepoUsageLevel;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper;
@@ -49,8 +48,6 @@ import org.junit.experimental.categories.Category;
import org.junit.runners.MethodSorters;
import org.springframework.context.ApplicationContext;
import junit.framework.TestCase;
/**
* Tests {@link RepoUsageComponent}
*
@@ -239,123 +236,6 @@ public class RepoUsageComponentTest extends TestCase
RepoUsage usage = getUsage();
}
public void testLicenceHoursBeforeExpiration() throws Exception
{
// Update usage
updateUsage(UsageType.USAGE_ALL);
// Set the restrictions for license to expire in 6 hours
RepoUsage restrictions = new RepoUsage(
System.currentTimeMillis(),
5000L,
100000L,
LicenseMode.TEAM,
System.currentTimeMillis() + TimeUnit.HOURS.toMillis(6),
false);
repoUsageComponent.setRestrictions(restrictions);
// Update use
updateUsage(UsageType.USAGE_ALL);
// Get the usage
RepoUsage usage = getUsage();
// Check
assertFalse("Usage is in read-only mode",usage.isReadOnly());
assertTrue("System is in read-only mode",transactionService.getAllowWrite());
RepoUsageStatus status = repoUsageComponent.getUsageStatus();
assertEquals("System is not at Warning All Level",status.getLevel(),RepoUsageLevel.WARN_ALL);
}
public void testLicenceMinutesAfterExpiration() throws Exception
{
// Update usage
updateUsage(UsageType.USAGE_ALL);
// Set the restrictions for license to expire in 6 hours
RepoUsage restrictions = new RepoUsage(
System.currentTimeMillis(),
5000L,
100000L,
LicenseMode.TEAM,
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(1),
false);
repoUsageComponent.setRestrictions(restrictions);
// Update use
updateUsage(UsageType.USAGE_ALL);
// Get the usage
RepoUsage usage = getUsage();
// Check we are in read-only mode
assertTrue("Usage is not in read-only mode",usage.isReadOnly());
assertFalse("System is not in read-only mode",transactionService.getAllowWrite());
RepoUsageStatus status = repoUsageComponent.getUsageStatus();
assertEquals("System is not at Locked Level",status.getLevel(),RepoUsageLevel.LOCKED_DOWN);
}
public void testLicenceMonthsBeforeExpiration() throws Exception
{
// Update usage
updateUsage(UsageType.USAGE_ALL);
// Set the restrictions for license to expire in 60 days from now
RepoUsage restrictions = new RepoUsage(
System.currentTimeMillis(),
5000L,
100000L,
LicenseMode.TEAM,
System.currentTimeMillis() + TimeUnit.DAYS.toMillis(60),
false);
repoUsageComponent.setRestrictions(restrictions);
// Update use
updateUsage(UsageType.USAGE_ALL);
// Get the usage
RepoUsage usage = getUsage();
// Check
assertFalse("Usage is in read-only mode",usage.isReadOnly());
assertTrue("System is in read-only mode",transactionService.getAllowWrite());
RepoUsageStatus status = repoUsageComponent.getUsageStatus();
assertEquals("System is not at OK Level",status.getLevel(),RepoUsageLevel.OK);
}
public void testLicenceDaysAfterExpiration() throws Exception
{
// Update usage
updateUsage(UsageType.USAGE_ALL);
// Set the restrictions for license expired 5 days ago
RepoUsage restrictions = new RepoUsage(
System.currentTimeMillis(),
5000L,
100000L,
LicenseMode.TEAM,
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(5),
false);
repoUsageComponent.setRestrictions(restrictions);
// Update use
updateUsage(UsageType.USAGE_ALL);
// Get the usage
RepoUsage usage = getUsage();
// Check we are in read-only mode
assertTrue("Usage is not in read-only mode",usage.isReadOnly());
assertFalse("System is not in read-only mode",transactionService.getAllowWrite());
RepoUsageStatus status = repoUsageComponent.getUsageStatus();
assertEquals("System is not at Locked Level",status.getLevel(),RepoUsageLevel.LOCKED_DOWN);
}
/**
* Check that concurrent updates are prevented
*

View File

@@ -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=
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