mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-24 14:32:01 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
aed08fe5d9 | ||
|
a3b0541560 | ||
|
2f6c5614c3 | ||
|
82d3828351 | ||
|
c986498481 | ||
|
c93d81379e | ||
|
d348e0b72d | ||
|
dc5e7405cc | ||
|
3c8bb7f154 | ||
|
bb8d42d23c | ||
|
9c1aa53819 | ||
|
885f4a49a5 | ||
|
9989ec3260 | ||
|
78ad14b696 |
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@@ -21,7 +21,6 @@ package org.alfresco.httpclient;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.AlgorithmParameters;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,14 +31,11 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
import org.alfresco.encryption.AlfrescoKeyStore;
|
import org.alfresco.encryption.AlfrescoKeyStore;
|
||||||
import org.alfresco.encryption.AlfrescoKeyStoreImpl;
|
import org.alfresco.encryption.AlfrescoKeyStoreImpl;
|
||||||
import org.alfresco.encryption.EncryptionUtils;
|
import org.alfresco.encryption.EncryptionUtils;
|
||||||
import org.alfresco.encryption.Encryptor;
|
|
||||||
import org.alfresco.encryption.KeyProvider;
|
|
||||||
import org.alfresco.encryption.KeyResourceLoader;
|
import org.alfresco.encryption.KeyResourceLoader;
|
||||||
import org.alfresco.encryption.KeyStoreParameters;
|
import org.alfresco.encryption.KeyStoreParameters;
|
||||||
import org.alfresco.encryption.ssl.AuthSSLProtocolSocketFactory;
|
import org.alfresco.encryption.ssl.AuthSSLProtocolSocketFactory;
|
||||||
import org.alfresco.encryption.ssl.SSLEncryptionParameters;
|
import org.alfresco.encryption.ssl.SSLEncryptionParameters;
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.util.Pair;
|
|
||||||
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
|
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
|
||||||
import org.apache.commons.httpclient.HostConfiguration;
|
import org.apache.commons.httpclient.HostConfiguration;
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
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.URI;
|
||||||
import org.apache.commons.httpclient.URIException;
|
import org.apache.commons.httpclient.URIException;
|
||||||
import org.apache.commons.httpclient.cookie.CookiePolicy;
|
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.DefaultHttpParams;
|
||||||
import org.apache.commons.httpclient.params.DefaultHttpParamsFactory;
|
import org.apache.commons.httpclient.params.DefaultHttpParamsFactory;
|
||||||
import org.apache.commons.httpclient.params.HttpClientParams;
|
import org.apache.commons.httpclient.params.HttpClientParams;
|
||||||
@@ -75,23 +69,25 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
*/
|
*/
|
||||||
public class HttpClientFactory
|
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
|
public static enum SecureCommsType
|
||||||
{
|
{
|
||||||
HTTPS, NONE;
|
HTTPS, NONE, SECRET;
|
||||||
|
|
||||||
public static SecureCommsType getType(String type)
|
public static SecureCommsType getType(String type)
|
||||||
{
|
{
|
||||||
if(type.equalsIgnoreCase("https"))
|
switch (type.toLowerCase())
|
||||||
{
|
{
|
||||||
return HTTPS;
|
case "https": return HTTPS;
|
||||||
}
|
case "none": return NONE;
|
||||||
else if(type.equalsIgnoreCase("none"))
|
case "secret": return SECRET;
|
||||||
{
|
default: throw new IllegalArgumentException("Invalid communications type");
|
||||||
return NONE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Invalid communications type");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -122,14 +118,24 @@ public class HttpClientFactory
|
|||||||
|
|
||||||
private int connectionTimeout = 0;
|
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()
|
public HttpClientFactory()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor for legacy subsystems.
|
||||||
|
*/
|
||||||
public HttpClientFactory(SecureCommsType secureCommsType, SSLEncryptionParameters sslEncryptionParameters,
|
public HttpClientFactory(SecureCommsType secureCommsType, SSLEncryptionParameters sslEncryptionParameters,
|
||||||
KeyResourceLoader keyResourceLoader, KeyStoreParameters keyStoreParameters,
|
KeyResourceLoader keyResourceLoader, KeyStoreParameters keyStoreParameters,
|
||||||
MD5EncryptionParameters encryptionParameters, String host, int port, int sslPort, int maxTotalConnections,
|
MD5EncryptionParameters encryptionParameters, String host, int port, int sslPort,
|
||||||
int maxHostConnections, int socketTimeout)
|
int maxTotalConnections, int maxHostConnections, int socketTimeout)
|
||||||
{
|
{
|
||||||
this.secureCommsType = secureCommsType;
|
this.secureCommsType = secureCommsType;
|
||||||
this.sslEncryptionParameters = sslEncryptionParameters;
|
this.sslEncryptionParameters = sslEncryptionParameters;
|
||||||
@@ -145,6 +151,21 @@ public class HttpClientFactory
|
|||||||
init();
|
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()
|
public void init()
|
||||||
{
|
{
|
||||||
this.sslKeyStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getKeyStoreParameters(), keyResourceLoader);
|
this.sslKeyStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getKeyStoreParameters(), keyResourceLoader);
|
||||||
@@ -272,10 +293,44 @@ public class HttpClientFactory
|
|||||||
this.connectionTimeout = connectionTimeout;
|
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();
|
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
|
||||||
HttpClient httpClient = new HttpClient(connectionManager);
|
RequestHeadersHttpClient httpClient = new RequestHeadersHttpClient(connectionManager);
|
||||||
HttpClientParams params = httpClient.getParams();
|
HttpClientParams params = httpClient.getParams();
|
||||||
params.setBooleanParameter(HttpConnectionParams.TCP_NODELAY, true);
|
params.setBooleanParameter(HttpConnectionParams.TCP_NODELAY, true);
|
||||||
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true);
|
params.setBooleanParameter(HttpConnectionParams.STALE_CONNECTION_CHECK, true);
|
||||||
@@ -291,15 +346,15 @@ public class HttpClientFactory
|
|||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpClient getHttpsClient()
|
protected RequestHeadersHttpClient getHttpsClient()
|
||||||
{
|
{
|
||||||
return getHttpsClient(host, sslPort);
|
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
|
// 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
|
// 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));
|
HttpHostFactory hostFactory = new HttpHostFactory(new Protocol("https", sslSocketFactory, HttpsURL.DEFAULT_PORT));
|
||||||
httpClient.setHostConfiguration(new HostConfigurationWithHostFactory(hostFactory));
|
httpClient.setHostConfiguration(new HostConfigurationWithHostFactory(hostFactory));
|
||||||
@@ -307,28 +362,54 @@ public class HttpClientFactory
|
|||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpClient getDefaultHttpClient()
|
protected RequestHeadersHttpClient getDefaultHttpClient()
|
||||||
{
|
{
|
||||||
return getDefaultHttpClient(host, port);
|
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);
|
httpClient.getHostConfiguration().setHost(httpHost, httpPort);
|
||||||
return httpClient;
|
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()
|
protected AlfrescoHttpClient getAlfrescoHttpsClient()
|
||||||
{
|
{
|
||||||
AlfrescoHttpClient repoClient = new HttpsClient(getHttpsClient());
|
return new HttpsClient(getHttpsClient());
|
||||||
return repoClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AlfrescoHttpClient getAlfrescoHttpClient()
|
protected AlfrescoHttpClient getAlfrescoHttpClient()
|
||||||
{
|
{
|
||||||
AlfrescoHttpClient repoClient = new DefaultHttpClient(getDefaultHttpClient());
|
return new DefaultHttpClient(getDefaultHttpClient());
|
||||||
return repoClient;
|
}
|
||||||
|
|
||||||
|
protected AlfrescoHttpClient getAlfrescoSharedSecretClient()
|
||||||
|
{
|
||||||
|
return new DefaultHttpClient(getSharedSecretHttpClient());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpClient getMD5HttpClient(String host, int port)
|
protected HttpClient getMD5HttpClient(String host, int port)
|
||||||
@@ -341,66 +422,37 @@ public class HttpClientFactory
|
|||||||
|
|
||||||
public AlfrescoHttpClient getRepoClient(String host, int port)
|
public AlfrescoHttpClient getRepoClient(String host, int port)
|
||||||
{
|
{
|
||||||
AlfrescoHttpClient repoClient = null;
|
switch (secureCommsType)
|
||||||
|
|
||||||
if(secureCommsType == SecureCommsType.HTTPS)
|
|
||||||
{
|
{
|
||||||
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)
|
}
|
||||||
|
|
||||||
|
public RequestHeadersHttpClient getHttpClient()
|
||||||
|
{
|
||||||
|
switch (secureCommsType)
|
||||||
{
|
{
|
||||||
repoClient = getAlfrescoHttpClient();
|
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
|
|
||||||
{
|
|
||||||
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(String host, int port)
|
||||||
{
|
{
|
||||||
HttpClient httpClient = null;
|
switch (secureCommsType)
|
||||||
|
|
||||||
if(secureCommsType == SecureCommsType.HTTPS)
|
|
||||||
{
|
{
|
||||||
httpClient = getHttpsClient();
|
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();
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
HttpClient httpClient = null;
|
|
||||||
|
|
||||||
if(secureCommsType == SecureCommsType.HTTPS)
|
|
||||||
{
|
|
||||||
httpClient = getHttpsClient(host, port);
|
|
||||||
}
|
|
||||||
else if(secureCommsType == SecureCommsType.NONE)
|
|
||||||
{
|
|
||||||
httpClient = getDefaultHttpClient(host, port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new AlfrescoRuntimeException("Invalid Solr secure communications type configured in alfresco.secureComms, should be 'ssl'or 'none'");
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A secure client connection to the repository.
|
* 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>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@@ -9,6 +9,6 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
6
pom.xml
6
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">
|
<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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>Alfresco Community Repo Parent</name>
|
<name>Alfresco Community Repo Parent</name>
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<acs.version.major>7</acs.version.major>
|
<acs.version.major>7</acs.version.major>
|
||||||
<acs.version.minor>0</acs.version.minor>
|
<acs.version.minor>0</acs.version.minor>
|
||||||
<acs.version.revision>0</acs.version.revision>
|
<acs.version.revision>1</acs.version.revision>
|
||||||
<acs.version.label />
|
<acs.version.label />
|
||||||
|
|
||||||
<version.edition>Community</version.edition>
|
<version.edition>Community</version.edition>
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
|
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
|
||||||
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
|
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
|
||||||
<url>https://github.com/Alfresco/alfresco-community-repo</url>
|
<url>https://github.com/Alfresco/alfresco-community-repo</url>
|
||||||
<tag>HEAD</tag>
|
<tag>9.8</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@@ -25,21 +25,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.web.scripts.solr;
|
package org.alfresco.repo.web.scripts.solr;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.httpclient.HttpClientFactory;
|
||||||
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;
|
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -88,9 +85,7 @@ public class SOLRAuthenticationFilter implements DependencyInjectedFilter, Initi
|
|||||||
|
|
||||||
private String sharedSecret;
|
private String sharedSecret;
|
||||||
|
|
||||||
private String sharedSecretHeader = DEFAULT_SHAREDSECRET_HEADER;
|
private String sharedSecretHeader = HttpClientFactory.DEFAULT_SHAREDSECRET_HEADER;
|
||||||
|
|
||||||
private static final String DEFAULT_SHAREDSECRET_HEADER = "X-Alfresco-Search-Secret";
|
|
||||||
|
|
||||||
public void setSecureComms(String type)
|
public void setSecureComms(String type)
|
||||||
{
|
{
|
||||||
|
@@ -31,6 +31,7 @@ import java.util.Properties;
|
|||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.alfresco.httpclient.HttpClientFactory.SecureCommsType;
|
||||||
import org.alfresco.web.scripts.servlet.X509ServletFilterBase;
|
import org.alfresco.web.scripts.servlet.X509ServletFilterBase;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.
|
* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.alfresco</groupId>
|
<groupId>org.alfresco</groupId>
|
||||||
<artifactId>alfresco-community-repo</artifactId>
|
<artifactId>alfresco-community-repo</artifactId>
|
||||||
<version>8.424-SNAPSHOT</version>
|
<version>9.8</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@@ -40,6 +40,7 @@ public class IdsEntity
|
|||||||
private Long idThree;
|
private Long idThree;
|
||||||
private Long idFour;
|
private Long idFour;
|
||||||
private List<Long> ids;
|
private List<Long> ids;
|
||||||
|
private boolean ordered;
|
||||||
public Long getIdOne()
|
public Long getIdOne()
|
||||||
{
|
{
|
||||||
return idOne;
|
return idOne;
|
||||||
@@ -80,4 +81,12 @@ public class IdsEntity
|
|||||||
{
|
{
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
}
|
}
|
||||||
|
public boolean isOrdered()
|
||||||
|
{
|
||||||
|
return ordered;
|
||||||
|
}
|
||||||
|
public void setOrdered(boolean ordered)
|
||||||
|
{
|
||||||
|
this.ordered = ordered;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1483,7 +1483,17 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
|
|
||||||
// Update ACLs for moved tree
|
// Update ACLs for moved tree
|
||||||
Long newParentAclId = newParentNode.getAclId();
|
Long newParentAclId = newParentNode.getAclId();
|
||||||
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
|
|
||||||
|
// Verify if parent has aspect applied and ACL's are pending
|
||||||
|
if (hasNodeAspect(oldParentNodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
|
||||||
|
{
|
||||||
|
Long oldParentSharedAclId = (Long) this.getNodeProperty(oldParentNodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
||||||
|
accessControlListDAO.updateInheritance(newChildNodeId, oldParentSharedAclId, newParentAclId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accessControlListDAO.updateInheritance(newChildNodeId, oldParentAclId, newParentAclId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
@@ -2746,6 +2756,22 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
selectNodesWithAspects(qnameIds, minNodeId, maxNodeId, resultsCallback);
|
selectNodesWithAspects(qnameIds, minNodeId, maxNodeId, resultsCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getNodesWithAspects(
|
||||||
|
Set<QName> aspectQNames,
|
||||||
|
Long minNodeId, Long maxNodeId, boolean ordered,
|
||||||
|
NodeRefQueryCallback resultsCallback)
|
||||||
|
{
|
||||||
|
Set<Long> qnameIdsSet = qnameDAO.convertQNamesToIds(aspectQNames, false);
|
||||||
|
if (qnameIdsSet.size() == 0)
|
||||||
|
{
|
||||||
|
// No point running a query
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Long> qnameIds = new ArrayList<Long>(qnameIdsSet);
|
||||||
|
selectNodesWithAspects(qnameIds, minNodeId, maxNodeId, ordered, resultsCallback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns a writable copy of the cached aspects set
|
* @return Returns a writable copy of the cached aspects set
|
||||||
*/
|
*/
|
||||||
@@ -4917,6 +4943,10 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
List<Long> qnameIds,
|
List<Long> qnameIds,
|
||||||
Long minNodeId, Long maxNodeId,
|
Long minNodeId, Long maxNodeId,
|
||||||
NodeRefQueryCallback resultsCallback);
|
NodeRefQueryCallback resultsCallback);
|
||||||
|
protected abstract void selectNodesWithAspects(
|
||||||
|
List<Long> qnameIds,
|
||||||
|
Long minNodeId, Long maxNodeId, boolean ordered,
|
||||||
|
NodeRefQueryCallback resultsCallback);
|
||||||
protected abstract Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex);
|
protected abstract Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex);
|
||||||
protected abstract int updateNodeAssoc(Long id, int assocIndex);
|
protected abstract int updateNodeAssoc(Long id, int assocIndex);
|
||||||
protected abstract int deleteNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId);
|
protected abstract int deleteNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId);
|
||||||
|
@@ -405,6 +405,20 @@ public interface NodeDAO extends NodeBulkLoader
|
|||||||
Long minNodeId, Long maxNodeId,
|
Long minNodeId, Long maxNodeId,
|
||||||
NodeRefQueryCallback resultsCallback);
|
NodeRefQueryCallback resultsCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get nodes with aspects between the given ranges, ordering the results optionally
|
||||||
|
*
|
||||||
|
* @param aspectQNames the aspects that must be on the nodes
|
||||||
|
* @param minNodeId the minimum node ID (inclusive)
|
||||||
|
* @param maxNodeId the maximum node ID (exclusive)
|
||||||
|
* @param ordered if the results are to be ordered by nodeID
|
||||||
|
* @param resultsCallback callback to process results
|
||||||
|
*/
|
||||||
|
public void getNodesWithAspects(
|
||||||
|
Set<QName> aspectQNames,
|
||||||
|
Long minNodeId, Long maxNodeId, boolean ordered,
|
||||||
|
NodeRefQueryCallback resultsCallback);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Node Assocs
|
* Node Assocs
|
||||||
*/
|
*/
|
||||||
|
@@ -764,6 +764,31 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
template.select(SELECT_NODES_WITH_ASPECT_IDS, parameters, resultHandler);
|
template.select(SELECT_NODES_WITH_ASPECT_IDS, parameters, resultHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void selectNodesWithAspects(
|
||||||
|
List<Long> qnameIds,
|
||||||
|
Long minNodeId, Long maxNodeId, boolean ordered,
|
||||||
|
final NodeRefQueryCallback resultsCallback)
|
||||||
|
{
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
ResultHandler resultHandler = new ResultHandler()
|
||||||
|
{
|
||||||
|
public void handleResult(ResultContext context)
|
||||||
|
{
|
||||||
|
NodeEntity entity = (NodeEntity) context.getResultObject();
|
||||||
|
Pair<Long, NodeRef> nodePair = new Pair<Long, NodeRef>(entity.getId(), entity.getNodeRef());
|
||||||
|
resultsCallback.handle(nodePair);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IdsEntity parameters = new IdsEntity();
|
||||||
|
parameters.setIdOne(minNodeId);
|
||||||
|
parameters.setIdTwo(maxNodeId);
|
||||||
|
parameters.setIds(qnameIds);
|
||||||
|
parameters.setOrdered(ordered);
|
||||||
|
template.select(SELECT_NODES_WITH_ASPECT_IDS, parameters, resultHandler);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex)
|
protected Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId, int assocIndex)
|
||||||
{
|
{
|
||||||
|
@@ -337,6 +337,13 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false, asyncCall, true);
|
setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false, asyncCall, true);
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall, boolean forceSharedACL)
|
||||||
|
{
|
||||||
|
List<AclChange> changes = new ArrayList<AclChange>();
|
||||||
|
setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false, asyncCall, true, forceSharedACL);
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateChangedAcls(NodeRef startingPoint, List<AclChange> changes)
|
public void updateChangedAcls(NodeRef startingPoint, List<AclChange> changes)
|
||||||
{
|
{
|
||||||
@@ -362,6 +369,29 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, false, true);
|
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support to set a shared ACL on a node and all of its children
|
||||||
|
*
|
||||||
|
* @param nodeId
|
||||||
|
* the parent node
|
||||||
|
* @param inheritFrom
|
||||||
|
* the parent node's ACL
|
||||||
|
* @param mergeFrom
|
||||||
|
* the shared ACL, if already known. If <code>null</code>, will be retrieved / created lazily
|
||||||
|
* @param changes
|
||||||
|
* the list in which to record changes
|
||||||
|
* @param set
|
||||||
|
* set the shared ACL on the parent ?
|
||||||
|
* @param asyncCall
|
||||||
|
* function may require asynchronous call depending the execution time; if time exceeds configured <code>fixedAclMaxTransactionTime</code> value,
|
||||||
|
* recursion is stopped using propagateOnChildren parameter(set on false) and those nodes for which the method execution was not finished
|
||||||
|
* in the classical way, will have ASPECT_PENDING_FIX_ACL, which will be used in {@link FixedAclUpdater} for later processing
|
||||||
|
*/
|
||||||
|
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
|
||||||
|
{
|
||||||
|
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, false, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support to set a shared ACL on a node and all of its children
|
* Support to set a shared ACL on a node and all of its children
|
||||||
*
|
*
|
||||||
@@ -379,8 +409,10 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
* function may require asynchronous call depending the execution time; if time exceeds configured <code>fixedAclMaxTransactionTime</code> value,
|
* function may require asynchronous call depending the execution time; if time exceeds configured <code>fixedAclMaxTransactionTime</code> value,
|
||||||
* recursion is stopped using propagateOnChildren parameter(set on false) and those nodes for which the method execution was not finished
|
* recursion is stopped using propagateOnChildren parameter(set on false) and those nodes for which the method execution was not finished
|
||||||
* in the classical way, will have ASPECT_PENDING_FIX_ACL, which will be used in {@link FixedAclUpdater} for later processing
|
* in the classical way, will have ASPECT_PENDING_FIX_ACL, which will be used in {@link FixedAclUpdater} for later processing
|
||||||
|
* @param forceSharedACL
|
||||||
|
* When a child node has an unexpected ACL, force it to assume the new shared ACL instead of throwing a concurrency exception.
|
||||||
*/
|
*/
|
||||||
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
|
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren, boolean forceSharedACL)
|
||||||
{
|
{
|
||||||
if (log.isDebugEnabled())
|
if (log.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@@ -431,14 +463,14 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
|
|
||||||
if (acl == null)
|
if (acl == null)
|
||||||
{
|
{
|
||||||
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
|
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren, forceSharedACL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Still has old shared ACL or already replaced
|
// Still has old shared ACL or already replaced
|
||||||
if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom) || acl.equals(currentAcl))
|
if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom) || acl.equals(currentAcl))
|
||||||
{
|
{
|
||||||
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
|
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren, forceSharedACL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -457,7 +489,20 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
else if (dbAcl.getAclType() == ACLType.SHARED)
|
else if (dbAcl.getAclType() == ACLType.SHARED)
|
||||||
{
|
{
|
||||||
throw new ConcurrencyFailureException("setFixedAcls: unexpected shared acl: "+dbAcl);
|
if (forceSharedACL)
|
||||||
|
{
|
||||||
|
log.warn("Forcing shared ACL on node: " + child.getId() + " ( "
|
||||||
|
+ nodeDAO.getNodePair(child.getId()).getSecond() + ") - " + dbAcl);
|
||||||
|
sharedAclToReplace = acl;
|
||||||
|
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace,
|
||||||
|
changes, false, asyncCall, propagateOnChildren, forceSharedACL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ConcurrencyFailureException(
|
||||||
|
"setFixedAcls: unexpected shared acl: " + dbAcl + " on node " + child.getId() + " ( "
|
||||||
|
+ nodeDAO.getNodePair(child.getId()).getSecond() + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,7 +551,7 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private boolean setFixAclPending(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace,
|
private boolean setFixAclPending(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace,
|
||||||
List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren)
|
List<AclChange> changes, boolean set, boolean asyncCall, boolean propagateOnChildren, boolean forceSharedACL)
|
||||||
{
|
{
|
||||||
// check transaction time
|
// check transaction time
|
||||||
long transactionStartTime = AlfrescoTransactionSupport.getTransactionStartTime();
|
long transactionStartTime = AlfrescoTransactionSupport.getTransactionStartTime();
|
||||||
@@ -514,7 +559,7 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
if (transactionTime < fixedAclMaxTransactionTime)
|
if (transactionTime < fixedAclMaxTransactionTime)
|
||||||
{
|
{
|
||||||
// make regular method call if time is under max transaction configured time
|
// make regular method call if time is under max transaction configured time
|
||||||
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren);
|
setFixedAcls(nodeId, inheritFrom, mergeFrom, sharedAclToReplace, changes, set, asyncCall, propagateOnChildren, forceSharedACL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -91,6 +91,11 @@ public interface AccessControlListDAO
|
|||||||
*/
|
*/
|
||||||
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall);
|
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the inheritance on a given node and it's children. If an unexpected ACL occurs in a child, it can be overriden by setting forceSharedACL
|
||||||
|
*/
|
||||||
|
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace, boolean asyncCall, boolean forceSharedACL);
|
||||||
|
|
||||||
public Long getIndirectAcl(NodeRef nodeRef);
|
public Long getIndirectAcl(NodeRef nodeRef);
|
||||||
|
|
||||||
public Long getInheritedAcl(NodeRef nodeRef);
|
public Long getInheritedAcl(NodeRef nodeRef);
|
||||||
|
@@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||||
import org.alfresco.repo.batch.BatchProcessor;
|
import org.alfresco.repo.batch.BatchProcessor;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||||
import org.alfresco.repo.domain.node.NodeDAO;
|
import org.alfresco.repo.domain.node.NodeDAO;
|
||||||
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
|
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
|
||||||
import org.alfresco.repo.lock.JobLockService;
|
import org.alfresco.repo.lock.JobLockService;
|
||||||
@@ -50,6 +51,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
|||||||
import org.alfresco.repo.security.permissions.PermissionServicePolicies;
|
import org.alfresco.repo.security.permissions.PermissionServicePolicies;
|
||||||
import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled;
|
import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -64,6 +66,8 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds nodes with ASPECT_PENDING_FIX_ACL aspect and sets fixed ACLs for them
|
* Finds nodes with ASPECT_PENDING_FIX_ACL aspect and sets fixed ACLs for them
|
||||||
@@ -91,6 +95,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
|
|
||||||
private int maxItemBatchSize = 100;
|
private int maxItemBatchSize = 100;
|
||||||
private int numThreads = 4;
|
private int numThreads = 4;
|
||||||
|
private boolean forceSharedACL = false;
|
||||||
|
|
||||||
private ClassPolicyDelegate<OnInheritPermissionsDisabled> onInheritPermissionsDisabledDelegate;
|
private ClassPolicyDelegate<OnInheritPermissionsDisabled> onInheritPermissionsDisabledDelegate;
|
||||||
private PolicyComponent policyComponent;
|
private PolicyComponent policyComponent;
|
||||||
@@ -132,6 +137,11 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
this.maxItemBatchSize = maxItemBatchSize;
|
this.maxItemBatchSize = maxItemBatchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setForceSharedACL(boolean forceSharedACL)
|
||||||
|
{
|
||||||
|
this.forceSharedACL = forceSharedACL;
|
||||||
|
}
|
||||||
|
|
||||||
public void setLockTimeToLive(long lockTimeToLive)
|
public void setLockTimeToLive(long lockTimeToLive)
|
||||||
{
|
{
|
||||||
this.lockTimeToLive = lockTimeToLive;
|
this.lockTimeToLive = lockTimeToLive;
|
||||||
@@ -182,7 +192,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
public List<NodeRef> execute() throws Throwable
|
public List<NodeRef> execute() throws Throwable
|
||||||
{
|
{
|
||||||
getNodesCallback.init();
|
getNodesCallback.init();
|
||||||
nodeDAO.getNodesWithAspects(aspects, getNodesCallback.getMinNodeId(), null, getNodesCallback);
|
nodeDAO.getNodesWithAspects(aspects, getNodesCallback.getMinNodeId(), null, true, getNodesCallback);
|
||||||
getNodesCallback.done();
|
getNodesCallback.done();
|
||||||
|
|
||||||
return getNodesCallback.getNodes();
|
return getNodesCallback.getNodes();
|
||||||
@@ -253,7 +263,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(final NodeRef nodeRef) throws Throwable
|
public void process(final NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
RunAsWork<Void> findAndUpdateAclRunAsWork = new RunAsWork<Void>()
|
RunAsWork<Void> findAndUpdateAclRunAsWork = new RunAsWork<Void>()
|
||||||
{
|
{
|
||||||
@@ -265,34 +275,44 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
log.debug(String.format("Processing node %s", nodeRef));
|
log.debug(String.format("Processing node %s", nodeRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
|
try
|
||||||
|
|
||||||
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do not
|
|
||||||
// process
|
|
||||||
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
|
|
||||||
{
|
{
|
||||||
|
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
|
||||||
|
|
||||||
|
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do
|
||||||
|
// not
|
||||||
|
// process
|
||||||
|
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
|
||||||
|
{
|
||||||
|
accessControlListDAO.removePendingAclAspect(nodeId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve acl properties from node
|
||||||
|
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
|
||||||
|
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
||||||
|
|
||||||
|
// set inheritance using retrieved prop
|
||||||
|
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true,
|
||||||
|
forceSharedACL);
|
||||||
|
|
||||||
|
// Remove aspect
|
||||||
accessControlListDAO.removePendingAclAspect(nodeId);
|
accessControlListDAO.removePendingAclAspect(nodeId);
|
||||||
return null;
|
|
||||||
|
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
|
||||||
|
{
|
||||||
|
boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport
|
||||||
|
.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
|
||||||
|
|
||||||
|
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
|
||||||
|
.get(ContentModel.TYPE_BASE);
|
||||||
|
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
// retrieve acl properties from node
|
|
||||||
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
|
|
||||||
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
|
||||||
|
|
||||||
// set inheritance using retrieved prop
|
|
||||||
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true);
|
|
||||||
|
|
||||||
// Remove aspect
|
|
||||||
accessControlListDAO.removePendingAclAspect(nodeId);
|
|
||||||
|
|
||||||
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
|
|
||||||
{
|
{
|
||||||
boolean transformedToAsyncOperation = toBoolean(
|
log.error("Job could not process pending ACL node " + nodeRef + ": " + e);
|
||||||
(Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
|
e.printStackTrace();
|
||||||
|
|
||||||
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
|
|
||||||
.get(ContentModel.TYPE_BASE);
|
|
||||||
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.isDebugEnabled())
|
if (log.isDebugEnabled())
|
||||||
@@ -308,6 +328,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
AuthenticationUtil.runAs(findAndUpdateAclRunAsWork, AuthenticationUtil.getSystemUserName());
|
AuthenticationUtil.runAs(findAndUpdateAclRunAsWork, AuthenticationUtil.getSystemUserName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private class GetNodesWithAspectCallback implements NodeRefQueryCallback
|
private class GetNodesWithAspectCallback implements NodeRefQueryCallback
|
||||||
{
|
{
|
||||||
|
@@ -54,7 +54,6 @@ import org.alfresco.repo.policy.JavaBehaviour;
|
|||||||
import org.alfresco.repo.policy.PolicyComponent;
|
import org.alfresco.repo.policy.PolicyComponent;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
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.dictionary.DictionaryService;
|
||||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
@@ -90,11 +89,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
protected DictionaryService dictionaryService;
|
protected DictionaryService dictionaryService;
|
||||||
private DescriptorService descriptorService;
|
private DescriptorService descriptorService;
|
||||||
private EventFilterRegistry eventFilterRegistry;
|
private EventFilterRegistry eventFilterRegistry;
|
||||||
private Event2MessageProducer event2MessageProducer;
|
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
private PersonService personService;
|
private PersonService personService;
|
||||||
protected NodeResourceHelper nodeResourceHelper;
|
protected NodeResourceHelper nodeResourceHelper;
|
||||||
|
|
||||||
|
private EventGeneratorQueue eventGeneratorQueue;
|
||||||
private NodeTypeFilter nodeTypeFilter;
|
private NodeTypeFilter nodeTypeFilter;
|
||||||
private ChildAssociationTypeFilter childAssociationTypeFilter;
|
private ChildAssociationTypeFilter childAssociationTypeFilter;
|
||||||
private EventUserFilter userFilter;
|
private EventUserFilter userFilter;
|
||||||
@@ -109,10 +108,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
|
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
|
||||||
PropertyCheck.mandatory(this, "descriptorService", descriptorService);
|
PropertyCheck.mandatory(this, "descriptorService", descriptorService);
|
||||||
PropertyCheck.mandatory(this, "eventFilterRegistry", eventFilterRegistry);
|
PropertyCheck.mandatory(this, "eventFilterRegistry", eventFilterRegistry);
|
||||||
PropertyCheck.mandatory(this, "event2MessageProducer", event2MessageProducer);
|
|
||||||
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
||||||
PropertyCheck.mandatory(this, "personService", personService);
|
PropertyCheck.mandatory(this, "personService", personService);
|
||||||
PropertyCheck.mandatory(this, "nodeResourceHelper", nodeResourceHelper);
|
PropertyCheck.mandatory(this, "nodeResourceHelper", nodeResourceHelper);
|
||||||
|
PropertyCheck.mandatory(this, "eventGeneratorQueue", eventGeneratorQueue);
|
||||||
|
|
||||||
this.nodeTypeFilter = eventFilterRegistry.getNodeTypeFilter();
|
this.nodeTypeFilter = eventFilterRegistry.getNodeTypeFilter();
|
||||||
this.childAssociationTypeFilter = eventFilterRegistry.getChildAssociationTypeFilter();
|
this.childAssociationTypeFilter = eventFilterRegistry.getChildAssociationTypeFilter();
|
||||||
@@ -177,12 +176,6 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
this.eventFilterRegistry = eventFilterRegistry;
|
this.eventFilterRegistry = eventFilterRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public void setEvent2MessageProducer(Event2MessageProducer event2MessageProducer)
|
|
||||||
{
|
|
||||||
this.event2MessageProducer = event2MessageProducer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTransactionService(TransactionService transactionService)
|
public void setTransactionService(TransactionService transactionService)
|
||||||
{
|
{
|
||||||
this.transactionService = transactionService;
|
this.transactionService = transactionService;
|
||||||
@@ -198,6 +191,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
this.nodeResourceHelper = nodeResourceHelper;
|
this.nodeResourceHelper = nodeResourceHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEventGeneratorQueue(EventGeneratorQueue eventGeneratorQueue)
|
||||||
|
{
|
||||||
|
this.eventGeneratorQueue = eventGeneratorQueue;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
{
|
{
|
||||||
@@ -428,20 +426,26 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
|
|
||||||
protected void sendEvent(NodeRef nodeRef, EventConsolidator consolidator)
|
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 (consolidator.isTemporaryNode())
|
||||||
{
|
{
|
||||||
if (LOGGER.isTraceEnabled())
|
if (LOGGER.isTraceEnabled())
|
||||||
{
|
{
|
||||||
LOGGER.trace("Ignoring temporary node: " + nodeRef);
|
LOGGER.trace("Ignoring temporary node: " + nodeRef);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
||||||
// Get the repo event before the filtering,
|
// Get the repo event before the filtering,
|
||||||
// so we can take the latest node info into account
|
// 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();
|
final QName nodeType = consolidator.getNodeType();
|
||||||
if (isFiltered(nodeType, user))
|
if (isFiltered(nodeType, user))
|
||||||
@@ -452,7 +456,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
+ ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString())
|
+ ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString())
|
||||||
+ "' created by: " + user);
|
+ "' created by: " + user);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType().equals(EventType.NODE_UPDATED.getType()) && consolidator.isResourceBeforeAllFieldsNull())
|
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);
|
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)
|
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 (consolidator.isTemporaryChildAssociation())
|
||||||
{
|
{
|
||||||
if (LOGGER.isTraceEnabled())
|
if (LOGGER.isTraceEnabled())
|
||||||
{
|
{
|
||||||
LOGGER.trace("Ignoring temporary child association: " + childAssociationRef);
|
LOGGER.trace("Ignoring temporary child association: " + childAssociationRef);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
||||||
// Get the repo event before the filtering,
|
// Get the repo event before the filtering,
|
||||||
// so we can take the latest association info into account
|
// 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();
|
final QName childAssocType = consolidator.getChildAssocType();
|
||||||
if (isFilteredChildAssociation(childAssocType, user))
|
if (isFilteredChildAssociation(childAssocType, user))
|
||||||
@@ -492,7 +503,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
||||||
+ "' created by: " + user);
|
+ "' created by: " + user);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
} else if (childAssociationRef.isPrimary())
|
} else if (childAssociationRef.isPrimary())
|
||||||
{
|
{
|
||||||
if (LOGGER.isTraceEnabled())
|
if (LOGGER.isTraceEnabled())
|
||||||
@@ -501,13 +512,20 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
|
||||||
+ "' created by: " + user);
|
+ "' created by: " + user);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
logAndSendEvent(event, consolidator.getEventTypes());
|
logEvent(event, consolidator.getEventTypes());
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendEvent(AssociationRef peerAssociationRef, PeerAssociationEventConsolidator consolidator)
|
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())
|
if (consolidator.isTemporaryPeerAssociation())
|
||||||
{
|
{
|
||||||
@@ -515,30 +533,21 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
|||||||
{
|
{
|
||||||
LOGGER.trace("Ignoring temporary peer association: " + peerAssociationRef);
|
LOGGER.trace("Ignoring temporary peer association: " + peerAssociationRef);
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
RepoEvent<?> event = consolidator.getRepoEvent(eventInfo);
|
||||||
// Get the repo event before the filtering,
|
logEvent(event, consolidator.getEventTypes());
|
||||||
// so we can take the latest association info into account
|
return event;
|
||||||
final RepoEvent<?> event = consolidator.getRepoEvent(getEventInfo(user));
|
|
||||||
|
|
||||||
logAndSendEvent(event, consolidator.getEventTypes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void logAndSendEvent(RepoEvent<?> event, Deque<EventType> listOfEvents)
|
private void logEvent(RepoEvent<?> event, Deque<EventType> listOfEvents)
|
||||||
{
|
{
|
||||||
if (LOGGER.isTraceEnabled())
|
if (LOGGER.isTraceEnabled())
|
||||||
{
|
{
|
||||||
LOGGER.trace("List of Events:" + listOfEvents);
|
LOGGER.trace("List of Events:" + listOfEvents);
|
||||||
LOGGER.trace("Sending event:" + event);
|
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
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* 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 java.util.StringJoiner;
|
||||||
|
|
||||||
import static org.alfresco.repo.content.MimetypeMap.MIMETYPE_PDF;
|
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_ENLARGEMENT;
|
||||||
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALLOW_PDF_ENLARGEMENT;
|
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALLOW_PDF_ENLARGEMENT;
|
||||||
import static org.alfresco.repo.rendition2.RenditionDefinition2.ALPHA_REMOVE;
|
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.addAll(RESIZE_OPTIONS);
|
||||||
IMAGE_OPTIONS.add(AUTO_ORIENT);
|
IMAGE_OPTIONS.add(AUTO_ORIENT);
|
||||||
IMAGE_OPTIONS.add(ALPHA_REMOVE);
|
IMAGE_OPTIONS.add(ALPHA_REMOVE);
|
||||||
|
IMAGE_OPTIONS.add(OPT_COMMAND_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> PDF_OPTIONS = new HashSet<>(Arrays.asList(new String[]
|
private static Set<String> PDF_OPTIONS = new HashSet<>(Arrays.asList(new String[]
|
||||||
@@ -284,6 +286,8 @@ public class TransformationOptionsConverter implements InitializingBean
|
|||||||
}
|
}
|
||||||
opts.setSourceOptionsList(sourceOptionsList);
|
opts.setSourceOptionsList(sourceOptionsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifSet(options, OPT_COMMAND_OPTIONS, (v) -> opts.setCommandOptions(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -361,13 +365,11 @@ public class TransformationOptionsConverter implements InitializingBean
|
|||||||
{
|
{
|
||||||
ImageTransformationOptions opts = (ImageTransformationOptions) options;
|
ImageTransformationOptions opts = (ImageTransformationOptions) options;
|
||||||
|
|
||||||
// TODO We don't support this any more for security reasons, however it might be possible to
|
// From a security viewpoint it would be better not to support the option of passing anything to
|
||||||
// extract some of the well know values and add them to the newer ImageMagick transform options.
|
// 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();
|
String commandOptions = opts.getCommandOptions();
|
||||||
if (commandOptions != null && !commandOptions.isBlank())
|
ifSet(commandOptions != null && !commandOptions.isBlank(), map, OPT_COMMAND_OPTIONS, commandOptions);
|
||||||
{
|
|
||||||
logger.error("ImageMagick commandOptions are no longer supported for security reasons: " + commandOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageResizeOptions imageResizeOptions = opts.getResizeOptions();
|
ImageResizeOptions imageResizeOptions = opts.getResizeOptions();
|
||||||
if (imageResizeOptions != null)
|
if (imageResizeOptions != null)
|
||||||
|
@@ -38,9 +38,10 @@
|
|||||||
<property name="dictionaryService" ref="dictionaryService"/>
|
<property name="dictionaryService" ref="dictionaryService"/>
|
||||||
<property name="descriptorService" ref="descriptorComponent"/>
|
<property name="descriptorService" ref="descriptorComponent"/>
|
||||||
<property name="eventFilterRegistry" ref="event2FilterRegistry"/>
|
<property name="eventFilterRegistry" ref="event2FilterRegistry"/>
|
||||||
<property name="event2MessageProducer" ref="event2MessageProducer"/>
|
|
||||||
<property name="transactionService" ref="transactionService"/>
|
<property name="transactionService" ref="transactionService"/>
|
||||||
<property name="personService" ref="personService"/>
|
<property name="personService" ref="personService"/>
|
||||||
|
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
|
||||||
|
<property name="eventGeneratorQueue" ref="eventGeneratorQueue"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="baseNodeResourceHelper" abstract="true">
|
<bean id="baseNodeResourceHelper" abstract="true">
|
||||||
@@ -54,7 +55,45 @@
|
|||||||
|
|
||||||
<bean id="nodeResourceHelper" class="org.alfresco.repo.event2.NodeResourceHelper" parent="baseNodeResourceHelper"/>
|
<bean id="nodeResourceHelper" class="org.alfresco.repo.event2.NodeResourceHelper" parent="baseNodeResourceHelper"/>
|
||||||
|
|
||||||
<bean id="eventGeneratorV2" class="org.alfresco.repo.event2.EventGenerator" parent="baseEventGeneratorV2">
|
<bean id="eventGeneratorV2" class="org.alfresco.repo.event2.EventGenerator" parent="baseEventGeneratorV2"/>
|
||||||
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
|
|
||||||
|
<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>
|
</bean>
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -779,6 +779,7 @@
|
|||||||
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
|
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
|
||||||
and na.qname_id in
|
and na.qname_id in
|
||||||
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
|
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
|
||||||
|
<if test="ordered == true">order by node.id ASC</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- Common results for result_NodeAssoc -->
|
<!-- Common results for result_NodeAssoc -->
|
||||||
|
@@ -117,6 +117,7 @@
|
|||||||
<property name="nodeDAO" ref="nodeDAO"/>
|
<property name="nodeDAO" ref="nodeDAO"/>
|
||||||
<property name="maxItemBatchSize" value="${system.fixedACLsUpdater.maxItemBatchSize}"/>
|
<property name="maxItemBatchSize" value="${system.fixedACLsUpdater.maxItemBatchSize}"/>
|
||||||
<property name="numThreads" value="${system.fixedACLsUpdater.numThreads}"/>
|
<property name="numThreads" value="${system.fixedACLsUpdater.numThreads}"/>
|
||||||
|
<property name="forceSharedACL" value="${system.fixedACLsUpdater.forceSharedACL}"/>
|
||||||
<property name="lockTimeToLive" value="${system.fixedACLsUpdater.lockTTL}"/>
|
<property name="lockTimeToLive" value="${system.fixedACLsUpdater.lockTTL}"/>
|
||||||
<property name="policyComponent" ref="policyComponent"/>
|
<property name="policyComponent" ref="policyComponent"/>
|
||||||
<property name="policyIgnoreUtil" ref="policyIgnoreUtil"/>
|
<property name="policyIgnoreUtil" ref="policyIgnoreUtil"/>
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
repository.name=Main Repository
|
repository.name=Main Repository
|
||||||
|
|
||||||
# Schema number
|
# Schema number
|
||||||
version.schema=14002
|
version.schema=14100
|
||||||
|
|
||||||
# Directory configuration
|
# Directory configuration
|
||||||
|
|
||||||
@@ -1082,6 +1082,8 @@ system.fixedACLsUpdater.lockTTL=10000
|
|||||||
system.fixedACLsUpdater.maxItemBatchSize=100
|
system.fixedACLsUpdater.maxItemBatchSize=100
|
||||||
# fixedACLsUpdater - the number of threads to use
|
# fixedACLsUpdater - the number of threads to use
|
||||||
system.fixedACLsUpdater.numThreads=4
|
system.fixedACLsUpdater.numThreads=4
|
||||||
|
# fixedACLsUpdater - Force shared ACL to propagate through children even if there is an unexpected ACL
|
||||||
|
system.fixedACLsUpdater.forceSharedACL=false
|
||||||
# fixedACLsUpdater cron expression - fire at midnight every day
|
# fixedACLsUpdater cron expression - fire at midnight every day
|
||||||
system.fixedACLsUpdater.cronExpression=0 0 0 * * ?
|
system.fixedACLsUpdater.cronExpression=0 0 0 * * ?
|
||||||
|
|
||||||
@@ -1207,6 +1209,15 @@ repo.event2.filter.childAssocTypes=rn:rendition
|
|||||||
repo.event2.filter.users=System, null
|
repo.event2.filter.users=System, null
|
||||||
# Topic name
|
# Topic name
|
||||||
repo.event2.topic.endpoint=amqp:topic:alfresco.repo.event2
|
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
|
# MNT-21083
|
||||||
# --DELETE_NOT_EXISTS - default settings
|
# --DELETE_NOT_EXISTS - default settings
|
||||||
|
@@ -165,6 +165,8 @@
|
|||||||
<property name="keyResourceLoader" ref="springKeyResourceLoader"/>
|
<property name="keyResourceLoader" ref="springKeyResourceLoader"/>
|
||||||
<property name="keyStoreParameters" ref="keyStoreParameters"/>
|
<property name="keyStoreParameters" ref="keyStoreParameters"/>
|
||||||
<property name="encryptionParameters" ref="md5EncryptionParameters"/>
|
<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="host" value="${solr.host}"/>
|
||||||
<property name="port" value="${solr.port}"/>
|
<property name="port" value="${solr.port}"/>
|
||||||
<property name="sslPort" value="${solr.port.ssl}"/>
|
<property name="sslPort" value="${solr.port.ssl}"/>
|
||||||
|
@@ -90,8 +90,8 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
private CheckOutCheckInService checkOutCheckInService;
|
private CheckOutCheckInService checkOutCheckInService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private AuthorityService authorityService;
|
private AuthorityService authorityService;
|
||||||
private static final long MAX_TRANSACTION_TIME_DEFAULT = 50;
|
private static final long MAX_TRANSACTION_TIME_DEFAULT = 10;
|
||||||
private static final int[] filesPerLevelMoreFolders = { 5, 3, 1, 50 };
|
private static final int[] filesPerLevelMoreFolders = { 5, 1, 1, 1, 1, 1, 1 };
|
||||||
private static final int[] filesPerLevelMoreFiles = { 5, 100 };
|
private static final int[] filesPerLevelMoreFiles = { 5, 100 };
|
||||||
private long maxTransactionTime;
|
private long maxTransactionTime;
|
||||||
private static HashMap<Integer, Class<?>> errors;
|
private static HashMap<Integer, Class<?>> errors;
|
||||||
@@ -306,7 +306,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testSyncCopyNoTimeOut() throws FileExistsException, FileNotFoundException
|
public void testSyncCopyNoTimeOut() throws FileExistsException, FileNotFoundException
|
||||||
{
|
{
|
||||||
NodeRef originalRef = createFolderHierarchyInRootForFolderTests("originFolder");
|
NodeRef originalRef = createFolderHierarchyInRootForFolderTests("originFolder");
|
||||||
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("targetFolder");
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("targetFolder");
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
// Get ACLS for later comparison
|
||||||
ACLComparator aclComparatorOrigin = new ACLComparator(originalRef);
|
ACLComparator aclComparatorOrigin = new ACLComparator(originalRef);
|
||||||
@@ -316,6 +316,19 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
maxTransactionTime = 86400000;
|
maxTransactionTime = 86400000;
|
||||||
setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
|
setFixedAclMaxTransactionTime(permissionsDaoComponent, homeFolderNodeRef, maxTransactionTime);
|
||||||
|
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
// Set Shared permissions on origin
|
// Set Shared permissions on origin
|
||||||
permissionService.setInheritParentPermissions(originalRef, true, false);
|
permissionService.setInheritParentPermissions(originalRef, true, false);
|
||||||
permissionService.setPermission(originalRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
|
permissionService.setPermission(originalRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
|
||||||
@@ -343,7 +356,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(originalRef);
|
deleteNodes(originalRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,14 +367,26 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testAsyncWithNodeCopy()
|
public void testAsyncWithNodeCopy()
|
||||||
{
|
{
|
||||||
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
||||||
NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeCopyTargetFolder",
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
|
||||||
ContentModel.TYPE_FOLDER);
|
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
|
||||||
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
||||||
|
|
||||||
// Set permissions on target folder
|
// Set permissions on target folder
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
permissionService.setInheritParentPermissions(targetRef, false, false);
|
permissionService.setInheritParentPermissions(targetRef, false, false);
|
||||||
@@ -410,7 +435,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(folderRef);
|
deleteNodes(folderRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,13 +446,26 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testAsyncWithNodeCopyToPendingFolder()
|
public void testAsyncWithNodeCopyToPendingFolder()
|
||||||
{
|
{
|
||||||
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
||||||
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
|
||||||
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
||||||
|
|
||||||
// Set permissions on target folder
|
// Set permissions on target folder
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
permissionService.setInheritParentPermissions(targetRef, false, false);
|
permissionService.setInheritParentPermissions(targetRef, false, false);
|
||||||
@@ -487,7 +525,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(folderRef);
|
deleteNodes(folderRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,13 +537,26 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testAsyncWithNodeCopyParentToChildPendingFolder()
|
public void testAsyncWithNodeCopyParentToChildPendingFolder()
|
||||||
{
|
{
|
||||||
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyOriginFolder");
|
||||||
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeCopyTargetFolder");
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
|
||||||
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
||||||
|
|
||||||
// Set permissions on target folder
|
// Set permissions on target folder
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
permissionService.setInheritParentPermissions(targetRef, false, false);
|
permissionService.setInheritParentPermissions(targetRef, false, false);
|
||||||
@@ -585,7 +636,151 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(folderRef);
|
deleteNodes(folderRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move child of node that has the aspect to a child folder of a folder that also has the aspect applied before job
|
||||||
|
* runs
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAsyncWithNodeMoveChildToChildPendingFolder()
|
||||||
|
{
|
||||||
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveChildToChildPendingFolderOrigin");
|
||||||
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveChildToChildPendingFolderTarget");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Set permissions on a child to get a new shared ACL with pending acl nodes
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRef, true, false);
|
||||||
|
permissionService.setPermission(targetRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Get target Folder with a pending ACL
|
||||||
|
NodeRef targetFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, targetRef);
|
||||||
|
assertNotNull("No children folders were found with pendingFixACl aspect", targetFolderWithPendingAcl);
|
||||||
|
NodeRef targetFolderWithPendingAclChild = nodeDAO
|
||||||
|
.getNodePair(getChild(nodeDAO.getNodePair(targetFolderWithPendingAcl).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetFolderWithPendingAcl);
|
||||||
|
aclComparatorTarget.setOriginalPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR);
|
||||||
|
|
||||||
|
// Set permissions on origin folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(folderRef, true, false);
|
||||||
|
permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Find a pending ACL folder
|
||||||
|
NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
|
||||||
|
assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
|
||||||
|
NodeRef originFolderWithPendingAclChild = nodeDAO
|
||||||
|
.getNodePair(getChild(nodeDAO.getNodePair(originFolderWithPendingAcl).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorMovedNode = new ACLComparator(originFolderWithPendingAclChild);
|
||||||
|
aclComparatorMovedNode.setOriginalPermission(TEST_GROUP_NAME_FULL, DEFAULT_PERMISSION);
|
||||||
|
|
||||||
|
// Move one pending folder into the other
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
fileFolderService.move(originFolderWithPendingAclChild, targetFolderWithPendingAclChild, "movedFolder");
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger job
|
||||||
|
triggerFixedACLJob();
|
||||||
|
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
assertTrue("Moved node did not inherit permissions from target",
|
||||||
|
aclComparatorMovedNode.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
|
||||||
|
assertTrue("Child of Pending Moved node did not inherit permissions from target",
|
||||||
|
aclComparatorMovedNode.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
|
||||||
|
assertFalse("Moved node kept original permissions", aclComparatorMovedNode.parentHasOriginalPermission());
|
||||||
|
assertFalse("Child of Moved node kept original permissions",
|
||||||
|
aclComparatorMovedNode.firstChildHasOriginalPermission());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
deleteNodes(folderRef);
|
||||||
|
deleteNodes(targetRefBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a conflicting ACL on a node and then try to run the job normally, without forcing the ACL to get the
|
||||||
|
* expected error and then run it again with the forcedShareACL property as true so it can override the problematic
|
||||||
|
* ACL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAsyncWithErrorsForceSharedACL()
|
||||||
|
{
|
||||||
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithErrorsForceSharedACL");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Set permissions on origin folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(folderRef, true, false);
|
||||||
|
permissionService.setPermission(folderRef, TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Find a pending ACL folder
|
||||||
|
NodeRef originFolderWithPendingAcl = getFirstNodeWithAclPending(ContentModel.TYPE_FOLDER, folderRef);
|
||||||
|
assertNotNull("No children folders were found with pendingFixACl aspect", originFolderWithPendingAcl);
|
||||||
|
NodeRef originFolderWithPendingAclChild = nodeDAO
|
||||||
|
.getNodePair(getChild(nodeDAO.getNodePair(originFolderWithPendingAcl).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Create a new ACL elsewhere and put the shared ACL (from a child) on the pending node child to simulate
|
||||||
|
// conflict
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
NodeRef tempNode = createFile(fileFolderService, folderRef, "testAsyncWithErrorsForceSharedACLTemp",
|
||||||
|
ContentModel.TYPE_FOLDER);
|
||||||
|
permissionService.setInheritParentPermissions(tempNode, false, false);
|
||||||
|
permissionService.setPermission(tempNode, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
NodeRef tempNodeChild = createFile(fileFolderService, tempNode, "testAsyncWithErrorsForceSharedACLTempChild",
|
||||||
|
ContentModel.TYPE_FOLDER);
|
||||||
|
setACL(permissionsDaoComponent, originFolderWithPendingAclChild,
|
||||||
|
nodeDAO.getNodeAclId(nodeDAO.getNodePair(tempNodeChild).getFirst()));
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
ACLComparator aclComparator = new ACLComparator(originFolderWithPendingAclChild);
|
||||||
|
|
||||||
|
// Trigger job without forcing the shared ACL, only 1 error is expected
|
||||||
|
triggerFixedACLJob(false);
|
||||||
|
assertEquals("Unexpected number of errors", 1, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
// Trigger job forcing the shared ACL
|
||||||
|
triggerFixedACLJob(true);
|
||||||
|
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
assertTrue("Child of node with conflict does not have correct permissions",
|
||||||
|
aclComparator.firstChildHasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
|
||||||
|
assertTrue("Node with conflict does not have correct permissions",
|
||||||
|
aclComparator.hasPermission(TEST_GROUP_NAME_FULL, PermissionService.COORDINATOR));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
deleteNodes(folderRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,14 +791,26 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testAsyncWithNodeMove()
|
public void testAsyncWithNodeMove()
|
||||||
{
|
{
|
||||||
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
|
||||||
NodeRef targetRef = createFile(fileFolderService, homeFolderNodeRef, "testAsyncWithNodeMoveTargetFolder",
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
|
||||||
ContentModel.TYPE_FOLDER);
|
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
|
||||||
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
||||||
|
|
||||||
// Set permissions on target folder
|
// Set permissions on target folder
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
permissionService.setInheritParentPermissions(targetRef, false, false);
|
permissionService.setInheritParentPermissions(targetRef, false, false);
|
||||||
@@ -649,7 +856,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(folderRef);
|
deleteNodes(folderRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,13 +867,27 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
public void testAsyncWithNodeMoveToPendingFolder()
|
public void testAsyncWithNodeMoveToPendingFolder()
|
||||||
{
|
{
|
||||||
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
|
NodeRef folderRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveOriginFolder");
|
||||||
NodeRef targetRef = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
|
NodeRef targetRefBase = createFolderHierarchyInRootForFolderTests("testAsyncWithNodeMoveTargetFolder");
|
||||||
|
|
||||||
// Get ACLS for later comparison
|
|
||||||
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Set permissions on target folder
|
||||||
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
permissionService.setInheritParentPermissions(targetRefBase, true, false);
|
||||||
|
permissionService.setPermission(targetRefBase, TEST_GROUP_NAME_FULL, PermissionService.CONSUMER, true);
|
||||||
|
return null;
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Trigger the job so the target folder structure has a different base ACL
|
||||||
|
triggerFixedACLJob();
|
||||||
|
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
|
||||||
|
|
||||||
|
NodeRef targetRef = nodeDAO.getNodePair(getChild(nodeDAO.getNodePair(targetRefBase).getFirst())).getSecond();
|
||||||
|
|
||||||
|
// Get ACLS for later comparison
|
||||||
|
ACLComparator aclComparatorTarget = new ACLComparator(targetRef);
|
||||||
|
|
||||||
// Set permissions on target folder
|
// Set permissions on target folder
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
permissionService.setInheritParentPermissions(targetRef, false, false);
|
permissionService.setInheritParentPermissions(targetRef, false, false);
|
||||||
@@ -723,7 +944,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
deleteNodes(folderRef);
|
deleteNodes(folderRef);
|
||||||
deleteNodes(targetRef);
|
deleteNodes(targetRefBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1250,6 +1471,19 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setACL(PermissionsDaoComponent permissionsDaoComponent, NodeRef nodeRef, long aclId)
|
||||||
|
{
|
||||||
|
if (permissionsDaoComponent instanceof ADMPermissionsDaoComponentImpl)
|
||||||
|
{
|
||||||
|
AccessControlListDAO acldao = ((ADMPermissionsDaoComponentImpl) permissionsDaoComponent).getACLDAO(nodeRef);
|
||||||
|
if (acldao instanceof ADMAccessControlListDAO)
|
||||||
|
{
|
||||||
|
ADMAccessControlListDAO admAcLDao = (ADMAccessControlListDAO) acldao;
|
||||||
|
admAcLDao.setAccessControlList(nodeRef, aclId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private NodeRef createFolderHierarchyInRoot(String folderName, int[] filesPerLevel)
|
private NodeRef createFolderHierarchyInRoot(String folderName, int[] filesPerLevel)
|
||||||
{
|
{
|
||||||
return txnHelper.doInTransaction((RetryingTransactionCallback<NodeRef>) () -> {
|
return txnHelper.doInTransaction((RetryingTransactionCallback<NodeRef>) () -> {
|
||||||
@@ -1318,6 +1552,11 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void triggerFixedACLJob()
|
private void triggerFixedACLJob()
|
||||||
|
{
|
||||||
|
triggerFixedACLJob(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerFixedACLJob(boolean forceSharedACL)
|
||||||
{
|
{
|
||||||
// run the fixedAclUpdater until there is nothing more to fix (running the updater may create more to fix up) or
|
// run the fixedAclUpdater until there is nothing more to fix (running the updater may create more to fix up) or
|
||||||
// the count doesn't change for 3 cycles, meaning we have a problem.
|
// the count doesn't change for 3 cycles, meaning we have a problem.
|
||||||
@@ -1325,6 +1564,7 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
int previousCount = 0;
|
int previousCount = 0;
|
||||||
int rounds = 0;
|
int rounds = 0;
|
||||||
|
fixedAclUpdater.setForceSharedACL(forceSharedACL);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
previousCount = count;
|
previousCount = count;
|
||||||
@@ -1356,8 +1596,13 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
isDescendent = true;
|
isDescendent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDescendent && nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
|
if (isDescendent && nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
|
||||||
{
|
{
|
||||||
|
// If folder, the tests will need a child and a grandchild to verify permissions
|
||||||
|
if (nodeType.equals(ContentModel.TYPE_FOLDER) && !hasGrandChilden(nodeRef)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return nodeRef;
|
return nodeRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1377,6 +1622,10 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
|
NodeRef nodeRef = nodesWithAclPendingAspect.get(i);
|
||||||
if (nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
|
if (nodeDAO.getNodeType(nodeDAO.getNodePair(nodeRef).getFirst()).equals(nodeType))
|
||||||
{
|
{
|
||||||
|
// If folder, the tests will need a child and a grandchild to verify permissions
|
||||||
|
if (nodeType.equals(ContentModel.TYPE_FOLDER) && !hasGrandChilden(nodeRef)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return nodeRef;
|
return nodeRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1385,6 +1634,18 @@ public class FixedAclUpdaterTest extends TestCase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasGrandChilden(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
|
||||||
|
Long childId = getChild(nodeId);
|
||||||
|
Long grandChild = null;
|
||||||
|
if (childId != null)
|
||||||
|
{
|
||||||
|
grandChild = getChild(childId);
|
||||||
|
}
|
||||||
|
return (grandChild != null);
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteNodes(NodeRef folder)
|
private void deleteNodes(NodeRef folder)
|
||||||
{
|
{
|
||||||
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
txnHelper.doInTransaction((RetryingTransactionCallback<Void>) () -> {
|
||||||
|
@@ -30,6 +30,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||||||
import static org.awaitility.Awaitility.await;
|
import static org.awaitility.Awaitility.await;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
import javax.jms.ConnectionFactory;
|
||||||
@@ -77,17 +78,19 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
|
|
||||||
public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
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 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 BROKER_URL = "tcp://localhost:61616";
|
||||||
private static final String TOPIC_NAME = "alfresco.repo.event2";
|
private static final String TOPIC_NAME = "alfresco.repo.event2";
|
||||||
private static final String CAMEL_ROUTE = "jms:topic:" + TOPIC_NAME;
|
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 final CamelContext CAMEL_CONTEXT = new DefaultCamelContext();
|
||||||
|
|
||||||
private static boolean isCamelConfigured;
|
private static boolean isCamelConfigured;
|
||||||
private static DataFormat dataFormat;
|
private static DataFormat dataFormat;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected RetryingTransactionHelper retryingTransactionHelper;
|
protected RetryingTransactionHelper retryingTransactionHelper;
|
||||||
|
|
||||||
@@ -104,6 +107,13 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected ObjectMapper event2ObjectMapper;
|
protected ObjectMapper event2ObjectMapper;
|
||||||
|
|
||||||
|
@Autowired @Qualifier("eventGeneratorV2")
|
||||||
|
protected EventGenerator eventGenerator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("eventGeneratorQueue")
|
||||||
|
protected EventGeneratorQueue eventQueue;
|
||||||
|
|
||||||
protected NodeRef rootNodeRef;
|
protected NodeRef rootNodeRef;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@@ -141,8 +151,35 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
|||||||
}
|
}
|
||||||
return nodeService.getRootNode(storeRef);
|
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
|
@After
|
||||||
public void tearDown()
|
public void tearDown()
|
||||||
{
|
{
|
||||||
@@ -179,6 +216,16 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
|||||||
propertyMap).getChildRef());
|
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)
|
protected void deleteNode(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
retryingTransactionHelper.doInTransaction(() -> {
|
retryingTransactionHelper.doInTransaction(() -> {
|
||||||
@@ -376,13 +423,18 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
|||||||
|
|
||||||
public static class RepoEventContainer implements Processor
|
public static class RepoEventContainer implements Processor
|
||||||
{
|
{
|
||||||
private final List<RepoEvent<?>> events = new ArrayList<>();
|
private final List<RepoEvent<?>> events = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Exchange exchange)
|
public void process(Exchange exchange)
|
||||||
{
|
{
|
||||||
Object object = exchange.getIn().getBody();
|
Object object = exchange.getIn().getBody();
|
||||||
events.add((RepoEvent<?>) object);
|
events.add((RepoEvent<?>) object);
|
||||||
|
|
||||||
|
if (DEBUG)
|
||||||
|
{
|
||||||
|
System.err.println("XX: "+object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RepoEvent<?>> getEvents()
|
public List<RepoEvent<?>> getEvents()
|
||||||
@@ -404,6 +456,12 @@ public abstract class AbstractContextAwareRepoEvent extends BaseSpringTest
|
|||||||
{
|
{
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty()
|
||||||
|
{
|
||||||
|
return events.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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,
|
UpdateRepoEventIT.class,
|
||||||
DeleteRepoEventIT.class,
|
DeleteRepoEventIT.class,
|
||||||
ChildAssociationRepoEventIT.class,
|
ChildAssociationRepoEventIT.class,
|
||||||
PeerAssociationRepoEventIT.class
|
PeerAssociationRepoEventIT.class,
|
||||||
|
EventGeneratorTest.class
|
||||||
})
|
})
|
||||||
public class RepoEvent2ITSuite
|
public class RepoEvent2ITSuite
|
||||||
{
|
{
|
||||||
|
@@ -33,7 +33,8 @@ import org.junit.runners.Suite.SuiteClasses;
|
|||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@SuiteClasses({ EventFilterUnitTest.class,
|
@SuiteClasses({ EventFilterUnitTest.class,
|
||||||
EventConsolidatorUnitTest.class,
|
EventConsolidatorUnitTest.class,
|
||||||
EventJSONSchemaUnitTest.class
|
EventJSONSchemaUnitTest.class,
|
||||||
|
EventGeneratorQueueUnitTest.class
|
||||||
})
|
})
|
||||||
public class RepoEvent2UnitSuite
|
public class RepoEvent2UnitSuite
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
@@ -565,4 +565,18 @@ public class TransformationOptionsConverterTest
|
|||||||
"timeout=-1 "
|
"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 ");
|
||||||
|
}
|
||||||
}
|
}
|
@@ -31,14 +31,16 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
import org.alfresco.httpclient.HttpClientFactory;
|
import org.alfresco.httpclient.HttpClientFactory;
|
||||||
|
import org.alfresco.httpclient.RequestHeadersHttpClient;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
import org.apache.commons.codec.net.URLCodec;
|
import org.apache.commons.codec.net.URLCodec;
|
||||||
import org.apache.commons.httpclient.HostConfiguration;
|
import org.apache.commons.httpclient.HostConfiguration;
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
import org.apache.commons.httpclient.HttpClient;
|
||||||
import org.apache.commons.httpclient.protocol.Protocol;
|
import org.apache.commons.httpclient.protocol.Protocol;
|
||||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -46,8 +48,6 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andy
|
* @author Andy
|
||||||
*
|
*
|
||||||
@@ -64,34 +64,34 @@ public class SolrStoreMappingWrapperTest
|
|||||||
HttpClientFactory httpClientFactory;
|
HttpClientFactory httpClientFactory;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClientCommon;
|
RequestHeadersHttpClient httpClientCommon;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient1;
|
RequestHeadersHttpClient httpClient1;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient2;
|
RequestHeadersHttpClient httpClient2;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient3;
|
RequestHeadersHttpClient httpClient3;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient4;
|
RequestHeadersHttpClient httpClient4;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient5;
|
RequestHeadersHttpClient httpClient5;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient6;
|
RequestHeadersHttpClient httpClient6;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient7;
|
RequestHeadersHttpClient httpClient7;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient8;
|
RequestHeadersHttpClient httpClient8;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HttpClient httpClient9;
|
RequestHeadersHttpClient httpClient9;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
HostConfiguration hostConfigurationCommon;
|
HostConfiguration hostConfigurationCommon;
|
||||||
|
Reference in New Issue
Block a user