mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c5aed167f4 | ||
|
a477c19e9a | ||
|
1497362d3e | ||
|
27e2775e40 | ||
|
f2ecce0f46 | ||
|
0ad54cbf77 | ||
|
3e3cd479c2 | ||
|
b9b41a10e8 | ||
|
664d0b9704 | ||
|
1493b02d8d | ||
|
70c1a1279c | ||
|
f0638e8d7d | ||
|
983dd47c35 | ||
|
24d092cb02 | ||
|
ddb299ab03 | ||
|
19d214fcb0 | ||
|
870ff8cc64 | ||
|
aed08fe5d9 | ||
|
a3b0541560 | ||
|
2f6c5614c3 | ||
|
82d3828351 | ||
|
c986498481 | ||
|
c93d81379e | ||
|
d348e0b72d | ||
|
dc5e7405cc | ||
|
3c8bb7f154 | ||
|
bb8d42d23c | ||
|
9c1aa53819 | ||
|
885f4a49a5 | ||
|
9989ec3260 | ||
|
78ad14b696 |
@@ -25,6 +25,10 @@
|
||||
<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>
|
||||
|
||||
|
@@ -177,11 +177,6 @@ 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'
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -21,7 +21,6 @@ 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;
|
||||
@@ -32,14 +31,11 @@ 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;
|
||||
@@ -53,8 +49,6 @@ 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;
|
||||
@@ -75,23 +69,25 @@ 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;
|
||||
HTTPS, NONE, SECRET;
|
||||
|
||||
public static SecureCommsType getType(String type)
|
||||
{
|
||||
if(type.equalsIgnoreCase("https"))
|
||||
switch (type.toLowerCase())
|
||||
{
|
||||
return HTTPS;
|
||||
}
|
||||
else if(type.equalsIgnoreCase("none"))
|
||||
{
|
||||
return NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid communications type");
|
||||
case "https": return HTTPS;
|
||||
case "none": return NONE;
|
||||
case "secret": return SECRET;
|
||||
default: throw new IllegalArgumentException("Invalid communications type");
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -122,14 +118,24 @@ 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;
|
||||
@@ -145,6 +151,21 @@ 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);
|
||||
@@ -272,10 +293,44 @@ public class HttpClientFactory
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
protected HttpClient constructHttpClient()
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
|
||||
HttpClient httpClient = new HttpClient(connectionManager);
|
||||
RequestHeadersHttpClient httpClient = new RequestHeadersHttpClient(connectionManager);
|
||||
HttpClientParams params = httpClient.getParams();
|
||||
params.setBooleanParameter(HttpConnectionParams.TCP_NODELAY, true);
|
||||
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true);
|
||||
@@ -291,15 +346,15 @@ public class HttpClientFactory
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
protected HttpClient getHttpsClient()
|
||||
protected RequestHeadersHttpClient getHttpsClient()
|
||||
{
|
||||
return getHttpsClient(host, sslPort);
|
||||
}
|
||||
|
||||
protected HttpClient getHttpsClient(String httpsHost, int httpsPort)
|
||||
protected RequestHeadersHttpClient getHttpsClient(String httpsHost, int httpsPort)
|
||||
{
|
||||
// Configure a custom SSL socket factory that will enforce mutual authentication
|
||||
HttpClient httpClient = constructHttpClient();
|
||||
RequestHeadersHttpClient 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));
|
||||
@@ -307,28 +362,54 @@ public class HttpClientFactory
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
protected HttpClient getDefaultHttpClient()
|
||||
protected RequestHeadersHttpClient getDefaultHttpClient()
|
||||
{
|
||||
return getDefaultHttpClient(host, port);
|
||||
}
|
||||
|
||||
protected HttpClient getDefaultHttpClient(String httpHost, int httpPort)
|
||||
protected RequestHeadersHttpClient getDefaultHttpClient(String httpHost, int httpPort)
|
||||
{
|
||||
HttpClient httpClient = constructHttpClient();
|
||||
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.getHostConfiguration().setHost(httpHost, httpPort);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
protected AlfrescoHttpClient getAlfrescoHttpsClient()
|
||||
{
|
||||
AlfrescoHttpClient repoClient = new HttpsClient(getHttpsClient());
|
||||
return repoClient;
|
||||
return new HttpsClient(getHttpsClient());
|
||||
}
|
||||
|
||||
protected AlfrescoHttpClient getAlfrescoHttpClient()
|
||||
{
|
||||
AlfrescoHttpClient repoClient = new DefaultHttpClient(getDefaultHttpClient());
|
||||
return repoClient;
|
||||
return new DefaultHttpClient(getDefaultHttpClient());
|
||||
}
|
||||
|
||||
protected AlfrescoHttpClient getAlfrescoSharedSecretClient()
|
||||
{
|
||||
return new DefaultHttpClient(getSharedSecretHttpClient());
|
||||
}
|
||||
|
||||
protected HttpClient getMD5HttpClient(String host, int port)
|
||||
@@ -341,66 +422,37 @@ public class HttpClientFactory
|
||||
|
||||
public AlfrescoHttpClient getRepoClient(String host, int port)
|
||||
{
|
||||
AlfrescoHttpClient repoClient = null;
|
||||
|
||||
if(secureCommsType == SecureCommsType.HTTPS)
|
||||
switch (secureCommsType)
|
||||
{
|
||||
repoClient = getAlfrescoHttpsClient();
|
||||
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'");
|
||||
}
|
||||
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 HttpClient getHttpClient()
|
||||
public RequestHeadersHttpClient getHttpClient()
|
||||
{
|
||||
HttpClient httpClient = null;
|
||||
|
||||
if(secureCommsType == SecureCommsType.HTTPS)
|
||||
switch (secureCommsType)
|
||||
{
|
||||
httpClient = getHttpsClient();
|
||||
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'");
|
||||
}
|
||||
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 HttpClient getHttpClient(String host, int port)
|
||||
public RequestHeadersHttpClient getHttpClient(String host, int port)
|
||||
{
|
||||
HttpClient httpClient = null;
|
||||
|
||||
if(secureCommsType == SecureCommsType.HTTPS)
|
||||
switch (secureCommsType)
|
||||
{
|
||||
httpClient = getHttpsClient(host, port);
|
||||
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'");
|
||||
}
|
||||
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.
|
||||
*
|
||||
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@@ -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-6.el8 \
|
||||
dejavu-fonts-common-2.35-7.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-6.el8 && \
|
||||
dejavu-sans-fonts-2.35-7.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,
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<profiles>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -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="./css/reset.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./css/alfresco.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/reset.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/alfresco.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="sticky-wrapper">
|
||||
|
@@ -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="./css/reset.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./css/alfresco.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/reset.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/<%=sysAdminParams.getAlfrescoContext()%>/css/alfresco.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="sticky-wrapper">
|
||||
|
26
pom.xml
26
pom.xml
@@ -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>11.2</version>
|
||||
<version>9.13</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>1</acs.version.minor>
|
||||
<acs.version.revision>0</acs.version.revision>
|
||||
<acs.version.minor>0</acs.version.minor>
|
||||
<acs.version.revision>1</acs.version.revision>
|
||||
<acs.version.label />
|
||||
|
||||
<version.edition>Community</version.edition>
|
||||
@@ -55,14 +55,14 @@
|
||||
|
||||
<dependency.spring.version>5.3.3</dependency.spring.version>
|
||||
<dependency.antlr.version>3.5.2</dependency.antlr.version>
|
||||
<dependency.jackson.version>2.12.2</dependency.jackson.version>
|
||||
<dependency.jackson.version>2.12.1</dependency.jackson.version>
|
||||
<dependency.jackson-databind.version>${dependency.jackson.version}</dependency.jackson-databind.version>
|
||||
<dependency.cxf.version>3.4.3</dependency.cxf.version>
|
||||
<dependency.cxf.version>3.4.2</dependency.cxf.version>
|
||||
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
|
||||
<dependency.webscripts.version>8.18</dependency.webscripts.version>
|
||||
<dependency.bouncycastle.version>1.68</dependency.bouncycastle.version>
|
||||
<dependency.mockito-core.version>3.8.0</dependency.mockito-core.version>
|
||||
<dependency.org-json.version>20210307</dependency.org-json.version>
|
||||
<dependency.org-json.version>20201115</dependency.org-json.version>
|
||||
<dependency.commons-dbcp.version>1.4-DBCP330</dependency.commons-dbcp.version>
|
||||
<dependency.commons-io.version>2.8.0</dependency.commons-io.version>
|
||||
<dependency.gson.version>2.8.5</dependency.gson.version>
|
||||
@@ -80,7 +80,7 @@
|
||||
<dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
|
||||
<dependency.keycloak.version>11.0.0-alfresco-001</dependency.keycloak.version>
|
||||
<dependency.jboss.logging.version>3.4.1.Final</dependency.jboss.logging.version>
|
||||
<dependency.camel.version>3.7.1</dependency.camel.version>
|
||||
<dependency.camel.version>3.7.0</dependency.camel.version>
|
||||
<dependency.activemq.version>5.16.1</dependency.activemq.version>
|
||||
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
|
||||
<dependency.awaitility.version>4.0.3</dependency.awaitility.version>
|
||||
@@ -102,10 +102,10 @@
|
||||
<dependency.postgresql.version>42.2.19</dependency.postgresql.version>
|
||||
<dependency.mysql.version>8.0.23</dependency.mysql.version>
|
||||
<dependency.mariadb.version>2.7.2</dependency.mariadb.version>
|
||||
<dependency.tas-utility.version>3.0.44</dependency.tas-utility.version>
|
||||
<dependency.tas-utility.version>3.0.43</dependency.tas-utility.version>
|
||||
<dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
|
||||
<dependency.tas-restapi.version>1.57</dependency.tas-restapi.version>
|
||||
<dependency.tas-cmis.version>1.29</dependency.tas-cmis.version>
|
||||
<dependency.tas-restapi.version>1.56</dependency.tas-restapi.version>
|
||||
<dependency.tas-cmis.version>1.27</dependency.tas-cmis.version>
|
||||
<dependency.tas-email.version>1.8</dependency.tas-email.version>
|
||||
<dependency.tas-webdav.version>1.6</dependency.tas-webdav.version>
|
||||
<dependency.tas-ftp.version>1.5</dependency.tas-ftp.version>
|
||||
@@ -116,7 +116,7 @@
|
||||
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
|
||||
<url>https://github.com/Alfresco/alfresco-community-repo</url>
|
||||
<tag>11.2</tag>
|
||||
<tag>9.13</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -679,7 +679,7 @@
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.10.10</version>
|
||||
<version>2.10.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided dependencies -->
|
||||
@@ -694,7 +694,7 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<version>4.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -25,21 +25,18 @@
|
||||
*/
|
||||
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;
|
||||
@@ -88,9 +85,7 @@ public class SOLRAuthenticationFilter implements DependencyInjectedFilter, Initi
|
||||
|
||||
private String sharedSecret;
|
||||
|
||||
private String sharedSecretHeader = DEFAULT_SHAREDSECRET_HEADER;
|
||||
|
||||
private static final String DEFAULT_SHAREDSECRET_HEADER = "X-Alfresco-Search-Secret";
|
||||
private String sharedSecretHeader = HttpClientFactory.DEFAULT_SHAREDSECRET_HEADER;
|
||||
|
||||
public void setSecureComms(String type)
|
||||
{
|
||||
|
@@ -716,7 +716,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!pathInfo.substring(0, 6).toLowerCase().equals("/cmis/") && !pathInfo.equals("/discovery"))
|
||||
if((pathInfo.length() > 5 && !pathInfo.substring(0, 6).toLowerCase().equals("/cmis/")) && !pathInfo.equals("/discovery"))
|
||||
{
|
||||
// remove tenant
|
||||
int idx = pathInfo.indexOf('/', 1);
|
||||
|
@@ -31,6 +31,7 @@ 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;
|
||||
@@ -70,7 +71,9 @@ 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 || "none".equals(prop))
|
||||
if (prop == null ||
|
||||
SecureCommsType.getType(prop) == SecureCommsType.NONE ||
|
||||
SecureCommsType.getType(prop) == SecureCommsType.SECRET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.2</version>
|
||||
<version>9.13</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -82,7 +82,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
@@ -810,7 +810,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -32,6 +32,8 @@ 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;
|
||||
@@ -228,7 +230,7 @@ public class ActivityPosterImpl implements CmisActivityPoster, InitializingBean
|
||||
{
|
||||
if(activitiesEnabled && !hiddenAspect.hasHiddenAspect(nodeRef))
|
||||
{
|
||||
SiteInfo siteInfo = siteService.getSite(nodeRef);
|
||||
SiteInfo siteInfo = getSiteAsSystem(nodeRef);
|
||||
String siteId = (siteInfo != null ? siteInfo.getShortName() : null);
|
||||
if(siteId != null && !siteId.equals(""))
|
||||
{
|
||||
@@ -291,4 +293,15 @@ 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -35,8 +35,6 @@ 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;
|
||||
@@ -85,16 +83,13 @@ 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;
|
||||
|
||||
@@ -163,12 +158,6 @@ 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
|
||||
@@ -252,7 +241,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
||||
}
|
||||
}
|
||||
|
||||
protected class AclWorker implements BatchProcessor.BatchProcessWorker<NodeRef>
|
||||
private class AclWorker implements BatchProcessor.BatchProcessWorker<NodeRef>
|
||||
{
|
||||
private Set<QName> aspects = new HashSet<>(1);
|
||||
|
||||
@@ -326,8 +315,6 @@ 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));
|
||||
@@ -343,13 +330,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
||||
};
|
||||
|
||||
|
||||
/** Create a new AclWorker. */
|
||||
protected AclWorker createAclWorker()
|
||||
{
|
||||
return new AclWorker();
|
||||
}
|
||||
|
||||
class GetNodesWithAspectCallback implements NodeRefQueryCallback
|
||||
private class GetNodesWithAspectCallback implements NodeRefQueryCallback
|
||||
{
|
||||
private List<NodeRef> nodes = new ArrayList<>();
|
||||
private long minNodeId;
|
||||
@@ -440,11 +421,11 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
||||
|
||||
try
|
||||
{
|
||||
lockToken = jobLockService.getLock(LOCK_Q_NAME, lockTimeToLive, 0, 1);
|
||||
jobLockService.refreshLock(lockToken, LOCK_Q_NAME, lockRefreshTime, jobLockRefreshCallback);
|
||||
lockToken = jobLockService.getLock(lockQName, lockTimeToLive, 0, 1);
|
||||
jobLockService.refreshLock(lockToken, lockQName, lockRefreshTime, jobLockRefreshCallback);
|
||||
|
||||
AclWorkProvider provider = new AclWorkProvider();
|
||||
AclWorker worker = createAclWorker();
|
||||
AclWorker worker = new AclWorker();
|
||||
BatchProcessor<NodeRef> bp = new BatchProcessor<>("FixedAclUpdater",
|
||||
transactionService.getRetryingTransactionHelper(), provider, numThreads, maxItemBatchSize, applicationContext,
|
||||
log, 100);
|
||||
@@ -461,7 +442,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
||||
jobLockRefreshCallback.isActive.set(false);
|
||||
if (lockToken != null)
|
||||
{
|
||||
jobLockService.releaseLock(lockToken, LOCK_Q_NAME);
|
||||
jobLockService.releaseLock(lockToken, lockQName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,35 +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.domain.permissions;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/** Listener to receive callback events when permissions are asynchronously updated with the {@link FixedAclUpdater}. */
|
||||
public interface FixedAclUpdaterListener
|
||||
{
|
||||
/** Callback method for when permissions have been updated by the FixedAclUpdater. */
|
||||
void permissionsUpdatedAsynchronously(NodeRef nodeRef);
|
||||
}
|
@@ -54,7 +54,6 @@ 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;
|
||||
@@ -90,11 +89,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;
|
||||
@@ -109,10 +108,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();
|
||||
@@ -177,12 +176,6 @@ 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;
|
||||
@@ -198,6 +191,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
this.nodeResourceHelper = nodeResourceHelper;
|
||||
}
|
||||
|
||||
public void setEventGeneratorQueue(EventGeneratorQueue eventGeneratorQueue)
|
||||
{
|
||||
this.eventGeneratorQueue = eventGeneratorQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
@@ -428,20 +426,26 @@ 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;
|
||||
return null;
|
||||
}
|
||||
|
||||
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(getEventInfo(user));
|
||||
|
||||
final RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
|
||||
|
||||
final QName nodeType = consolidator.getNodeType();
|
||||
if (isFiltered(nodeType, user))
|
||||
@@ -452,7 +456,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
+ ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString())
|
||||
+ "' created by: " + user);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (event.getType().equals(EventType.NODE_UPDATED.getType()) && consolidator.isResourceBeforeAllFieldsNull())
|
||||
@@ -461,27 +465,34 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
{
|
||||
LOGGER.trace("Ignoring node updated event as no fields have been updated: " + nodeRef);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
logAndSendEvent(event, consolidator.getEventTypes());
|
||||
logEvent(event, consolidator.getEventTypes());
|
||||
return event;
|
||||
}
|
||||
|
||||
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;
|
||||
return null;
|
||||
}
|
||||
|
||||
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));
|
||||
final RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
|
||||
|
||||
final QName childAssocType = consolidator.getChildAssocType();
|
||||
if (isFilteredChildAssociation(childAssocType, user))
|
||||
@@ -492,7 +503,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
||||
+ "' created by: " + user);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
} else if (childAssociationRef.isPrimary())
|
||||
{
|
||||
if (LOGGER.isTraceEnabled())
|
||||
@@ -501,13 +512,20 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
||||
+ "' created by: " + user);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
logAndSendEvent(event, consolidator.getEventTypes());
|
||||
logEvent(event, consolidator.getEventTypes());
|
||||
return event;
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
@@ -515,30 +533,21 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
{
|
||||
LOGGER.trace("Ignoring temporary peer association: " + peerAssociationRef);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
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());
|
||||
RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
|
||||
logEvent(event, consolidator.getEventTypes());
|
||||
return event;
|
||||
}
|
||||
|
||||
protected void logAndSendEvent(RepoEvent<?> event, Deque<EventType> listOfEvents)
|
||||
private void logEvent(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* #%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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* 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
|
||||
@@ -52,6 +52,7 @@ 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;
|
||||
@@ -122,6 +123,7 @@ 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[]
|
||||
@@ -284,6 +286,8 @@ public class TransformationOptionsConverter implements InitializingBean
|
||||
}
|
||||
opts.setSourceOptionsList(sourceOptionsList);
|
||||
}
|
||||
|
||||
ifSet(options, OPT_COMMAND_OPTIONS, (v) -> opts.setCommandOptions(v));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -361,13 +365,11 @@ public class TransformationOptionsConverter implements InitializingBean
|
||||
{
|
||||
ImageTransformationOptions opts = (ImageTransformationOptions) options;
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
String commandOptions = opts.getCommandOptions();
|
||||
if (commandOptions != null && !commandOptions.isBlank())
|
||||
{
|
||||
logger.error("ImageMagick commandOptions are no longer supported for security reasons: " + commandOptions);
|
||||
}
|
||||
ifSet(commandOptions != null && !commandOptions.isBlank(), map, OPT_COMMAND_OPTIONS, commandOptions);
|
||||
|
||||
ImageResizeOptions imageResizeOptions = opts.getResizeOptions();
|
||||
if (imageResizeOptions != null)
|
||||
|
@@ -35,6 +35,7 @@ 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;
|
||||
@@ -46,6 +47,7 @@ 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;
|
||||
@@ -110,8 +112,12 @@ 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)
|
||||
@@ -129,6 +135,11 @@ public class DBQueryEngine implements QueryEngine
|
||||
this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis;
|
||||
}
|
||||
|
||||
public void setMaxPermissionCheckEnabled(boolean maxPermissionCheckEnabled)
|
||||
{
|
||||
this.maxPermissionCheckEnabled = maxPermissionCheckEnabled;
|
||||
}
|
||||
|
||||
public void setTemplate(SqlSessionTemplate template)
|
||||
{
|
||||
this.template = template;
|
||||
@@ -313,6 +324,9 @@ 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);
|
||||
|
||||
@@ -322,21 +336,16 @@ public class DBQueryEngine implements QueryEngine
|
||||
@Override
|
||||
public void handleResult(ResultContext<? extends Node> context)
|
||||
{
|
||||
doHandleResult(permissionAssessor, nodes, requiredNodes, context);
|
||||
}
|
||||
|
||||
private void doHandleResult(NodePermissionAssessor permissionAssessor, List<Node> nodes,
|
||||
int requiredNodes, ResultContext<? extends Node> context)
|
||||
{
|
||||
if (nodes.size() >= requiredNodes)
|
||||
if (!maxPermissionCheckEnabled && nodes.size() >= requiredNodes)
|
||||
{
|
||||
context.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
Node node = context.getResultObject();
|
||||
addStoreInfo(node);
|
||||
|
||||
boolean shouldCache = nodes.size() >= options.getSkipCount();
|
||||
boolean shouldCache = shouldCache(options, nodes, requiredNodes);
|
||||
if(shouldCache)
|
||||
{
|
||||
logger.debug("- selected node "+nodes.size()+": "+node.getUuid()+" "+node.getId());
|
||||
@@ -349,7 +358,14 @@ public class DBQueryEngine implements QueryEngine
|
||||
|
||||
if (permissionAssessor.isIncluded(node))
|
||||
{
|
||||
nodes.add(shouldCache ? node : null);
|
||||
if (nodes.size() > requiredNodes)
|
||||
{
|
||||
nodes.add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.add(shouldCache ? node : null);
|
||||
}
|
||||
}
|
||||
|
||||
if (permissionAssessor.shouldQuitChecks())
|
||||
@@ -358,6 +374,18 @@ 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();
|
||||
@@ -457,4 +485,21 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -41,9 +41,13 @@ 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;
|
||||
@@ -138,24 +142,31 @@ public class NodePermissionAssessor
|
||||
|
||||
public void setMaxPermissionChecks(int maxPermissionChecks)
|
||||
{
|
||||
this.maxPermissionChecks = maxPermissionChecks;
|
||||
if (maxPermissionChecks == Integer.MAX_VALUE)
|
||||
{
|
||||
this.maxPermissionChecks = maxPermissionChecks;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.maxPermissionChecks = maxPermissionChecks + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldQuitChecks()
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
if (checksPerformed >= maxPermissionChecks)
|
||||
{
|
||||
result = true;
|
||||
logger.warn("Maximum permission checks exceeded (" + maxPermissionChecks + ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((System.currentTimeMillis() - startTime) >= maxPermissionCheckTimeMillis)
|
||||
{
|
||||
result = true;
|
||||
logger.warn("Maximum permission checks time exceeded (" + maxPermissionCheckTimeMillis + ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis)
|
||||
|
@@ -38,9 +38,10 @@
|
||||
<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">
|
||||
@@ -54,7 +55,45 @@
|
||||
|
||||
<bean id="nodeResourceHelper" class="org.alfresco.repo.event2.NodeResourceHelper" parent="baseNodeResourceHelper"/>
|
||||
|
||||
<bean id="eventGeneratorV2" class="org.alfresco.repo.event2.EventGenerator" parent="baseEventGeneratorV2">
|
||||
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
|
||||
<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>
|
||||
</beans>
|
||||
|
@@ -9,7 +9,9 @@
|
||||
{"name": "allowEnlargement", "value": true},
|
||||
{"name": "maintainAspectRatio", "value": true},
|
||||
{"name": "autoOrient", "value": true},
|
||||
{"name": "thumbnail", "value": true}
|
||||
{"name": "thumbnail", "value": true},
|
||||
{"name": "startPage", "value": "0"},
|
||||
{"name": "endPage", "value": "0"}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -21,7 +23,9 @@
|
||||
{"name": "allowEnlargement", "value": false},
|
||||
{"name": "maintainAspectRatio", "value": true},
|
||||
{"name": "autoOrient", "value": true},
|
||||
{"name": "thumbnail", "value": true}
|
||||
{"name": "thumbnail", "value": true},
|
||||
{"name": "startPage", "value": "0"},
|
||||
{"name": "endPage", "value": "0"}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -33,7 +37,9 @@
|
||||
{"name": "allowEnlargement", "value": false},
|
||||
{"name": "maintainAspectRatio", "value": true},
|
||||
{"name": "autoOrient", "value": true},
|
||||
{"name": "thumbnail", "value": true}
|
||||
{"name": "thumbnail", "value": true},
|
||||
{"name": "startPage", "value": "0"},
|
||||
{"name": "endPage", "value": "0"}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -45,7 +51,9 @@
|
||||
{"name": "allowEnlargement", "value": false},
|
||||
{"name": "maintainAspectRatio", "value": true},
|
||||
{"name": "autoOrient", "value": true},
|
||||
{"name": "thumbnail", "value": true}
|
||||
{"name": "thumbnail", "value": true},
|
||||
{"name": "startPage", "value": "0"},
|
||||
{"name": "endPage", "value": "0"}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -57,7 +65,9 @@
|
||||
{"name": "allowEnlargement", "value": false},
|
||||
{"name": "maintainAspectRatio", "value": true},
|
||||
{"name": "autoOrient", "value": true},
|
||||
{"name": "thumbnail", "value": true}
|
||||
{"name": "thumbnail", "value": true},
|
||||
{"name": "startPage", "value": "0"},
|
||||
{"name": "endPage", "value": "0"}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@@ -153,6 +153,7 @@ 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
|
||||
@@ -480,7 +481,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
|
||||
@@ -1206,9 +1207,18 @@ 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=
|
||||
repo.event2.filter.users=System, null
|
||||
# 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
|
||||
|
@@ -126,6 +126,9 @@
|
||||
<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">
|
||||
|
@@ -165,6 +165,8 @@
|
||||
<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}"/>
|
||||
|
@@ -170,7 +170,6 @@ 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,
|
||||
|
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* #%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);
|
||||
}
|
||||
}
|
@@ -78,6 +78,7 @@ 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;
|
||||
@@ -107,7 +108,13 @@ 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;
|
||||
@@ -121,7 +128,6 @@ 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;
|
||||
@@ -213,6 +219,9 @@ 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;
|
||||
|
||||
@@ -338,6 +347,9 @@ 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");
|
||||
@@ -719,12 +731,17 @@ 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("admin", "admin", cmisVersion);
|
||||
CallContext context = new SimpleCallContext(username, password, cmisVersion);
|
||||
cmisService = factory.getService(context);
|
||||
T ret = callback.execute(cmisService);
|
||||
return ret;
|
||||
@@ -4101,6 +4118,108 @@ 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>();
|
||||
|
@@ -1,108 +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.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));
|
||||
}
|
||||
}
|
@@ -30,6 +30,7 @@ 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;
|
||||
@@ -77,12 +78,14 @@ 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;
|
||||
@@ -104,6 +107,13 @@ 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
|
||||
@@ -141,6 +151,33 @@ 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
|
||||
@@ -179,6 +216,16 @@ 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(() -> {
|
||||
@@ -376,13 +423,18 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
||||
|
||||
public static class RepoEventContainer implements Processor
|
||||
{
|
||||
private final List<RepoEvent<?>> events = new ArrayList<>();
|
||||
private final List<RepoEvent<?>> events = Collections.synchronizedList(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()
|
||||
@@ -404,6 +456,12 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
||||
{
|
||||
events.clear();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return events.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* #%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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* #%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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -34,7 +34,8 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
UpdateRepoEventIT.class,
|
||||
DeleteRepoEventIT.class,
|
||||
ChildAssociationRepoEventIT.class,
|
||||
PeerAssociationRepoEventIT.class
|
||||
PeerAssociationRepoEventIT.class,
|
||||
EventGeneratorTest.class
|
||||
})
|
||||
public class RepoEvent2ITSuite
|
||||
{
|
||||
|
@@ -33,7 +33,8 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ EventFilterUnitTest.class,
|
||||
EventConsolidatorUnitTest.class,
|
||||
EventJSONSchemaUnitTest.class
|
||||
EventJSONSchemaUnitTest.class,
|
||||
EventGeneratorQueueUnitTest.class
|
||||
})
|
||||
public class RepoEvent2UnitSuite
|
||||
{
|
||||
|
@@ -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.1.0-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.0.1-RC2"
|
||||
// The main version may contain 3 or 4 digit parts.
|
||||
public void testGetVersionWithoutSuffix()
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* 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
|
||||
@@ -32,10 +32,13 @@ 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;
|
||||
@@ -126,6 +129,27 @@ 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 " +
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* 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
|
||||
@@ -565,4 +565,18 @@ 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 ");
|
||||
}
|
||||
}
|
@@ -159,6 +159,19 @@ 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()
|
||||
{
|
||||
|
@@ -31,14 +31,16 @@ 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;
|
||||
@@ -46,8 +48,6 @@ 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
|
||||
HttpClient httpClientCommon;
|
||||
RequestHeadersHttpClient httpClientCommon;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient1;
|
||||
RequestHeadersHttpClient httpClient1;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient2;
|
||||
RequestHeadersHttpClient httpClient2;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient3;
|
||||
RequestHeadersHttpClient httpClient3;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient4;
|
||||
RequestHeadersHttpClient httpClient4;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient5;
|
||||
RequestHeadersHttpClient httpClient5;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient6;
|
||||
RequestHeadersHttpClient httpClient6;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient7;
|
||||
RequestHeadersHttpClient httpClient7;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient8;
|
||||
RequestHeadersHttpClient httpClient8;
|
||||
|
||||
@Mock
|
||||
HttpClient httpClient9;
|
||||
RequestHeadersHttpClient httpClient9;
|
||||
|
||||
@Mock
|
||||
HostConfiguration hostConfigurationCommon;
|
||||
|
@@ -25,19 +25,4 @@
|
||||
<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>
|
@@ -1,9 +1,6 @@
|
||||
messaging.broker.url=nio://localhost:61616
|
||||
messaging.broker.url=vm://localhost?broker.persistent=false
|
||||
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
|
Reference in New Issue
Block a user