Compare commits

..

13 Commits

Author SHA1 Message Date
alfresco-build
4417e28412 [maven-release-plugin][skip ci] prepare release 23.1.0.101 2023-05-11 09:43:02 +00:00
Damian Ujma
58653cb523 ACS-5087 Add more attempts to create a folder in RenditionIntegrationTests (#1904)
* ACS-5087 Add more attempts to create a folder

* ACS-5087 Use awaitility to add more attempts to create a folder

* ACS-5087 Add ignoreExceptions condition

* ACS-5087 Use a smaller pollInterval
2023-05-11 10:59:38 +02:00
alfresco-build
7af935d43a [maven-release-plugin][skip ci] prepare for next development iteration 2023-05-08 12:41:15 +00:00
alfresco-build
f5d843446a [maven-release-plugin][skip ci] prepare release 23.1.0.100 2023-05-08 12:41:11 +00:00
mstrankowski
817901e74e Update Master branch to 23.1.0, forgotten updates 2023-05-08 13:52:16 +02:00
mstrankowski
c492683113 Update Master branch to 23.1.0 2023-05-08 13:02:01 +02:00
alfresco-build
e2305d053f [maven-release-plugin][skip ci] prepare for next development iteration 2023-05-07 00:07:14 +00:00
alfresco-build
749768457e [maven-release-plugin][skip ci] prepare release 20.163 2023-05-07 00:07:11 +00:00
Alfresco CI User
118f2ecbab [force] Force release for 2023-05-07. 2023-05-07 00:03:02 +00:00
alfresco-build
a4ac93df7a [maven-release-plugin][skip ci] prepare for next development iteration 2023-05-04 07:56:19 +00:00
alfresco-build
1e1fbe8207 [maven-release-plugin][skip ci] prepare release 20.162 2023-05-04 07:56:16 +00:00
Sara
e78f9ced98 ACS-5157_Bump_api-explorer_to_7-4-0 (#1912) 2023-05-04 08:10:00 +01:00
alfresco-build
72221c777d [maven-release-plugin][skip ci] prepare for next development iteration 2023-05-03 20:54:48 +00:00
53 changed files with 191 additions and 884 deletions

View File

@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest
if: >
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -52,7 +52,7 @@ jobs:
if: >
((github.ref_name == 'master' || startsWith(github.ref_name, 'release/')) && github.event_name != 'pull_request') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -73,7 +73,7 @@ jobs:
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -94,7 +94,7 @@ jobs:
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -139,7 +139,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -169,7 +169,7 @@ jobs:
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -195,7 +195,7 @@ jobs:
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -220,7 +220,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -245,7 +245,7 @@ jobs:
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -268,7 +268,7 @@ jobs:
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -289,7 +289,7 @@ jobs:
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -358,7 +358,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tas]')) ||
contains(github.event.head_commit.message, '[tas]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -425,7 +425,7 @@ jobs:
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
@@ -448,7 +448,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip ags]')) ||
contains(github.event.head_commit.message, '[ags]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -479,7 +479,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip ags]')) ||
contains(github.event.head_commit.message, '[ags on MySQL]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
@@ -510,7 +510,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip ags]') && !contains(github.event.head_commit.message, '[skip tas]')) ||
(contains(github.event.head_commit.message, '[ags]') && contains(github.event.head_commit.message, '[tas]'))) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
!contains(github.event.head_commit.message, '[force]')
env:
REQUIRES_LOCAL_IMAGES: true
steps:

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<build>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<properties>

View File

@@ -3,9 +3,9 @@
#
# Version label
version.major=7
version.minor=4
version.revision=2
version.major=23
version.minor=1
version.revision=0
version.label=
# Edition label

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<build>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<properties>

View File

@@ -48,7 +48,7 @@ function tagQuery()
}
query += "ASPECT:\"{http://www.alfresco.org/model/content/1.0}taggable\"";
//MNT-2118 Share inconsistencies when displaying locked files with tags
query += " AND -ASPECT:\"{http://www.alfresco.org/model/content/1.0}workingcopy\"";
query += " -ASPECT:\"{http://www.alfresco.org/model/content/1.0}workingcopy\"";
// MNT-20091 check to prevent cm:taggable with NULL
query += " AND ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}taggable\"";
@@ -60,7 +60,7 @@ function tagQuery()
query: query,
language: "lucene",
page: {
// query minimum rows because all useful info will come with facets
// query minimum rows because all usefull info will come with facets
maxItems: 1,
skipCount: 0
},

View File

@@ -24,7 +24,7 @@ function getCategoryNode()
else
{
var queryPath = "/" + catAspect + "/" + encodePath(path);
categoryResults = search.luceneSearch("+PATH:\"" + queryPath + "/*\" AND -PATH:\"" + queryPath + "/member\"");
categoryResults = search.luceneSearch("+PATH:\"" + queryPath + "/*\" -PATH:\"" + queryPath + "/member\"");
}
// make each result an object and indicate it is selectable in the UI
@@ -71,4 +71,4 @@ function encodePath(path)
function sortByName(a, b)
{
return (b.node.name.toLowerCase() > a.node.name.toLowerCase() ? -1 : 1);
}
}

View File

@@ -29,7 +29,7 @@ function main()
{
query = "+PATH:\"" + parsedArgs.pathNode.qnamePath + "//*\" ";
}
query += "AND +TYPE:\"cm:content\" AND +@cm\\:content.mimetype:\"image/*\"";
query += "+TYPE:\"cm:content\" +@cm\\:content.mimetype:image/*";
// Sort the list before trimming to page chunks
assets = search.query(
@@ -52,4 +52,4 @@ function main()
/**
* Images List Component: images
*/
model.images = main();
model.images = main();

View File

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

View File

@@ -92,16 +92,15 @@ public class HttpClient4Factory
else
{
//Setting a connectionManager overrides these properties
config.getMaxTotalConnections().ifPresent(v -> clientBuilder.setMaxConnTotal(v));
config.getMaxHostConnections().ifPresent(v -> clientBuilder.setMaxConnPerRoute(v));
clientBuilder.setMaxConnTotal(config.getMaxTotalConnections());
clientBuilder.setMaxConnPerRoute(config.getMaxHostConnections());
}
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
config.getConnectionTimeout().ifPresent(v -> requestConfigBuilder.setConnectTimeout(v));
config.getConnectionRequestTimeout().ifPresent(v -> requestConfigBuilder.setConnectionRequestTimeout(v));
config.getSocketTimeout().ifPresent(v -> requestConfigBuilder.setSocketTimeout(v));
RequestConfig requestConfig = requestConfigBuilder.build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(config.getConnectionTimeout())
.setSocketTimeout(config.getSocketTimeout())
.setConnectionRequestTimeout(config.getConnectionRequestTimeout())
.build();
clientBuilder.setDefaultRequestConfig(requestConfig);
@@ -136,8 +135,8 @@ public class HttpClient4Factory
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.build());
}
config.getMaxTotalConnections().ifPresent(v -> poolingHttpClientConnectionManager.setMaxTotal(v));
config.getMaxHostConnections().ifPresent(v -> poolingHttpClientConnectionManager.setDefaultMaxPerRoute(v));
poolingHttpClientConnectionManager.setMaxTotal(config.getMaxTotalConnections());
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(config.getMaxHostConnections());
return poolingHttpClientConnectionManager;
}

View File

@@ -85,27 +85,17 @@ public class HttpClientConfig
this.keyStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getKeyStoreParameters(), keyResourceLoader);
this.trustStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getTrustStoreParameters(), keyResourceLoader);
config = retrieveConfig();
config = retrieveConfig(serviceName);
checkUnsupportedProperties(config);
}
/**
* Method used for retrieving HttpClient config from Global Properties
* that can also have values provided/overridden through System Properties
*
* @param serviceName name of used service
* @return map of properties
*/
private Map<String, String> retrieveConfig()
private Map<String, String> retrieveConfig(String serviceName)
{
Map<String, String> resultProperties = getHttpClientPropertiesForService(properties);
Map<String, String> systemProperties = getHttpClientPropertiesForService(System.getProperties());
systemProperties.forEach((k, v) -> resultProperties.put(k, v)); //Override/Add to Global Properties results with values from System Properties
return resultProperties;
}
private Map<String, String> getHttpClientPropertiesForService(Properties properties) {
return properties.keySet().stream()
.filter(key -> key instanceof String)
.map(Object::toString)
@@ -122,75 +112,79 @@ public class HttpClientConfig
.forEach(propertyName -> LOGGER.warn(String.format("For service [%s], an unsupported property [%s] is set", serviceName, propertyName)));
}
private Optional<Integer> getIntegerProperty(HttpClientPropertiesEnum property)
private Integer getIntegerProperty(HttpClientPropertiesEnum property)
{
Optional<String> optionalProperty = extractValueFromConfig(property);
return optionalProperty.isPresent() ? Optional.of(Integer.parseInt(optionalProperty.get())) : Optional.empty();
return Integer.parseInt(extractValueFromConfig(property).orElse("0"));
}
private Optional<Boolean> getBooleanProperty(HttpClientPropertiesEnum property)
private Boolean getBooleanProperty(HttpClientPropertiesEnum property)
{
Optional<String> optionalProperty = extractValueFromConfig(property);
return optionalProperty.isPresent() ? Optional.of(Boolean.parseBoolean(optionalProperty.get())) : Optional.empty();
return Boolean.parseBoolean(extractValueFromConfig(property).orElse("false"));
}
private Optional<String> extractValueFromConfig(HttpClientPropertiesEnum property)
{
return Optional.ofNullable(config.get(property.name));
Optional<String> optionalProperty = Optional.ofNullable(config.get(property.name));
if(property.isRequired && optionalProperty.isEmpty())
{
String msg = String.format("Required property: '%s' is empty.", property.name);
throw new HttpClientException(msg);
}
return optionalProperty;
}
public Optional<Integer> getConnectionTimeout()
public Integer getConnectionTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.CONNECTION_REQUEST_TIMEOUT);
}
public Optional<Integer> getSocketTimeout()
public Integer getSocketTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.SOCKET_TIMEOUT);
}
public Optional<Integer> getConnectionRequestTimeout()
public Integer getConnectionRequestTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.CONNECTION_REQUEST_TIMEOUT);
}
public Optional<Integer> getMaxTotalConnections()
public Integer getMaxTotalConnections()
{
return getIntegerProperty(HttpClientPropertiesEnum.MAX_TOTAL_CONNECTIONS);
}
public Optional<Integer> getMaxHostConnections()
public Integer getMaxHostConnections()
{
return getIntegerProperty(HttpClientPropertiesEnum.MAX_HOST_CONNECTIONS);
}
public boolean isMTLSEnabled()
public Boolean isMTLSEnabled()
{
return getBooleanProperty(HttpClientPropertiesEnum.MTLS_ENABLED).orElse(Boolean.FALSE);
return getBooleanProperty(HttpClientPropertiesEnum.MTLS_ENABLED);
}
public boolean isHostnameVerificationDisabled()
{
return getBooleanProperty(HttpClientPropertiesEnum.HOSTNAME_VERIFICATION_DISABLED).orElse(Boolean.FALSE);
return getBooleanProperty(HttpClientPropertiesEnum.HOSTNAME_VERIFICATION_DISABLED);
}
private enum HttpClientPropertiesEnum
{
CONNECTION_TIMEOUT("connectionTimeout"),
SOCKET_TIMEOUT("socketTimeout"),
CONNECTION_REQUEST_TIMEOUT("connectionRequestTimeout"),
MAX_TOTAL_CONNECTIONS("maxTotalConnections"),
MAX_HOST_CONNECTIONS("maxHostConnections"),
HOSTNAME_VERIFICATION_DISABLED("hostnameVerificationDisabled"),
MTLS_ENABLED("mTLSEnabled");
CONNECTION_TIMEOUT("connectionTimeout", true),
SOCKET_TIMEOUT("socketTimeout", true),
CONNECTION_REQUEST_TIMEOUT("connectionRequestTimeout", true),
MAX_TOTAL_CONNECTIONS("maxTotalConnections", true),
MAX_HOST_CONNECTIONS("maxHostConnections", true),
HOSTNAME_VERIFICATION_DISABLED("hostnameVerificationDisabled", false),
MTLS_ENABLED("mTLSEnabled", true);
private final String name;
private final Boolean isRequired;
HttpClientPropertiesEnum(String propertyName)
HttpClientPropertiesEnum(String propertyName, Boolean isRequired)
{
this.name = propertyName;
this.isRequired = isRequired;
}
private static final List<String> supportedProperties = new ArrayList<>();

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<properties>

View File

@@ -201,11 +201,6 @@ public class SearchParameters implements BasicSearchParameters
private String timezone;
/**
* Configure the limit to track the total hits on search results
*/
private int trackTotalHits;
/**
* Default constructor
*/
@@ -256,7 +251,6 @@ public class SearchParameters implements BasicSearchParameters
sp.stats = this.stats;
sp.ranges = this.ranges;
sp.timezone = this.timezone;
sp.trackTotalHits = this.trackTotalHits;
return sp;
}
@@ -1647,21 +1641,6 @@ public class SearchParameters implements BasicSearchParameters
{
this.includeMetadata = includeMetadata;
}
public int getTrackTotalHits()
{
return trackTotalHits;
}
/**
* Set a maximum value for the report of total hits. The reported number of hits will never exceed this limit even
* if more are found. If unset, the engines default tracking limit is applied. To remove any limit, set to -1.
*
* @param trackTotalHits int
*/
public void setTrackTotalHits(int trackTotalHits)
{
this.trackTotalHits = trackTotalHits;
}
}

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<modules>

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<organization>

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
</parent>
<properties>
@@ -85,6 +85,13 @@
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${dependency.awaitility.version}</version>
<scope>test</scope>
</dependency>
<!-- REST ASSURED -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>

View File

@@ -1,82 +0,0 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2023 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.rest.search;
import org.alfresco.rest.core.IRestModel;
import org.alfresco.utility.model.TestModel;
import com.fasterxml.jackson.annotation.JsonProperty;
public class RestRequestLimitsModel extends TestModel implements IRestModel<RestRequestLimitsModel>
{
@JsonProperty
RestRequestLimitsModel model;
private Integer permissionEvaluationTime;
private Integer permissionEvaluationCount;
private Integer trackTotalHitsLimit;
@Override
public RestRequestLimitsModel onModel()
{
return model;
}
public RestRequestLimitsModel(Integer permissionEvaluationTime, Integer permissionEvaluationCount,
Integer trackTotalHitsLimit)
{
super();
this.permissionEvaluationTime = permissionEvaluationTime;
this.permissionEvaluationCount = permissionEvaluationCount;
this.trackTotalHitsLimit = trackTotalHitsLimit;
}
public Integer getPermissionEvaluationTime()
{
return permissionEvaluationTime;
}
public void setPermissionEvaluationTime(Integer permissionEvaluationTime)
{
this.permissionEvaluationTime = permissionEvaluationTime;
}
public Integer getPermissionEvaluationCount()
{
return permissionEvaluationCount;
}
public void setPermissionEvaluationCount(Integer permissionEvaluationCount)
{
this.permissionEvaluationCount = permissionEvaluationCount;
}
public Integer getTrackTotalHitsLimit()
{
return trackTotalHitsLimit;
}
public void setTrackTotalHitsLimit(Integer trackTotalHitsLimit)
{
this.trackTotalHitsLimit = trackTotalHitsLimit;
}
}

View File

@@ -76,7 +76,6 @@ public class SearchRequest extends TestModel
String facetFormat;
List<String> include;
List<SortClause> sort;
RestRequestLimitsModel limits;
public SearchRequest()
{
@@ -280,15 +279,4 @@ public class SearchRequest extends TestModel
return this;
}
public RestRequestLimitsModel getLimits()
{
return limits;
}
public void setLimits(RestRequestLimitsModel limits)
{
this.limits = limits;
}
}

View File

@@ -1,5 +1,7 @@
package org.alfresco.rest.renditions;
import java.time.Duration;
import com.google.common.base.Predicates;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.core.RestResponse;
import org.alfresco.rest.model.RestNodeModel;
@@ -8,6 +10,8 @@ import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.awaitility.Awaitility;
import org.awaitility.Durations;
import org.springframework.http.HttpStatus;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
@@ -68,15 +72,23 @@ public abstract class RenditionIntegrationTests extends RestTest
*/
protected RestNodeModel uploadFile(String sourceFile) throws Exception
{
FolderModel folder = FolderModel.getRandomFolderModel();
folder = dataContent.usingUser(user).usingSite(site).createFolder(folder);
FolderModel folder = Awaitility
.await()
.atMost(Duration.ofSeconds(30))
.pollInterval(Durations.ONE_SECOND)
.ignoreExceptions()
.until(() -> {
FolderModel randomFolderModel = FolderModel.getRandomFolderModel();
return dataContent.usingUser(user).usingSite(site).createFolder(randomFolderModel);
}, Predicates.notNull());
restClient.authenticateUser(user).configureRequestSpec()
.addMultiPart("filedata", Utility.getResourceTestDataFile(sourceFile));
.addMultiPart("filedata", Utility.getResourceTestDataFile(sourceFile));
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createNode();
Assert.assertEquals(Integer.valueOf(restClient.getStatusCode()).intValue(), HttpStatus.CREATED.value(),
"Failed to created a node for rendition tests using file " + sourceFile);
"Failed to created a node for rendition tests using file " + sourceFile);
return fileNode;
}
}

View File

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

View File

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

12
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>22.1</version>
<version>23.1.0.101</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -23,9 +23,9 @@
</modules>
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>4</acs.version.minor>
<acs.version.revision>2</acs.version.revision>
<acs.version.major>23</acs.version.major>
<acs.version.minor>1</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.label />
<amp.min.version>${acs.version.major}.0.0</amp.min.version>
@@ -62,7 +62,7 @@
<dependency.jackson.version>2.15.0-rc1</dependency.jackson.version>
<dependency.cxf.version>3.5.5</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.44</dependency.webscripts.version>
<dependency.webscripts.version>8.40</dependency.webscripts.version>
<dependency.bouncycastle.version>1.70</dependency.bouncycastle.version>
<dependency.mockito-core.version>4.9.0</dependency.mockito-core.version>
<dependency.assertj.version>3.24.2</dependency.assertj.version>
@@ -150,7 +150,7 @@
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>22.1</tag>
<tag>23.1.0.101</tag>
</scm>
<distributionManagement>

View File

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

View File

@@ -68,7 +68,6 @@ import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.rendition2.RenditionDefinition2;
import org.alfresco.repo.rendition2.RenditionDefinitionRegistry2;
import org.alfresco.repo.rendition2.RenditionService2;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.AccessDeniedException;
@@ -149,7 +148,6 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
@@ -218,7 +216,6 @@ public class NodesImpl implements Nodes
private LockService lockService;
private VirtualStore smartStore; // note: remove as part of REPO-1173
private ClassDefinitionMapper classDefinitionMapper;
private RuleService ruleService;
private enum Activity_Type
{
@@ -341,11 +338,6 @@ public class NodesImpl implements Nodes
this.classDefinitionMapper = classDefinitionMapper;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
// excluded namespaces (aspects, properties, assoc types)
private static final List<String> EXCLUDED_NS = Arrays.asList(NamespaceService.SYSTEM_MODEL_1_0_URI);
@@ -2551,8 +2543,6 @@ public class NodesImpl implements Nodes
Set<QName> aspectsToAdd = new HashSet<>(3);
Set<QName> aspectsToRemove = new HashSet<>(3);
boolean hasRules = ruleService.hasRules(nodeRef);
for (QName aspectQName : aspectQNames)
{
if (EXCLUDED_NS.contains(aspectQName.getNamespaceURI()) || excludedAspects.contains(aspectQName) || aspectQName.equals(ContentModel.ASPECT_AUDITABLE))
@@ -2568,7 +2558,7 @@ public class NodesImpl implements Nodes
for (QName existingAspect : existingAspects)
{
if (EXCLUDED_NS.contains(existingAspect.getNamespaceURI()) || excludedAspects.contains(existingAspect) || existingAspect.equals(ContentModel.ASPECT_AUDITABLE) || existingAspect.equals(RuleModel.ASPECT_RULES) && hasRules)
if (EXCLUDED_NS.contains(existingAspect.getNamespaceURI()) || excludedAspects.contains(existingAspect) || existingAspect.equals(ContentModel.ASPECT_AUDITABLE))
{
continue; // ignore
}

View File

@@ -823,11 +823,6 @@ public class SearchMapper
sp.setLimitBy(LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS);
sp.setMaxPermissionCheckTimeMillis(limits.getPermissionEvaluationTime());
}
if(limits.getTrackTotalHitsLimit() != null)
{
sp.setTrackTotalHits(limits.getTrackTotalHitsLimit());
}
}
}

View File

@@ -93,7 +93,7 @@ public class FacetField
public String toFilterQuery(String value)
{
return ("Null".equals(value)) ? "ISNULL:\"" + field + "\"" : field + ":\"" + value + "\"";
return field+":\""+value+"\"";
}
public String getPrefix()

View File

@@ -37,16 +37,13 @@ public class Limits
private final Integer permissionEvaluationTime;
private final Integer permissionEvaluationCount;
private final Integer trackTotalHitsLimit;
@JsonCreator
public Limits(@JsonProperty("permissionEvaluationTime") Integer permissionEvaluationTime,
@JsonProperty("permissionEvaluationCount") Integer permissionEvaluationCount,
@JsonProperty("trackTotalHitsLimit") Integer trackTotalHitsLimit)
@JsonProperty("permissionEvaluationCount") Integer permissionEvaluationCount)
{
this.permissionEvaluationTime = permissionEvaluationTime;
this.permissionEvaluationCount = permissionEvaluationCount;
this.trackTotalHitsLimit = trackTotalHitsLimit;
}
public Integer getPermissionEvaluationTime()
@@ -58,9 +55,4 @@ public class Limits
{
return permissionEvaluationCount;
}
public Integer getTrackTotalHitsLimit()
{
return trackTotalHitsLimit;
}
}

View File

@@ -537,7 +537,6 @@
<property name="poster" ref="activitiesPoster" />
<property name="smartStore" ref="smartStore"/>
<property name="classDefinitionMapper" ref="classDefinitionMapper" />
<property name="ruleService" ref="RuleService" />
</bean>
<bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -745,56 +745,33 @@ public class SearchMapperTests
}
@Test
public void fromLimits_setNull() throws Exception
public void fromLimits() throws Exception
{
SearchParameters searchParameters = new SearchParameters();
searchMapper.setDefaults(searchParameters);
//Doesn't error
searchMapper.fromLimits(searchParameters, null);
assertEquals("LimitBy default value should be unlimited", LimitBy.UNLIMITED, searchParameters.getLimitBy());
assertEquals("Limit default value should be 500", 500, searchParameters.getLimit());
}
assertEquals(500, searchParameters.getLimit());
assertEquals(LimitBy.UNLIMITED, searchParameters.getLimitBy());
@Test
public void fromLimits_setAllLimitsAsNull() throws Exception
{
SearchParameters searchParameters = new SearchParameters();
searchMapper.setDefaults(searchParameters);
searchMapper.fromLimits(searchParameters, new Limits(null, null, null));
assertEquals("LimitBy default value should be unlimited", LimitBy.UNLIMITED, searchParameters.getLimitBy());
assertEquals("Limit default value should be 500", 500, searchParameters.getLimit());
}
searchMapper.fromLimits(searchParameters, new Limits(null, null));
assertEquals(LimitBy.UNLIMITED, searchParameters.getLimitBy());
assertEquals(500, searchParameters.getLimit());
@Test
public void fromLimits_setPermissionEvaluationCount() throws Exception
{
SearchParameters searchParameters = new SearchParameters();
searchMapper.setDefaults(searchParameters);
searchMapper.fromLimits(searchParameters, new Limits(null, 34, null));
searchMapper.fromLimits(searchParameters, new Limits(null, 34));
assertEquals(LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS, searchParameters.getLimitBy());
assertEquals("MaxPermissionChecks should be set", 34, searchParameters.getMaxPermissionChecks());
assertEquals("Limit should be -1", -1, searchParameters.getLimit());
assertEquals("MaxPermissionCheckTimeMillis should be -1", -1, searchParameters.getMaxPermissionCheckTimeMillis());
}
assertEquals(34, searchParameters.getMaxPermissionChecks());
assertEquals(-1, searchParameters.getLimit());
assertEquals(-1, searchParameters.getMaxPermissionCheckTimeMillis());
@Test
public void fromLimits_setPermissionEvaluationTime() throws Exception
{
SearchParameters searchParameters = new SearchParameters();
searchParameters = new SearchParameters();
searchMapper.setDefaults(searchParameters);
searchMapper.fromLimits(searchParameters, new Limits(1000, null, null));
searchMapper.fromLimits(searchParameters, new Limits(1000, null));
assertEquals(LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS, searchParameters.getLimitBy());
assertEquals("MaxPermissionCheckTimeMillis should be set", 1000, searchParameters.getMaxPermissionCheckTimeMillis());
assertEquals("Limit should be -1", -1, searchParameters.getLimit());
assertEquals("MaxPermissionChecks should be -1", -1, searchParameters.getMaxPermissionChecks());
}
@Test
public void fromLimits_setTrackTotalHitsLimit() throws Exception
{
SearchParameters searchParameters = new SearchParameters();
searchMapper.setDefaults(searchParameters);
searchMapper.fromLimits(searchParameters, new Limits(null, null, 10));
assertEquals("TrackTotalHits should be set", 10, searchParameters.getTrackTotalHits());
assertEquals(1000, searchParameters.getMaxPermissionCheckTimeMillis());
assertEquals(-1, searchParameters.getLimit());
assertEquals(-1, searchParameters.getMaxPermissionChecks());
}
@Test

View File

@@ -49,10 +49,8 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
import org.alfresco.repo.content.ContentLimitProvider.SimpleFixedLimitProvider;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
@@ -85,16 +83,11 @@ import org.alfresco.rest.api.tests.util.MultiPartBuilder;
import org.alfresco.rest.api.tests.util.MultiPartBuilder.FileData;
import org.alfresco.rest.api.tests.util.MultiPartBuilder.MultiPartRequest;
import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.rule.RuleType;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
@@ -137,8 +130,7 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
protected AuthorityService authorityService;
private NodeService nodeService;
private NamespaceService namespaceService;
private RuleService ruleService;
private ActionService actionService;
private String rootGroupName = null;
private String groupA = null;
@@ -153,8 +145,6 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
authorityService = (AuthorityService) applicationContext.getBean("AuthorityService");
nodeService = applicationContext.getBean("NodeService", NodeService.class);
namespaceService= (NamespaceService) applicationContext.getBean("NamespaceService");
ruleService = (RuleService) applicationContext.getBean("RuleService", RuleService.class);
actionService = (ActionService) applicationContext.getBean("ActionService", ActionService.class);
}
@After
@@ -6408,42 +6398,5 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
setRequestContext(user1);
deleteSite(site1Id, true, 204);
}
@Test
public void testRuleAspectAfterUpdate() throws Exception
{
// Change to User1 context
setRequestContext(networkOne.getId(), user1, null);
AuthenticationUtil.setFullyAuthenticatedUser(user1);
// Create folder
String folderId = createUniqueFolder(getMyNodeId());
NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, folderId);
assertFalse("Folder shouldn't have the rule aspect", nodeService.hasAspect(folderNodeRef, RuleModel.ASPECT_RULES));
// Create Rule
Rule rule = new Rule();
rule.setTitle("My Rule");
rule.setRuleType(RuleType.INBOUND);
Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME);
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE);
rule.setAction(action);
this.ruleService.saveRule(folderNodeRef, rule);
assertTrue("Folder should have the rule aspect", nodeService.hasAspect(folderNodeRef, RuleModel.ASPECT_RULES));
// Update folder with empty aspectNames
Folder folderUpdate = new Folder();
folderUpdate.setAspectNames(Arrays.asList());
put(URL_NODES, folderId, toJsonAsStringNonNull(folderUpdate), null, 200);
assertTrue("Folder should have the rule aspect", nodeService.hasAspect(folderNodeRef, RuleModel.ASPECT_RULES));
assertEquals("Folder should have 1 rule.", 1, ruleService.countRules(folderNodeRef));
// Cleanup
delete(URL_NODES, folderId, 204);
}
}

View File

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

View File

@@ -251,16 +251,15 @@ public class TransactionBehaviourQueue implements TransactionListener
}
catch (IllegalArgumentException e)
{
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId() + " : " + e.getMessage(), e);
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId(), e);
}
catch (IllegalAccessException e)
{
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId() + " : " + e.getMessage(), e);
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId(), e);
}
catch (InvocationTargetException e)
{
String msg = e.getMessage() + (e.getTargetException() != null ? "(" + e.getTargetException().getMessage() + ")" : "");
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId() + " : " + msg, e.getTargetException());
throw new AlfrescoRuntimeException("Failed to execute transaction-level behaviour " + context.method + " in transaction " + AlfrescoTransactionSupport.getTransactionId(), e.getTargetException());
}
}

View File

@@ -1605,6 +1605,8 @@ public class LDAPUserRegistry implements UserRegistry, LDAPNameResolver, Initial
this.userSearchCtls = new SearchControls();
this.userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
this.userSearchCtls.setReturningAttributes(LDAPUserRegistry.this.userKeys.getFirst());
// MNT-14001 fix, set search limit to ensure that server will not return more search results then provided by paged result control
this.userSearchCtls.setCountLimit(LDAPUserRegistry.this.queryBatchSize > 0 ? LDAPUserRegistry.this.queryBatchSize : 0);
this.next = fetchNext();
}

View File

@@ -997,20 +997,6 @@ public class WorkflowServiceImpl implements WorkflowService
public WorkflowTask updateTask(String taskId, Map<QName, Serializable> properties, Map<QName, List<NodeRef>> add,
Map<QName, List<NodeRef>> remove)
{
if(properties.containsKey(WorkflowModel.PROP_STATUS)) {
LinkedList<String> validTaskStatus = new LinkedList<>();
validTaskStatus.add("Not Yet Started");
validTaskStatus.add("In Progress");
validTaskStatus.add("On Hold");
validTaskStatus.add("Cancelled");
validTaskStatus.add("Completed");
if (!validTaskStatus.contains(properties.get(WorkflowModel.PROP_STATUS))) {
throw new WorkflowException("Invalid Value is Passed for Task Status.");
}
}
String engineId = BPMEngineRegistry.getEngineId(taskId);
TaskComponent component = getTaskComponent(engineId);
// get the current assignee before updating the task

View File

@@ -25,19 +25,16 @@
*/
package org.alfresco.schedule;
import java.util.concurrent.atomic.AtomicBoolean;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.VmShutdownListener.VmShutdownException;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.VmShutdownListener.VmShutdownException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* This class encapsulates the {@link org.alfresco.repo.lock.JobLockService JobLockService}
@@ -59,7 +56,7 @@ public class ScheduledJobLockExecuter
{
private static final long LOCK_TTL = 30000L;
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledJobLockExecuter.class);
private static Log logger = LogFactory.getLog(ScheduledJobLockExecuter.class.getName());
private static ThreadLocal<Pair<Long, String>> lockThreadLocal = new ThreadLocal<Pair<Long, String>>();
private final JobLockService jobLockService;
@@ -86,43 +83,52 @@ public class ScheduledJobLockExecuter
* @throws JobExecutionException thrown if the job fails to execute
*/
public void execute(JobExecutionContext jobContext) throws JobExecutionException
{
LockCallback lockCallback = new LockCallback();
String lockName = lockQName.getLocalName();
{
try
{
LOGGER.debug(" Job {} started.", lockName);
refreshLock(lockCallback);
if (logger.isDebugEnabled())
{
logger.debug(String.format(" Job %s started.", lockQName.getLocalName()));
}
refreshLock();
job.executeJob(jobContext);
LOGGER.debug(" Job {} completed.", lockName);
if (logger.isDebugEnabled())
{
logger.debug(String.format(" Job %s completed.", lockQName.getLocalName()));
}
}
catch (LockAcquisitionException e)
{
// Job being done by another process
LOGGER.debug(" Job {} already underway.", lockName);
// Job being done by another process
if (logger.isDebugEnabled())
{
logger.debug(String.format(" Job %s already underway.", lockQName.getLocalName()));
}
}
catch (VmShutdownException e)
{
// Aborted
LOGGER.debug(" Job {} aborted.", lockName);
if (logger.isDebugEnabled())
{
logger.debug(String.format(" Job %s aborted.", lockQName.getLocalName()));
}
}
finally
{
releaseLock(lockCallback);
releaseLock();
}
}
/**
* Lazily update the job lock
*/
private void refreshLock(LockCallback lockCallback)
private void refreshLock()
{
Pair<Long, String> lockPair = lockThreadLocal.get();
if (lockPair == null)
{
String lockToken = jobLockService.getLock(lockQName, LOCK_TTL);
jobLockService.refreshLock(lockToken, lockQName, LOCK_TTL, lockCallback);
Long lastLock = Long.valueOf(System.currentTimeMillis());
String lockToken = jobLockService.getLock(lockQName, LOCK_TTL);
Long lastLock = new Long(System.currentTimeMillis());
// We have not locked before
lockPair = new Pair<Long, String>(lastLock, lockToken);
lockThreadLocal.set(lockPair);
@@ -135,7 +141,7 @@ public class ScheduledJobLockExecuter
// Only refresh the lock if we are past a threshold
if (now - lastLock > (long) (LOCK_TTL / 2L))
{
jobLockService.refreshLock(lockToken, lockQName, LOCK_TTL, lockCallback);
jobLockService.refreshLock(lockToken, lockQName, LOCK_TTL);
lastLock = System.currentTimeMillis();
lockPair = new Pair<Long, String>(lastLock, lockToken);
lockThreadLocal.set(lockPair);
@@ -146,13 +152,8 @@ public class ScheduledJobLockExecuter
/**
* Release the lock after the job completes
*/
private void releaseLock(LockCallback lockCallback)
{
if (lockCallback != null)
{
lockCallback.running.set(false);
}
private void releaseLock()
{
Pair<Long, String> lockPair = lockThreadLocal.get();
if (lockPair != null)
{
@@ -168,23 +169,5 @@ public class ScheduledJobLockExecuter
}
}
// else: We can't release without a token
}
private class LockCallback implements JobLockRefreshCallback
{
final AtomicBoolean running = new AtomicBoolean(true);
@Override
public boolean isActive()
{
return running.get();
}
@Override
public void lockReleased()
{
running.set(false);
LOGGER.debug("Lock release notification: {}", lockQName);
}
}
}

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
version.schema=18200
version.schema=19000
# Directory configuration
@@ -754,6 +754,13 @@ encryption.ssl.truststore.keyMetaData.location=
httpclient.config.transform.mTLSEnabled=false
httpclient.config.transform.maxTotalConnections=20
httpclient.config.transform.maxHostConnections=20
httpclient.config.transform.socketTimeout=5000
httpclient.config.transform.connectionRequestTimeout=5000
httpclient.config.transform.connectionTimeout=5000
# Property is disabled by default for security reasons, never enable it on for production environments.
# It will stop verification of hostnames placed in certificates returned with server responses to Repository requests towards transform services
httpclient.config.transform.hostnameVerificationDisabled=false
# Re-encryptor properties
encryption.reencryptor.chunkSize=100
@@ -1342,7 +1349,7 @@ system.remove-alf_server-table-from-db.ignored=true
allow.unsecure.callback.jsonp=false
# pre-configured allow list of media/mime types to allow inline instead of attachment (via Content-Disposition response header)
content.nonAttach.mimetypes=application/pdf,image/jpeg,image/gif,image/png,image/tiff,image/bmp,application/octet-stream
content.nonAttach.mimetypes=application/pdf,image/jpeg,image/gif,image/png,image/tiff,image/bmp
# Zip file compression ratio threshold as a percentage, above which the zip file will be considered a "zip bomb" and the
# import extraction process cancelled.

View File

@@ -38,15 +38,6 @@ import org.junit.runners.Suite;
@RunWith(Categories.class)
@Categories.ExcludeCategory({DBTests.class, NonBuildTests.class})
@Suite.SuiteClasses({
// ----------------------------------------------------------------------
// testScheduleContext [classpath:alfresco/application-context.xml, classpath:alfresco/schedule/test-schedule-context.xml]
//
// This test needs to be first as it will clean nodes from trashcan, if order is changed, then it will take lot of time
// to remove all the nodes from previous tests
// ----------------------------------------------------------------------
org.alfresco.schedule.AbstractScheduledLockedJobTest.class,
// ----------------------------------------------------------------------
// globalIntegrationTestContext [classpath:alfresco/application-context.xml, classpath:alfresco/test/global-integration-test-context.xml]
// ----------------------------------------------------------------------

View File

@@ -1,209 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2023 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.schedule;
import java.util.UUID;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseSpringTest;
import org.junit.Before;
import org.junit.Test;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.SchedulerAccessorBean;
import org.springframework.test.context.ContextConfiguration;
import com.google.common.collect.ImmutableMap;
/**
*
* @author Tiago Salvado
*/
@ContextConfiguration({"classpath:alfresco/application-context.xml", "classpath:alfresco/schedule/test-schedule-context.xml"})
public class AbstractScheduledLockedJobTest extends BaseSpringTest
{
private static final int TOTAL_NODES = 9;
private static final int NUM_THREADS = 2;
private static final long JOB_EXECUTER_LOCK_TTL = 30000L;
private static final String ARCHIVE_STORE_URL = "archive://SpacesStore";
private NodeService nodeService;
private TransactionService transactionService;
private Repository repository;
private SchedulerAccessorBean testCleanerAccessor;
private JobDetail testCleanerJobDetail;
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractScheduledLockedJobTest.class);
/**
* Sets services and job beans
*/
@Before
public void setUp()
{
nodeService = (NodeService) applicationContext.getBean("nodeService");
transactionService = (TransactionService) applicationContext.getBean("transactionComponent");
repository = (Repository) applicationContext.getBean("repositoryHelper");
}
@Test
public void test() throws SchedulerException, InterruptedException
{
createAndDeleteNodes(TOTAL_NODES);
assertTrue("Expected nodes haven't been created", getNumberOfNodesInTrashcan() >= TOTAL_NODES);
CleanerThread[] threads = new CleanerThread[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++)
{
CleanerThread t = new CleanerThread(i);
threads[i] = t;
t.start();
Thread.sleep(JOB_EXECUTER_LOCK_TTL);
}
for (Thread t : threads)
{
t.join();
}
while (getNumberOfNodesInTrashcan() > 0)
{
Thread.sleep(2000);
}
for (CleanerThread t : threads)
{
if (t.hasErrors())
{
fail("An error has occurred when executing multiple cleaner jobs at the same time");
}
}
}
/**
* Creates and deletes the specified number of nodes.
*
* @param archivedNodes
* Number of nodes to be created and added to trashcan
*/
private void createAndDeleteNodes(int archivedNodes)
{
AuthenticationUtil.runAsSystem(() -> {
RetryingTransactionHelper.RetryingTransactionCallback<Void> txnWork = () -> {
for (int i = 0; i < archivedNodes; i++)
{
addNodeToTrashcan();
}
return null;
};
return transactionService.getRetryingTransactionHelper().doInTransaction(txnWork);
});
}
/**
* Creates and deletes nodes
*/
private void addNodeToTrashcan()
{
NodeRef companyHome = repository.getCompanyHome();
String name = "Sample (" + UUID.randomUUID().toString() + ")";
ChildAssociationRef association = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, name), ContentModel.TYPE_CONTENT,
ImmutableMap.of(ContentModel.PROP_NAME, name));
NodeRef parent = association.getChildRef();
nodeService.deleteNode(parent);
}
/**
* It returns the number of nodes present on trashcan.
*
* @return
*/
private long getNumberOfNodesInTrashcan()
{
StoreRef storeRef = new StoreRef(ARCHIVE_STORE_URL);
NodeRef archiveRoot = nodeService.getRootNode(storeRef);
return nodeService.getChildAssocs(archiveRoot, ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL).size();
}
/**
* Thread to start the cleaner job for the test.
*/
private class CleanerThread extends Thread
{
private int threadNum;
private boolean started;
private Cleaner testCleaner;
CleanerThread(int threadNum)
{
super(CleanerThread.class.getSimpleName() + "-" + threadNum);
this.threadNum = threadNum;
}
@Override
public void run()
{
try
{
testCleanerAccessor = (SchedulerAccessorBean) applicationContext.getBean("testSchedulerAccessor");
testCleanerJobDetail = (JobDetail) applicationContext.getBean("testCleanerJobDetail");
testCleaner = (Cleaner) testCleanerJobDetail.getJobDataMap().get("testCleaner");
testCleanerAccessor.getScheduler().triggerJob(testCleanerJobDetail.getKey());
LOGGER.info("Thread {} has started", this.threadNum);
this.started = true;
}
catch (SchedulerException e)
{
this.started = false;
}
}
public boolean hasErrors()
{
return !started || testCleaner != null && testCleaner.hasErrors();
}
}
}

View File

@@ -1,174 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2023 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.schedule;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A test implementation similar to the trash can cleaner job implementation that will be used in
* {@link AbstractScheduledLockedJobTest}
*
* @author Tiago Salvado
*/
public class Cleaner
{
private static final Logger LOGGER = LoggerFactory.getLogger(Cleaner.class);
private final NodeService nodeService;
private final TransactionService transactionService;
private static final String ARCHIVE_STORE_URL = "archive://SpacesStore";
private final int deleteBatchCount;
private List<NodeRef> nodesToClean;
private int numErrors;
private static final int REMOVAL_WAIT_TIME_MS = 5000;
/**
*
* @param nodeService
* @param transactionService
* @param deleteBatchCount
*/
public Cleaner(NodeService nodeService, TransactionService transactionService, int deleteBatchCount)
{
this.nodeService = nodeService;
this.transactionService = transactionService;
this.deleteBatchCount = deleteBatchCount;
}
/**
*
* It deletes the {@link java.util.List List} of {@link org.alfresco.service.cmr.repository.NodeRef NodeRef}
* received as argument.
*
* @param nodes
*
* return The number of deleted nodes
*/
private int deleteNodes(List<NodeRef> nodes)
{
AtomicInteger deletedNodes = new AtomicInteger();
for (NodeRef nodeRef : nodes)
{
// create a new transaction for each deletion so the transactions are smaller and the progress of the
// cleaner is not lost in case of any problems encountered during the job execution
AuthenticationUtil.runAsSystem(() -> {
RetryingTransactionCallback<Void> txnWork = () -> {
try
{
nodeService.deleteNode(nodeRef);
}
catch (InvalidNodeRefException inre)
{
numErrors++;
}
deletedNodes.getAndIncrement();
// Waiting REMOVAL_WAIT_TIME_MS seconds for next deletion so we don't need to have many nodes on the trash can
Thread.sleep(REMOVAL_WAIT_TIME_MS);
return null;
};
return transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false, true);
});
}
return deletedNodes.get();
}
/**
*
* It returns the {@link java.util.List List} of {@link org.alfresco.service.cmr.repository.NodeRef NodeRef} of the
* archive store set to be deleted according to configuration for <b>deleteBatchCount</b>.
*
* @return
*/
private List<NodeRef> getBatchToDelete()
{
return getChildAssocs().stream().map(ChildAssociationRef::getChildRef).collect(Collectors.toList());
}
/**
*
* It will return the first {@link #deleteBatchCount}
* {@link org.alfresco.service.cmr.repository.ChildAssociationRef}s of type {@link ContentModel}.ASSOC_CHILDREN from
* the archive store set.
*
* @return
*/
private List<ChildAssociationRef> getChildAssocs()
{
StoreRef archiveStore = new StoreRef(ARCHIVE_STORE_URL);
NodeRef archiveRoot = nodeService.getRootNode(archiveStore);
return nodeService.getChildAssocs(archiveRoot, ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL, deleteBatchCount,
false);
}
/**
*
* The method that will clean the specified <b>archiveStoreUrl</b> to the limits defined by the values set for
* <b>deleteBatchCount</b>.
*/
public void clean()
{
LOGGER.info("Running TestCleaner");
// Retrieve in a new read-only transaction the list of nodes to be deleted by the TestCleaner
AuthenticationUtil.runAsSystem(() -> {
RetryingTransactionCallback<Void> txnWork = () -> {
nodesToClean = getBatchToDelete();
LOGGER.info(String.format("Number of nodes to delete: %s", nodesToClean.size()));
return null;
};
return transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, true, true);
});
int deletedNodes = deleteNodes(nodesToClean);
LOGGER.info("TestCleaner finished. Number of deleted nodes: {}", deletedNodes);
}
public boolean hasErrors()
{
return numErrors > 0;
}
}

View File

@@ -1,45 +0,0 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2023 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.schedule;
import org.quartz.JobExecutionContext;
/**
* Test job that will execute {@link Cleaner}
*
* @author Tiago Salvado
*
* @see AbstractScheduledLockedJob
*/
public class CleanerJob extends AbstractScheduledLockedJob
{
@Override
public void executeJob(JobExecutionContext jobContext)
{
Cleaner testCleaner = (Cleaner) jobContext.getJobDetail().getJobDataMap().get("testCleaner");
testCleaner.clean();
}
}

View File

@@ -1,36 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="testCleaner" class="org.alfresco.schedule.Cleaner">
<constructor-arg ref="nodeService" />
<constructor-arg ref="transactionService" />
<constructor-arg value="100" />
</bean>
<bean id="testSchedulerAccessor" class="org.springframework.scheduling.quartz.SchedulerAccessorBean">
<property name="scheduler" ref="schedulerFactory"/>
<property name="triggers">
<list>
<ref bean="testCleanerTrigger"/>
</list>
</property>
</bean>
<bean id="testCleanerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="cronExpression" value="* * * * * ? 2099"/>
<property name="jobDetail" ref="testCleanerJobDetail"/>
</bean>
<bean id="testCleanerJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="org.alfresco.schedule.CleanerJob"/>
<property name="jobDataAsMap">
<map>
<entry key="testCleaner" value-ref="testCleaner" />
<entry key="jobLockService" value-ref="jobLockService" />
</map>
</property>
</bean>
</beans>