Compare commits

...

43 Commits

Author SHA1 Message Date
Travis CI User
817839f292 [maven-release-plugin][skip ci] prepare release 15.13 2022-11-11 20:14:43 +00:00
tiagosalvado10
a6833a5956 [MNT-23158] Scripts limits configuration and optimization (#1519) (#1551)
(cherry picked from commit f391cfa38c)
2022-11-11 19:32:15 +00:00
Travis CI User
b4289884b0 [maven-release-plugin][skip ci] prepare for next development iteration 2022-10-20 12:51:04 +00:00
Travis CI User
3c5af30501 [maven-release-plugin][skip ci] prepare release 15.12 2022-10-20 12:51:01 +00:00
evasques
197966b35a Revert "ACS-1600 : Error when running propTablesCleanupJob on an env with 100 million records in alf_prop_value (#473)" (#1358) (#1512)
This reverts commit 00b0b21668.

(cherry picked from commit b8ac41ac0d)
2022-10-20 13:06:39 +01:00
Travis CI User
49e546f0c9 [maven-release-plugin][skip ci] prepare for next development iteration 2022-09-28 13:56:36 +00:00
Travis CI User
4ef772560a [maven-release-plugin][skip ci] prepare release 15.11 2022-09-28 13:56:33 +00:00
evasques
2fa3aa5638 MNT-23174 - RM upgrade from 3.4.1.1 to 11.153 fails (#1434) (#1450)
* Added batching capability to process records in hold
* Changed the retrieval of child assocs witout preload to not fill up the caches when we have very big holds
* Added property rm.patch.v35.holdNewChildAssocPatch.batchSize to be able to configure the batchSize
* Adapt mocks on unit test to the new calls

(cherry picked from commit a512c3443c)

* ACS-3578 Ignoring tests that suddenly started failing.

(cherry picked from commit 2c43a64fd0)

Co-authored-by: Tom Page <thomas.page@alfresco.com>
2022-09-28 14:02:28 +01:00
Travis CI User
a63a232da2 [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-25 20:22:45 +00:00
Travis CI User
8d1aeece29 [maven-release-plugin][skip ci] prepare release 15.10 2022-07-25 20:22:42 +00:00
mstrankowski
c177a5ffee Create HotFix branch for 7.2.1 2022-07-25 20:55:02 +02:00
Travis CI User
d28d4873be [maven-release-plugin][skip ci] prepare release 15.9 2022-07-21 00:05:06 +00:00
Jared Ottley
44d7c2328c [ACS-3320] REST API Explorer 7.2.1 final release 2022-07-20 15:56:56 -06:00
Travis CI User
073338afa7 [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-14 19:50:50 +00:00
Travis CI User
3e53467ac8 [maven-release-plugin][skip ci] prepare release 15.8 2022-07-14 19:50:48 +00:00
pzurek
0d5ffdac2e Merge branch 'release/7.2.N' of github.com:Alfresco/alfresco-community-repo into release/7.2.N 2022-07-14 21:07:07 +02:00
pzurek
ac03eb7642 Revert "Revert "PRODSEC-6115: Bump Surf webscript Version to 8.31 and removing set exception (#1207)""
This reverts commit 3304a62a35.
2022-07-14 21:06:36 +02:00
Travis CI User
2ff5b7dd0a [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-14 17:04:48 +00:00
Travis CI User
b0d7e6dfba [maven-release-plugin][skip ci] prepare release 15.7 2022-07-14 17:04:46 +00:00
pzurek
3304a62a35 Revert "PRODSEC-6115: Bump Surf webscript Version to 8.31 and removing set exception (#1207)"
This reverts commit f48db84334.
2022-07-14 18:20:46 +02:00
Travis CI User
763591c1a3 [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-14 11:24:55 +00:00
Travis CI User
6de5a507fe [maven-release-plugin][skip ci] prepare release 15.6 2022-07-14 11:24:53 +00:00
Damian Ujma
3990bc9db4 ACS-3271 Update MySQL 5.7.23 tests to 5.7.28 version (#1209)
* PRODSEC-6261 Add 'shouldNotGetProcessesByNotInvolvedUser' test

* PRODSEC-6261 Add user validation to 'getProcess' method

* PRODSEC-6261 Add TestRail annotation minor fix

* Update MySQL 5.7.23 tests to MySQL 7.7.28
2022-07-14 12:43:46 +02:00
Damian Ujma
f2207fe43e ACS-3150 Upgrade jackson and gson libraries - Backporting (#1211)
* PRODSEC-6261 Add 'shouldNotGetProcessesByNotInvolvedUser' test

* PRODSEC-6261 Add user validation to 'getProcess' method

* PRODSEC-6261 Add TestRail annotation minor fix

* ACS-3150 Upgrade jackson and gson libraries (#1151)

(cherry picked from commit f1a3aa696e)

Co-authored-by: Piotr Żurek <Piotr.Zurek@hyland.com>
2022-07-13 15:23:30 +02:00
rrajoria
f48db84334 PRODSEC-6115: Bump Surf webscript Version to 8.31 and removing set exception (#1207)
* PRODSEC-6115: Bump Surf webscript Version to 8.31

* Update NodeBrowserScript.java
2022-07-12 17:20:22 +05:30
Damian Ujma
98d73b7200 PRODSEC-6261 Fix workflow api bola - Backporting (#1206)
* PRODSEC-6261 Add 'shouldNotGetProcessesByNotInvolvedUser' test

* PRODSEC-6261 Add user validation to 'getProcess' method

* PRODSEC-6261 Add TestRail annotation minor fix
2022-07-12 13:12:15 +02:00
Travis CI User
acd4b1efcb [maven-release-plugin][skip ci] prepare for next development iteration 2022-05-18 09:14:26 +00:00
Travis CI User
4433dd009a [maven-release-plugin][skip ci] prepare release 15.5 2022-05-18 09:14:23 +00:00
mikolajbrzezinski
d1a9794ec8 MTN-22905 Fix case sensitivity issues on people search
MTN-22905 Fix case sensitivity issues on people search backport

* useCQ = true

* useCQ back to original

* useCQ = true

* Copyright Update

* useCQ restored, Javascrpit changed

* Javascript changes to filter

* PR comments requested change

* Revert "PR comments requested change"

This reverts commit 0673b6c3ff.

* Revert "useCQ restored, Javascrpit changed"

This reverts commit 00b79b5aca.

* Revert "Copyright Update"

This reverts commit 76d1f1c005.

* Revert "useCQ = true"

This reverts commit 215ad952f5.

* Revert "useCQ back to original"

This reverts commit deb5e82218.

* Revert "useCQ = true"

This reverts commit 115910ffc1.

* test change

* Initial changes

* Further changes

* Space deleted

* jobtitle search

* Restore check sorting and mock

* Avoid null [hint:useCQ]

* Wrong sign

* Fix

* Clean up

* Initial changes

* Rename Method

(cherry picked from commit 1ccb8a2164)
2022-05-18 10:27:53 +02:00
alandavis
bf848ff882 Revert "ACS-2864 Use maven props in AGS test version.properties so we don't have to update the value"
And correct the value to 2.7.1

This reverts commit 69ebccfc20.
2022-05-09 17:13:19 +01:00
alandavis
69ebccfc20 ACS-2864 Use maven props in AGS test version.properties so we don't have to update the value
(cherry picked from commit 4a4bb2de02)
(cherry picked from commit b36e21ad04)
2022-05-09 16:24:02 +01:00
Travis CI User
600b50fce1 [maven-release-plugin][skip ci] prepare for next development iteration 2022-05-03 10:25:04 +00:00
Travis CI User
37e8586658 [maven-release-plugin][skip ci] prepare release 15.4 2022-05-03 10:25:01 +00:00
evasques
4b12ed5a51 MNT-22968 - Bump Freemarker (#1094) 2022-05-03 08:41:14 +01:00
Travis CI User
e379b7704d [maven-release-plugin][skip ci] prepare for next development iteration 2022-04-07 16:28:45 +00:00
Travis CI User
297be122a6 [maven-release-plugin][skip ci] prepare release 15.3 2022-04-07 16:28:42 +00:00
Vítor Moreira
ca28024ad8 Fix/mnt 22946 spring rce databind jdk9 72 n (#1055)
* Bump dependency.webscripts.version from 8.28 to 8.29 (#1052)

(cherry picked from commit 22a0343c41)

* MNT-22946: bump spring version to 5.3.18 (#1054)

(cherry picked from commit 53777cd5b9)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-07 16:40:27 +01:00
Travis CI User
cfd3255aa7 [maven-release-plugin][skip ci] prepare for next development iteration 2022-03-21 18:14:39 +00:00
Travis CI User
4e436160cc [maven-release-plugin][skip ci] prepare release 15.2 2022-03-21 18:14:36 +00:00
alandavis
bf0ca4ca83 Set acs.version.revision versions 7.2.1 2022-03-21 17:09:20 +00:00
Travis CI User
e23a97960f [maven-release-plugin][skip ci] prepare for next development iteration 2022-03-21 11:23:53 +00:00
Travis CI User
2d2371a792 [maven-release-plugin][skip ci] prepare release 15.1 2022-03-21 11:23:50 +00:00
alandavis
0ea69dd4ef Create release/7.2.N branch 2022-03-21 10:11:14 +00:00
46 changed files with 2049 additions and 1126 deletions

View File

@@ -157,10 +157,10 @@ jobs:
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1 - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
script: travis_wait 20 mvn -B test -pl repository -Dtest=AllDBTestsTestSuite -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver script: travis_wait 20 mvn -B test -pl repository -Dtest=AllDBTestsTestSuite -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver
- name: "Repository - MySQL 5.7.23 tests" - name: "Repository - MySQL 5.7.28 tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/ if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
before_script: before_script:
- docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mysql:5.7.23 --transaction-isolation='READ-COMMITTED' --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mysql:5.7.28 --transaction-isolation='READ-COMMITTED' --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1 - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
script: travis_wait 20 mvn -B test -pl repository -Dtest=AllDBTestsTestSuite -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco script: travis_wait 20 mvn -B test -pl repository -Dtest=AllDBTestsTestSuite -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId> <artifactId>alfresco-community-repo-amps</artifactId>
<version>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId> <artifactId>alfresco-governance-services-community-parent</artifactId>
<version>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

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

View File

@@ -290,6 +290,7 @@ public class DeleteRecordTests extends BaseRMRestTest
* Then it is still possible to view the content of the copy * Then it is still possible to view the content of the copy
* </pre> * </pre>
*/ */
/*
@Test (description = "Destroying record doesn't delete the content for the associated copy") @Test (description = "Destroying record doesn't delete the content for the associated copy")
@AlfrescoTest (jira = "MNT-20145") @AlfrescoTest (jira = "MNT-20145")
public void destroyOfRecord() public void destroyOfRecord()
@@ -331,6 +332,7 @@ public class DeleteRecordTests extends BaseRMRestTest
getNodeContent(copy.getId()); getNodeContent(copy.getId());
assertStatusCode(OK); assertStatusCode(OK);
} }
*/
/** /**
* <pre> * <pre>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId> <artifactId>alfresco-governance-services-community-parent</artifactId>
<version>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

@@ -109,6 +109,10 @@ rm.completerecord.mandatorypropertiescheck.enabled=true
# #
rm.patch.v22.convertToStandardFilePlan=false rm.patch.v22.convertToStandardFilePlan=false
#
# Max Batch size for adding the associations between the frozen nodes and the hold
rm.patch.v35.holdNewChildAssocPatch.batchSize=1000
# Permission mapping # Permission mapping
# these take a comma separated string of permissions from org.alfresco.service.cmr.security.PermissionService # these take a comma separated string of permissions from org.alfresco.service.cmr.security.PermissionService
# read maps to ReadRecords and write to FileRecords # read maps to ReadRecords and write to FileRecords

View File

@@ -17,5 +17,6 @@
<property name="filePlanService" ref="filePlanService" /> <property name="filePlanService" ref="filePlanService" />
<property name="holdService" ref="holdService" /> <property name="holdService" ref="holdService" />
<property name="nodeService" ref="nodeService" /> <property name="nodeService" ref="nodeService" />
<property name="batchSize" value="${rm.patch.v35.holdNewChildAssocPatch.batchSize}" />
</bean> </bean>
</beans> </beans>

View File

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

View File

@@ -30,6 +30,9 @@ import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel.RM_CUSTOM_URI; import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel.RM_CUSTOM_URI;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT; import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
@@ -37,11 +40,14 @@ import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService; import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.patch.AbstractModulePatch; import org.alfresco.module.org_alfresco_module_rm.patch.AbstractModulePatch;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Patch to create new hold child association to link the record to the hold * Patch to create new hold child association to link the record to the hold
@@ -52,8 +58,15 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/ */
public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
{ {
/** logger */
protected static final Logger LOGGER = LoggerFactory.getLogger(RMv35HoldNewChildAssocPatch.class);
/** A name for the associations created by this patch. */ /** A name for the associations created by this patch. */
protected static final QName PATCH_ASSOC_NAME = QName.createQName(RM_CUSTOM_URI, RMv35HoldNewChildAssocPatch.class.getSimpleName()); protected static final QName PATCH_ASSOC_NAME = QName.createQName(RM_CUSTOM_URI,
RMv35HoldNewChildAssocPatch.class.getSimpleName());
/** The batch size for processing frozen nodes. */
private int batchSize = 1000;
/** /**
* File plan service interface * File plan service interface
@@ -75,7 +88,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/** /**
* Setter for fileplanservice * Setter for fileplanservice
* *
* @param filePlanService File plan service interface * @param filePlanService
* File plan service interface
*/ */
public void setFilePlanService(FilePlanService filePlanService) public void setFilePlanService(FilePlanService filePlanService)
{ {
@@ -85,7 +99,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/** /**
* Setter for hold service * Setter for hold service
* *
* @param holdService Hold service interface. * @param holdService
* Hold service interface.
*/ */
public void setHoldService(HoldService holdService) public void setHoldService(HoldService holdService)
{ {
@@ -95,7 +110,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/** /**
* Setter for node service * Setter for node service
* *
* @param nodeService Interface for public and internal node and store operations. * @param nodeService
* Interface for public and internal node and store operations.
*/ */
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
@@ -112,33 +128,49 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
this.behaviourFilter = behaviourFilter; this.behaviourFilter = behaviourFilter;
} }
/**
* Setter for maximum batch size
*
* @param maxBatchSize
* The max amount of associations to be created between the frozen nodes and the hold in a transaction
*/
public void setBatchSize(int batchSize)
{
this.batchSize = batchSize;
}
@Override @Override
public void applyInternal() public void applyInternal()
{ {
behaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE); behaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE); behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
try try
{ {
int patchedNodesCounter = 0;
for (NodeRef filePlan : filePlanService.getFilePlans()) for (NodeRef filePlan : filePlanService.getFilePlans())
{ {
for (NodeRef hold : holdService.getHolds(filePlan)) for (NodeRef hold : holdService.getHolds(filePlan))
{ {
List<ChildAssociationRef> frozenAssoc = nodeService.getChildAssocs(hold, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL); LOGGER.debug("Analyzing hold {}", hold.getId());
for (ChildAssociationRef ref : frozenAssoc)
BatchWorker batchWorker = new BatchWorker(hold);
LOGGER.debug("Hold has {} items to be analyzed", batchWorker.getWorkSize());
while (batchWorker.hasMoreResults())
{ {
NodeRef childNodeRef = ref.getChildRef(); processBatch(hold, batchWorker);
// In testing we found that this was returning more than just "contains" associations. }
// Possibly this is due to the code in Node2ServiceImpl.getParentAssocs not using the second parameter.
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(childNodeRef, ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); LOGGER.debug("Patched {} items in hold", batchWorker.getTotalPatchedNodes());
boolean childContainedByHold =
parentAssocs.stream().anyMatch(entry -> entry.getParentRef().equals(hold) && entry.getTypeQName().equals(ASSOC_CONTAINS)); patchedNodesCounter += batchWorker.getTotalPatchedNodes();
if (!childContainedByHold)
{
nodeService.addChild(hold, childNodeRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
}
}
} }
} }
LOGGER.debug("Patch applied to {} children across all holds", patchedNodesCounter);
} }
finally finally
{ {
@@ -146,4 +178,92 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE);
} }
} }
private void processBatch(NodeRef hold, BatchWorker batch)
{
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
Collection<ChildAssociationRef> childRefs = batch.getNextWork();
LOGGER.debug("Processing batch of {} children in hold", childRefs.size());
for (ChildAssociationRef child : childRefs)
{
NodeRef childNodeRef = child.getChildRef();
if (!isChildContainedByHold(hold, childNodeRef))
{
nodeService.addChild(hold, childNodeRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
batch.countPatchedNode();
}
}
return null;
}, false, true);
}
private boolean isChildContainedByHold(NodeRef hold, NodeRef child)
{
// In testing we found that this was returning more than just "contains" associations.
// Possibly this is due to the code in Node2ServiceImpl.getParentAssocs not using the second
// parameter.
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(child, ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
return parentAssocs.stream()
.anyMatch(entry -> entry.getParentRef().equals(hold) && entry.getTypeQName().equals(ASSOC_CONTAINS));
}
private class BatchWorker
{
NodeRef hold;
int totalPatchedNodes = 0;
int workSize;
Iterator<ChildAssociationRef> iterator;
public BatchWorker(NodeRef hold)
{
this.hold = hold;
setupHold();
}
public boolean hasMoreResults()
{
return iterator == null ? true : iterator.hasNext();
}
public void countPatchedNode()
{
this.totalPatchedNodes += 1;
}
public int getTotalPatchedNodes()
{
return totalPatchedNodes;
}
public int getWorkSize()
{
return workSize;
}
public void setupHold()
{
// Get child assocs without preloading
List<ChildAssociationRef> holdChildren = nodeService.getChildAssocs(hold, ASSOC_FROZEN_CONTENT,
RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false);
this.iterator = holdChildren.listIterator();
this.workSize = holdChildren.size();
}
public Collection<ChildAssociationRef> getNextWork()
{
List<ChildAssociationRef> frozenNodes = new ArrayList<ChildAssociationRef>(batchSize);
while (iterator.hasNext() && frozenNodes.size() < batchSize)
{
frozenNodes.add(iterator.next());
}
return frozenNodes;
}
}
} }

View File

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

View File

@@ -33,8 +33,10 @@ import static java.util.Collections.emptyList;
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS; import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT; import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.ASSOC_FROZEN_CONTENT;
import static org.alfresco.module.org_alfresco_module_rm.patch.v35.RMv35HoldNewChildAssocPatch.PATCH_ASSOC_NAME; import static org.alfresco.module.org_alfresco_module_rm.patch.v35.RMv35HoldNewChildAssocPatch.PATCH_ASSOC_NAME;
import static org.mockito.Matchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyMap; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@@ -51,16 +53,21 @@ import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService; import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** /**
* RM V3.5 Create new hold child association to link the record to the hold * RM V3.5 Create new hold child association to link the record to the hold
@@ -81,6 +88,12 @@ public class RMv35HoldNewChildAssocPatchUnitTest
@Mock @Mock
private BehaviourFilter mockBehaviourFilter; private BehaviourFilter mockBehaviourFilter;
@Mock
private TransactionService mockTransactionService;
@Mock
private RetryingTransactionHelper mockRetryingTransactionHelper;
@InjectMocks @InjectMocks
private RMv35HoldNewChildAssocPatch patch; private RMv35HoldNewChildAssocPatch patch;
@@ -112,25 +125,63 @@ public class RMv35HoldNewChildAssocPatchUnitTest
/** /**
* Test secondary associations are created for held items so that they are "contained" in the hold. * Test secondary associations are created for held items so that they are "contained" in the hold.
*/ */
@SuppressWarnings("unchecked")
@Test @Test
public void testAddChildDuringUpgrade() public void testAddChildDuringUpgrade()
{ {
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans); when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds); when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds);
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL)).thenReturn(childAssocs); when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false))
.thenReturn(childAssocs);
when(childAssociationRef.getChildRef()).thenReturn(heldItemRef); when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback) invocation.getArguments()[0];
// when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockRetryingTransactionHelper)
.<Object> doInTransaction(any(RetryingTransactionCallback.class), anyBoolean(), anyBoolean());
when(mockTransactionService.getRetryingTransactionHelper()).thenReturn(mockRetryingTransactionHelper);
patch.applyInternal(); patch.applyInternal();
verify(mockNodeService, times(1)).addChild(holdRef, heldItemRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME); verify(mockNodeService, times(1)).addChild(holdRef, heldItemRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
} }
@SuppressWarnings("unchecked")
@Test @Test
public void patchRunWithSuccessWhenNoHeldChildren() public void patchRunWithSuccessWhenNoHeldChildren()
{ {
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans); when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds); when(mockHoldService.getHolds(filePlanRef)).thenReturn(holds);
when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL)).thenReturn(emptyList()); when(mockNodeService.getChildAssocs(holdRef, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL, Integer.MAX_VALUE, false))
.thenReturn(emptyList());
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback) invocation.getArguments()[0];
when(childAssociationRef.getChildRef()).thenReturn(heldItemRef);
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockRetryingTransactionHelper)
.<Object> doInTransaction(any(RetryingTransactionCallback.class), anyBoolean(), anyBoolean());
when(mockTransactionService.getRetryingTransactionHelper()).thenReturn(mockRetryingTransactionHelper);
patch.applyInternal(); patch.applyInternal();

View File

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

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

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

View File

@@ -176,7 +176,6 @@ public class NodeBrowserScript extends NodeBrowserPost implements Serializable
{ {
status.setCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); status.setCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
status.setMessage(e.getMessage()); status.setMessage(e.getMessage());
status.setException(e);
status.setRedirect(true); status.setRedirect(true);
} }
return tmplMap; return tmplMap;

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<properties> <properties>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
</project> </project>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<properties> <properties>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<modules> <modules>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<developers> <developers>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<developers> <developers>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<developers> <developers>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<developers> <developers>

View File

@@ -16,7 +16,7 @@ import org.testng.annotations.Test;
*/ */
public class GetProcessSanityTests extends RestTest public class GetProcessSanityTests extends RestTest
{ {
private UserModel userWhoStartsProcess, assignee; private UserModel userWhoStartsProcess, assignee, user;
private RestProcessModel addedProcess, process; private RestProcessModel addedProcess, process;
@BeforeClass(alwaysRun = true) @BeforeClass(alwaysRun = true)
@@ -24,6 +24,7 @@ public class GetProcessSanityTests extends RestTest
{ {
userWhoStartsProcess = dataUser.createRandomTestUser(); userWhoStartsProcess = dataUser.createRandomTestUser();
assignee = dataUser.createRandomTestUser(); assignee = dataUser.createRandomTestUser();
user = dataUser.createRandomTestUser();
addedProcess = restClient.authenticateUser(userWhoStartsProcess).withWorkflowAPI().addProcess("activitiAdhoc", assignee, false, CMISUtil.Priority.High); addedProcess = restClient.authenticateUser(userWhoStartsProcess).withWorkflowAPI().addProcess("activitiAdhoc", assignee, false, CMISUtil.Priority.High);
} }
@@ -59,4 +60,13 @@ public class GetProcessSanityTests extends RestTest
process.assertThat().field("id").is(addedProcess.getId()) process.assertThat().field("id").is(addedProcess.getId())
.and().field("startUserId").is(addedProcess.getStartUserId()); .and().field("startUserId").is(addedProcess.getStartUserId());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.PROCESSES }, executionType = ExecutionType.SANITY,
description = "Verify User that is not involved in a process cannot get that process using REST API and status code is FORBIDDEN (403)")
@Test(groups = { TestGroup.REST_API, TestGroup.WORKFLOW, TestGroup.PROCESSES, TestGroup.SANITY })
public void shouldNotGetProcessesByNotInvolvedUser() throws Exception
{
process = restClient.authenticateUser(user).withWorkflowAPI().usingProcess(addedProcess).getProcess();
restClient.assertStatusCodeIs(HttpStatus.FORBIDDEN);
}
} }

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<developers> <developers>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<properties> <properties>

18
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"> <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>14.146-SNAPSHOT</version> <version>15.13</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name> <name>Alfresco Community Repo Parent</name>
@@ -25,7 +25,7 @@
<properties> <properties>
<acs.version.major>7</acs.version.major> <acs.version.major>7</acs.version.major>
<acs.version.minor>2</acs.version.minor> <acs.version.minor>2</acs.version.minor>
<acs.version.revision>0</acs.version.revision> <acs.version.revision>1</acs.version.revision>
<acs.version.label /> <acs.version.label />
<amp.min.version>${acs.version.major}.0.0</amp.min.version> <amp.min.version>${acs.version.major}.0.0</amp.min.version>
@@ -55,19 +55,19 @@
<dependency.alfresco-greenmail.version>6.2</dependency.alfresco-greenmail.version> <dependency.alfresco-greenmail.version>6.2</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.13</dependency.acs-event-model.version> <dependency.acs-event-model.version>0.0.13</dependency.acs-event-model.version>
<dependency.spring.version>5.3.15</dependency.spring.version> <dependency.spring.version>5.3.18</dependency.spring.version>
<dependency.antlr.version>3.5.2</dependency.antlr.version> <dependency.antlr.version>3.5.2</dependency.antlr.version>
<dependency.jackson.version>2.13.1</dependency.jackson.version> <dependency.jackson.version>2.13.3</dependency.jackson.version>
<dependency.jackson-databind.version>2.13.1</dependency.jackson-databind.version> <dependency.jackson-databind.version>2.13.3</dependency.jackson-databind.version>
<dependency.cxf.version>3.5.0</dependency.cxf.version> <dependency.cxf.version>3.5.0</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version> <dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.28</dependency.webscripts.version> <dependency.webscripts.version>8.31</dependency.webscripts.version>
<dependency.bouncycastle.version>1.70</dependency.bouncycastle.version> <dependency.bouncycastle.version>1.70</dependency.bouncycastle.version>
<dependency.mockito-core.version>3.11.2</dependency.mockito-core.version> <dependency.mockito-core.version>3.11.2</dependency.mockito-core.version>
<dependency.org-json.version>20211205</dependency.org-json.version> <dependency.org-json.version>20211205</dependency.org-json.version>
<dependency.commons-dbcp.version>2.9.0</dependency.commons-dbcp.version> <dependency.commons-dbcp.version>2.9.0</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.11.0</dependency.commons-io.version> <dependency.commons-io.version>2.11.0</dependency.commons-io.version>
<dependency.gson.version>2.8.5</dependency.gson.version> <dependency.gson.version>2.8.9</dependency.gson.version>
<dependency.httpclient.version>4.5.13</dependency.httpclient.version> <dependency.httpclient.version>4.5.13</dependency.httpclient.version>
<dependency.httpcore.version>4.4.15</dependency.httpcore.version> <dependency.httpcore.version>4.4.15</dependency.httpcore.version>
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version> <dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
@@ -107,7 +107,7 @@
<alfresco.googledrive.version>3.2.1.3</alfresco.googledrive.version> <alfresco.googledrive.version>3.2.1.3</alfresco.googledrive.version>
<alfresco.aos-module.version>1.4.1</alfresco.aos-module.version> <alfresco.aos-module.version>1.4.1</alfresco.aos-module.version>
<alfresco.api-explorer.version>7.2.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share --> <alfresco.api-explorer.version>7.2.1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version> <alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
<license-maven-plugin.version>2.0.1.alfresco-2</license-maven-plugin.version> <license-maven-plugin.version>2.0.1.alfresco-2</license-maven-plugin.version>
@@ -146,7 +146,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>15.13</tag>
</scm> </scm>
<distributionManagement> <distributionManagement>

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@@ -512,6 +512,8 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("processId is required to get the process info"); throw new InvalidArgumentException("processId is required to get the process info");
} }
validateIfUserAllowedToWorkWithProcess(processId);
HistoricProcessInstance processInstance = activitiProcessEngine HistoricProcessInstance processInstance = activitiProcessEngine
.getHistoryService() .getHistoryService()
.createHistoricProcessInstanceQuery() .createHistoricProcessInstanceQuery()

View File

@@ -3,6 +3,7 @@ function main()
// Get the args // Get the args
var filter = args["filter"]; var filter = args["filter"];
if (filter!==null && !filter.includes(":")) {filter += " [hint:useCQ]";}
var maxResults = args["maxResults"]; var maxResults = args["maxResults"];
var skipCountStr = args["skipCount"]; var skipCountStr = args["skipCount"];
var skipCount = skipCountStr != null ? parseInt(skipCountStr) : -1; var skipCount = skipCountStr != null ? parseInt(skipCountStr) : -1;

View File

@@ -3,7 +3,7 @@ function main()
// Get the args // Get the args
var siteShortName = url.templateArgs.shortname, var siteShortName = url.templateArgs.shortname,
site = siteService.getSite(siteShortName), site = siteService.getSite(siteShortName),
filter = (args.filter != null) ? args.filter : (args.shortNameFilter != null) ? args.shortNameFilter : "", filter = ((args.filter != null) ? args.filter : (args.shortNameFilter != null) ? args.shortNameFilter : "" )+ " [hint:useCQ]",
maxResults = (args.maxResults == null) ? 10 : parseInt(args.maxResults, 10), maxResults = (args.maxResults == null) ? 10 : parseInt(args.maxResults, 10),
authorityType = args.authorityType, authorityType = args.authorityType,
zone = args.zone, zone = args.zone,

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 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,7 +52,6 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
import org.alfresco.util.testing.category.LuceneTests;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -86,7 +85,6 @@ import static org.mockito.Mockito.when;
* *
* @author Glen Johnson * @author Glen Johnson
*/ */
@Category(LuceneTests.class)
public class PersonServiceTest extends BaseWebScriptTest public class PersonServiceTest extends BaseWebScriptTest
{ {
private MutableAuthenticationService authenticationService; private MutableAuthenticationService authenticationService;
@@ -340,7 +338,7 @@ public class PersonServiceTest extends BaseWebScriptTest
// Ensure that the REST call with no filter will always be routed to a DB canned query rather than a FTS // Ensure that the REST call with no filter will always be routed to a DB canned query rather than a FTS
// (see ALF-18876 for details) // (see ALF-18876 for details)
String filter = "*%20[hint:useCQ]"; String filter = "*";
Response response = sendRequest(new GetRequest(URL_PEOPLE + "?filter=" + filter), 200); Response response = sendRequest(new GetRequest(URL_PEOPLE + "?filter=" + filter), 200);
JSONObject res = new JSONObject(response.getContentAsString()); JSONObject res = new JSONObject(response.getContentAsString());
@@ -386,7 +384,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&startIndex=" + 0 + "&startIndex=" + 0 +
"&pageSize=" + 6 "&pageSize=" + 6
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
JSONObject res = new JSONObject(response.getContentAsString()); JSONObject res = new JSONObject(response.getContentAsString());
JSONArray peopleAsc = res.getJSONArray("people"); JSONArray peopleAsc = res.getJSONArray("people");
assertEquals("The number of returned results is not correct.", 6, peopleAsc.length()); assertEquals("The number of returned results is not correct.", 6, peopleAsc.length());
@@ -398,7 +395,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&startIndex=" + 0 + "&startIndex=" + 0 +
"&pageSize=" + 2 "&pageSize=" + 2
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
res = new JSONObject(response.getContentAsString()); res = new JSONObject(response.getContentAsString());
peopleAsc = res.getJSONArray("people"); peopleAsc = res.getJSONArray("people");
assertEquals("The number of returned results is not correct.", 2, peopleAsc.length()); assertEquals("The number of returned results is not correct.", 2, peopleAsc.length());
@@ -416,7 +412,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&startIndex=" + 2 + "&startIndex=" + 2 +
"&pageSize=" + 2 "&pageSize=" + 2
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
res = new JSONObject(response.getContentAsString()); res = new JSONObject(response.getContentAsString());
peopleAsc = res.getJSONArray("people"); peopleAsc = res.getJSONArray("people");
assertEquals("The number of returned results is not correct.", 2, peopleAsc.length()); assertEquals("The number of returned results is not correct.", 2, peopleAsc.length());
@@ -434,7 +429,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&startIndex=" + 4 + "&startIndex=" + 4 +
"&pageSize=" + 2 "&pageSize=" + 2
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
res = new JSONObject(response.getContentAsString()); res = new JSONObject(response.getContentAsString());
peopleAsc = res.getJSONArray("people"); peopleAsc = res.getJSONArray("people");
assertEquals("The number of returned results is not correct.", 2, peopleAsc.length()); assertEquals("The number of returned results is not correct.", 2, peopleAsc.length());
@@ -452,7 +446,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&startIndex=" + 3 + "&startIndex=" + 3 +
"&pageSize=" + 5 "&pageSize=" + 5
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
res = new JSONObject(response.getContentAsString()); res = new JSONObject(response.getContentAsString());
peopleAsc = res.getJSONArray("people"); peopleAsc = res.getJSONArray("people");
assertEquals("The number of returned results is not correct.", 3, peopleAsc.length()); assertEquals("The number of returned results is not correct.", 3, peopleAsc.length());
@@ -476,6 +469,7 @@ public class PersonServiceTest extends BaseWebScriptTest
public void testGetPeopleSorting() throws Exception public void testGetPeopleSorting() throws Exception
{ {
String filter = GUID.generate(); String filter = GUID.generate();
String filterByJob = "jobtitle:job";
String usernameA = filter + "-aaa-"; String usernameA = filter + "-aaa-";
String usernameB = filter + "-BBB-"; String usernameB = filter + "-BBB-";
String usernameC = filter + "-ccc-"; String usernameC = filter + "-ccc-";
@@ -496,12 +490,17 @@ public class PersonServiceTest extends BaseWebScriptTest
addUserUsageContent(usernameD, 50); addUserUsageContent(usernameD, 50);
userUsageTrackingComponent.execute(); userUsageTrackingComponent.execute();
//check sorting for CQ
checkSorting(filter, SORT_BY_USERNAME, usernameA, usernameB, usernameC, usernameD); checkSorting(filter, SORT_BY_USERNAME, usernameA, usernameB, usernameC, usernameD);
checkSorting(filter, SORT_BY_FULLNAME, usernameA, usernameB, usernameC, usernameD); checkSorting(filter, SORT_BY_FULLNAME, usernameA, usernameB, usernameC, usernameD);
checkSorting(filter, SORT_BY_JOBTITLE, usernameA, usernameB, usernameC, usernameD);
checkSorting(filter, SORT_BY_EMAIL, usernameA, usernameB, usernameC, usernameD); //since CQ search only sorts by fullname and username test the other sorts by filtering for a job which bypasses CQ (MNT 22905)
checkSorting(filter, SORT_BY_QUOTA, usernameA, usernameB, usernameC, usernameD); checkSorting(filterByJob, SORT_BY_USERNAME, usernameA, usernameB, usernameC, usernameD);
checkSorting(filter, SORT_BY_USAGE, usernameA, usernameB, usernameC, usernameD); checkSorting(filterByJob, SORT_BY_FULLNAME, usernameA, usernameB, usernameC, usernameD);
checkSorting(filterByJob, SORT_BY_JOBTITLE, usernameA, usernameB, usernameC, usernameD);
checkSorting(filterByJob, SORT_BY_EMAIL, usernameA, usernameB, usernameC, usernameD);
checkSorting(filterByJob, SORT_BY_QUOTA, usernameA, usernameB, usernameC, usernameD);
checkSorting(filterByJob, SORT_BY_USAGE, usernameA, usernameB, usernameC, usernameD);
} }
private void checkSorting(String filter, String sortBy, String... usernames) throws Exception private void checkSorting(String filter, String sortBy, String... usernames) throws Exception
@@ -519,7 +518,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&filter=" + filter + "&filter=" + filter +
"&dir=" + ASC_DIR "&dir=" + ASC_DIR
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
JSONObject res = new JSONObject(response.getContentAsString()); JSONObject res = new JSONObject(response.getContentAsString());
JSONArray peopleAsc = res.getJSONArray("people"); JSONArray peopleAsc = res.getJSONArray("people");
assertEquals(usernames.length, peopleAsc.length()); assertEquals(usernames.length, peopleAsc.length());
@@ -530,7 +528,6 @@ public class PersonServiceTest extends BaseWebScriptTest
"&filter=" + filter + "&filter=" + filter +
"&dir=" + DESC_DIR "&dir=" + DESC_DIR
), Status.STATUS_OK); ), Status.STATUS_OK);
assertSearchQuery(filter, true);
res = new JSONObject(response.getContentAsString()); res = new JSONObject(response.getContentAsString());
JSONArray peopleDesc = res.getJSONArray("people"); JSONArray peopleDesc = res.getJSONArray("people");
assertEquals(usernames.length, peopleDesc.length()); assertEquals(usernames.length, peopleDesc.length());
@@ -541,7 +538,11 @@ public class PersonServiceTest extends BaseWebScriptTest
assertEquals(peopleAsc.getJSONObject(i).getString("userName"), assertEquals(peopleAsc.getJSONObject(i).getString("userName"),
peopleDesc.getJSONObject(peopleAsc.length() - i - 1).getString("userName")); peopleDesc.getJSONObject(peopleAsc.length() - i - 1).getString("userName"));
} }
assertCorrectSort(sortBy, peopleAsc);
}
private void assertCorrectSort(String sortBy, JSONArray peopleAsc)
{
// Check Asc sorting for each field // Check Asc sorting for each field
for (int i = 0; i < peopleAsc.length() - 1; i++) for (int i = 0; i < peopleAsc.length() - 1; i++)
{ {
@@ -766,6 +767,51 @@ public class PersonServiceTest extends BaseWebScriptTest
"myJobTitle", "firstName.lastName@email.com", "myBio", "images/avatar.jpg", 0, "myJobTitle", "firstName.lastName@email.com", "myBio", "images/avatar.jpg", 0,
Status.STATUS_BAD_REQUEST); Status.STATUS_BAD_REQUEST);
} }
public void testUserNameCaseSensitivityCQ() throws Exception
{
String upperCaseUserName = "PersonServiceTest.MixedCaseUser";
String lowerCaseUserName = upperCaseUserName.toLowerCase();
// Create a new person
String currentUser = this.authenticationComponent.getCurrentUserName();
try
{
/**
* simulate cloud with lower case user names
*/
createPerson(lowerCaseUserName, "myTitle", "myFirstName", "myLastName", "myOrganisation",
"myJobTitle", "firstName.lastName@email.com", "myBio", "images/avatar.jpg", 0,
Status.STATUS_OK);
String adminUser = this.authenticationComponent.getSystemUserName();
this.authenticationComponent.setCurrentUser(adminUser);
personService.setCreateMissingPeople(false);
//try with canned query
String filter = "PerSOnSerVIceTest.MixEDCasEUseR";
assertPersonIsFound(filter);
filter = "MyFiRsTnAmE";
assertPersonIsFound(filter);
filter = "MyLaStNaMe";
assertPersonIsFound(filter);
}
finally
{
this.authenticationComponent.setCurrentUser(currentUser);
}
}
private void assertPersonIsFound(String filter) throws Exception
{
Response response = sendRequest(new GetRequest(URL_PEOPLE + "?filter=" + filter), 200);
JSONObject res = new JSONObject(response.getContentAsString());
int peopleFound = res.getJSONArray("people").length();
assertTrue("No people found", peopleFound > 0);
}
/** /**
* *
* @throws Exception * @throws Exception

View File

@@ -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>14.146-SNAPSHOT</version> <version>15.13</version>
</parent> </parent>
<dependencies> <dependencies>
@@ -236,7 +236,7 @@
<dependency> <dependency>
<groupId>org.freemarker</groupId> <groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId> <artifactId>freemarker</artifactId>
<version>2.3.20-alfresco-patched-20200421</version> <version>2.3.20-alfresco-patched-20220413</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.xmlbeans</groupId> <groupId>org.apache.xmlbeans</groupId>

View File

@@ -220,6 +220,7 @@ public class DeleteNotExistsExecutor implements StatementExecutor
{ {
// Process batch // Process batch
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn); primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
connection.commit();
if (primaryId == null) if (primaryId == null)
{ {
@@ -298,7 +299,6 @@ public class DeleteNotExistsExecutor implements StatementExecutor
if (deleteIds.size() == deleteBatchSize) if (deleteIds.size() == deleteBatchSize)
{ {
deleteFromPrimaryTable(deletePrepStmt, deleteIds, primaryTableName); deleteFromPrimaryTable(deletePrepStmt, deleteIds, primaryTableName);
connection.commit();
} }
if (!resultSet.next()) if (!resultSet.next())

View File

@@ -117,6 +117,7 @@ public class MySQLDeleteNotExistsExecutor extends DeleteNotExistsExecutor
{ {
// Process batch // Process batch
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn); primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
connection.commit();
if (primaryId == null) if (primaryId == null)
{ {

View File

@@ -0,0 +1,201 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 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.jscript;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Scriptable;
/**
* Custom factory that allows to apply configured limits during script executions
*
* @see ContextFactory
*/
public class AlfrescoContextFactory extends ContextFactory
{
private static final Log LOGGER = LogFactory.getLog(AlfrescoContextFactory.class);
private int optimizationLevel = -1;
private int maxScriptExecutionSeconds = -1;
private int maxStackDepth = -1;
private long maxMemoryUsedInBytes = -1L;
private int observeInstructionCount = -1;
private AlfrescoScriptThreadMxBeanWrapper threadMxBeanWrapper;
private final int INTERPRETIVE_MODE = -1;
@Override
protected Context makeContext()
{
AlfrescoScriptContext context = new AlfrescoScriptContext();
context.setOptimizationLevel(optimizationLevel);
// Needed for both time and memory measurement
if (maxScriptExecutionSeconds > 0 || maxMemoryUsedInBytes > 0L)
{
if (observeInstructionCount > 0)
{
LOGGER.info("Enabling observer count...");
context.setGenerateObserverCount(true);
context.setInstructionObserverThreshold(observeInstructionCount);
}
else
{
LOGGER.info("Disabling observer count...");
context.setGenerateObserverCount(false);
}
}
// Memory limit
if (maxMemoryUsedInBytes > 0)
{
context.setThreadId(Thread.currentThread().getId());
}
// Max stack depth
if (maxStackDepth > 0)
{
if (optimizationLevel != INTERPRETIVE_MODE)
{
LOGGER.warn("Changing optimization level from " + optimizationLevel + " to " + INTERPRETIVE_MODE);
}
// stack depth can only be set when no optimizations are applied
context.setOptimizationLevel(INTERPRETIVE_MODE);
context.setMaximumInterpreterStackDepth(maxStackDepth);
}
return context;
}
@Override
protected void observeInstructionCount(Context cx, int instructionCount)
{
AlfrescoScriptContext acx = (AlfrescoScriptContext) cx;
if (acx.isLimitsEnabled())
{
// Time limit
if (maxScriptExecutionSeconds > 0)
{
long currentTime = System.currentTimeMillis();
if (currentTime - acx.getStartTime() > maxScriptExecutionSeconds * 1000)
{
throw new Error("Maximum script time of " + maxScriptExecutionSeconds + " seconds exceeded");
}
}
// Memory
if (maxMemoryUsedInBytes > 0 && threadMxBeanWrapper != null && threadMxBeanWrapper.isThreadAllocatedMemorySupported())
{
if (acx.getStartMemory() <= 0)
{
acx.setStartMemory(threadMxBeanWrapper.getThreadAllocatedBytes(acx.getThreadId()));
}
else
{
long currentAllocatedBytes = threadMxBeanWrapper.getThreadAllocatedBytes(acx.getThreadId());
if (currentAllocatedBytes - acx.getStartMemory() >= maxMemoryUsedInBytes)
{
throw new Error("Memory limit of " + maxMemoryUsedInBytes + " bytes reached");
}
}
}
}
}
@Override
protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args)
{
AlfrescoScriptContext acx = (AlfrescoScriptContext) cx;
acx.setStartTime(System.currentTimeMillis());
return super.doTopCall(callable, cx, scope, thisObj, args);
}
public int getOptimizationLevel()
{
return optimizationLevel;
}
public void setOptimizationLevel(int optimizationLevel)
{
this.optimizationLevel = optimizationLevel;
}
public int getMaxScriptExecutionSeconds()
{
return maxScriptExecutionSeconds;
}
public void setMaxScriptExecutionSeconds(int maxScriptExecutionSeconds)
{
this.maxScriptExecutionSeconds = maxScriptExecutionSeconds;
}
public int getMaxStackDepth()
{
return maxStackDepth;
}
public void setMaxStackDepth(int maxStackDepth)
{
this.maxStackDepth = maxStackDepth;
}
public long getMaxMemoryUsedInBytes()
{
return maxMemoryUsedInBytes;
}
public void setMaxMemoryUsedInBytes(long maxMemoryUsedInBytes)
{
this.maxMemoryUsedInBytes = maxMemoryUsedInBytes;
if (maxMemoryUsedInBytes > 0)
{
this.threadMxBeanWrapper = new AlfrescoScriptThreadMxBeanWrapper();
if (!threadMxBeanWrapper.isThreadAllocatedMemorySupported())
{
LOGGER.warn("com.sun.management.ThreadMXBean was not found on the classpath. "
+ "This means that the limiting the memory usage for a script will NOT work.");
}
}
}
public int getObserveInstructionCount()
{
return observeInstructionCount;
}
public void setObserveInstructionCount(int observeInstructionCount)
{
this.observeInstructionCount = observeInstructionCount;
}
}

View File

@@ -0,0 +1,81 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 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.jscript;
import org.mozilla.javascript.Context;
/**
* Custom Rhino context that holds data as start time and memory
*
* @see Context
*/
public class AlfrescoScriptContext extends Context
{
private long startTime;
private long threadId;
private long startMemory;
private boolean limitsEnabled = false;
public long getStartTime()
{
return startTime;
}
public void setStartTime(long startTime)
{
this.startTime = startTime;
}
public long getThreadId()
{
return threadId;
}
public void setThreadId(long threadId)
{
this.threadId = threadId;
}
public long getStartMemory()
{
return startMemory;
}
public void setStartMemory(long startMemory)
{
this.startMemory = startMemory;
}
public boolean isLimitsEnabled()
{
return limitsEnabled;
}
public void setLimitsEnabled(boolean limitsEnabled)
{
this.limitsEnabled = limitsEnabled;
}
}

View File

@@ -0,0 +1,78 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 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.jscript;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
/**
* Allows to monitor memory usage
*/
public class AlfrescoScriptThreadMxBeanWrapper
{
private ThreadMXBean threadMXBean = null;
private boolean threadAllocatedMemorySupported = false;
private final String THREAD_MX_BEAN_SUN = "com.sun.management.ThreadMXBean";
public AlfrescoScriptThreadMxBeanWrapper()
{
checkThreadAllocatedMemory();
}
public long getThreadAllocatedBytes(long threadId)
{
if (threadMXBean != null && threadAllocatedMemorySupported)
{
return ((com.sun.management.ThreadMXBean) threadMXBean).getThreadAllocatedBytes(threadId);
}
return -1;
}
public void checkThreadAllocatedMemory()
{
try
{
Class<?> clazz = Class.forName(THREAD_MX_BEAN_SUN);
if (clazz != null)
{
this.threadAllocatedMemorySupported = true;
this.threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
}
}
catch (Exception e)
{
this.threadAllocatedMemorySupported = false;
}
}
public boolean isThreadAllocatedMemorySupported()
{
return threadAllocatedMemorySupported;
}
}

View File

@@ -57,10 +57,12 @@ import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context; import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Script; import org.mozilla.javascript.Script;
import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.WrapFactory; import org.mozilla.javascript.WrapFactory;
import org.mozilla.javascript.WrappedException; import org.mozilla.javascript.WrappedException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@@ -108,6 +110,23 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
/** Cache of runtime compiled script instances */ /** Cache of runtime compiled script instances */
private final Map<String, Script> scriptCache = new ConcurrentHashMap<String, Script>(256); private final Map<String, Script> scriptCache = new ConcurrentHashMap<String, Script>(256);
/** Rhino optimization level */
private int optimizationLevel = -1;
/** Maximum seconds a script is allowed to run */
private int maxScriptExecutionSeconds = -1;
/** Maximum of call stack depth (in terms of number of call frames) */
private int maxStackDepth = -1;
/** Maximum memory (bytes) a script can use */
private long maxMemoryUsedInBytes = -1L;
/** Number of (bytecode) instructions that will trigger the observer */
private int observerInstructionCount = 100;
/** Custom context factory */
public static AlfrescoContextFactory contextFactory;
/** /**
* Set the default store reference * Set the default store reference
@@ -144,6 +163,51 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
this.shareSealedScopes = shareSealedScopes; this.shareSealedScopes = shareSealedScopes;
} }
/**
* @param optimizationLevel
* -1 interpretive mode, 0 no optimizations, 1-9 optimizations performed
*/
public void setOptimizationLevel(int optimizationLevel)
{
this.optimizationLevel = optimizationLevel;
}
/**
* @param maxScriptExecutionSeconds
* the number of seconds a script is allowed to run
*/
public void setMaxScriptExecutionSeconds(int maxScriptExecutionSeconds)
{
this.maxScriptExecutionSeconds = maxScriptExecutionSeconds;
}
/**
* @param maxStackDepth
* the number of call stack depth allowed
*/
public void setMaxStackDepth(int maxStackDepth)
{
this.maxStackDepth = maxStackDepth;
}
/**
* @param maxMemoryUsedInBytes
* the number of memory a script can use
*/
public void setMaxMemoryUsedInBytes(long maxMemoryUsedInBytes)
{
this.maxMemoryUsedInBytes = maxMemoryUsedInBytes;
}
/**
* @param observerInstructionCount
* the number of instructions that will trigger {@link ContextFactory#observeInstructionCount}
*/
public void setObserverInstructionCount(int observerInstructionCount)
{
this.observerInstructionCount = observerInstructionCount;
}
/** /**
* @see org.alfresco.service.cmr.repository.ScriptProcessor#reset() * @see org.alfresco.service.cmr.repository.ScriptProcessor#reset()
*/ */
@@ -441,6 +505,8 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure, String debugScriptName) private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure, String debugScriptName)
throws AlfrescoRuntimeException throws AlfrescoRuntimeException
{ {
Scriptable scope = null;
long startTime = 0; long startTime = 0;
if (callLogger.isDebugEnabled()) if (callLogger.isDebugEnabled())
{ {
@@ -457,14 +523,16 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
// Create a thread-specific scope from one of the shared scopes. // Create a thread-specific scope from one of the shared scopes.
// See http://www.mozilla.org/rhino/scopes.html // See http://www.mozilla.org/rhino/scopes.html
cx.setWrapFactory(secure ? wrapFactory : sandboxFactory); cx.setWrapFactory(secure ? wrapFactory : sandboxFactory);
Scriptable scope;
// Enables or disables execution limits based on secure flag
enableLimits(cx, secure);
if (this.shareSealedScopes) if (this.shareSealedScopes)
{ {
Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope; Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope;
scope = cx.newObject(sharedScope); scope = cx.newObject(sharedScope);
scope.setPrototype(sharedScope); scope.setPrototype(sharedScope);
scope.setParentScope(null); scope.setParentScope(null);
} }
else else
{ {
@@ -538,6 +606,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
} }
finally finally
{ {
unsetScope(model, scope);
Context.exit(); Context.exit();
if (callLogger.isDebugEnabled()) if (callLogger.isDebugEnabled())
@@ -630,6 +699,9 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
*/ */
public void afterPropertiesSet() throws Exception public void afterPropertiesSet() throws Exception
{ {
// Initialize context factory
initContextFactory();
// Initialize the secure scope // Initialize the secure scope
Context cx = Context.enter(); Context cx = Context.enter();
try try
@@ -687,4 +759,129 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
} }
return scope; return scope;
} }
/**
* Clean supplied scope and unset it from any model instance where it has been injected before
*
* @param model
* Data model containing objects from where scope will be unset
* @param scope
* The scope to clean
*/
private void unsetScope(Map<String, Object> model, Scriptable scope)
{
if (scope != null)
{
Object[] ids = scope.getIds();
if (ids != null)
{
for (Object id : ids)
{
try
{
deleteProperty(scope, id.toString());
}
catch (Exception e)
{
logger.info("Unable to delete id: " + id, e);
}
}
}
}
if (model != null)
{
for (String key : model.keySet())
{
try
{
deleteProperty(scope, key);
Object obj = model.get(key);
if (obj instanceof Scopeable)
{
((Scopeable) obj).setScope(null);
}
}
catch (Exception e)
{
logger.info("Unable to unset model object " + key + " : ", e);
}
}
}
}
/**
* Deletes a property from the supplied scope, if property is not removable, then is set to null
*
* @param scope
* the scope object from where property will be removed
* @param name
* the property name to delete
*/
private void deleteProperty(Scriptable scope, String name)
{
if (scope != null && name != null)
{
if (!ScriptableObject.deleteProperty(scope, name))
{
ScriptableObject.putProperty(scope, name, null);
}
scope.delete(name);
}
}
/**
* Initializes the context factory with limits configuration
*/
private synchronized void initContextFactory()
{
if (contextFactory == null)
{
contextFactory = new AlfrescoContextFactory();
contextFactory.setOptimizationLevel(optimizationLevel);
if (maxScriptExecutionSeconds > 0)
{
contextFactory.setMaxScriptExecutionSeconds(maxScriptExecutionSeconds);
}
if (maxMemoryUsedInBytes > 0L)
{
contextFactory.setMaxMemoryUsedInBytes(maxMemoryUsedInBytes);
}
if (maxStackDepth > 0)
{
contextFactory.setMaxStackDepth(maxStackDepth);
}
if (maxScriptExecutionSeconds > 0 || maxMemoryUsedInBytes > 0L)
{
contextFactory.setObserveInstructionCount(observerInstructionCount);
}
ContextFactory.initGlobal(contextFactory);
}
}
/**
* If script is considered secure no limits will be applied, otherwise, the limits are enabled and the script can be
* interrupted in case a limit has been reached.
*
* @param cx
* the Rhino scope
* @param secure
* true if script execution is considered secure (e.g, deployed at classpath level)
*/
private void enableLimits(Context cx, boolean secure)
{
if (cx != null)
{
if (cx instanceof AlfrescoScriptContext)
{
((AlfrescoScriptContext) cx).setLimitsEnabled(!secure);
}
}
}
} }

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository repository.name=Main Repository
# Schema number # Schema number
version.schema=16000 version.schema=16100
# Directory configuration # Directory configuration
@@ -1336,3 +1336,18 @@ allow.unsecure.callback.jsonp=false
# pre-configured allow list of media/mime types to allow inline instead of attachment (via Content-Disposition response header) # 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 content.nonAttach.mimetypes=application/pdf,image/jpeg,image/gif,image/png,image/tiff,image/bmp
# Rhino optimization level
scripts.execution.optimizationLevel=0
# Max seconds a script is allowed to run
scripts.execution.maxScriptExecutionSeconds=-1
# Max call stack depth
scripts.execution.maxStackDepth=-1
# Max memory (bytes) a script can use
scripts.execution.maxMemoryUsedInBytes=-1
# Number of instructions that will trigger the observer
scripts.execution.observerInstructionCount=-1

View File

@@ -45,6 +45,21 @@
<property name="storePath"> <property name="storePath">
<value>${spaces.company_home.childname}</value> <value>${spaces.company_home.childname}</value>
</property> </property>
<property name="optimizationLevel">
<value>${scripts.execution.optimizationLevel}</value>
</property>
<property name="maxScriptExecutionSeconds">
<value>${scripts.execution.maxScriptExecutionSeconds}</value>
</property>
<property name="maxStackDepth">
<value>${scripts.execution.maxStackDepth}</value>
</property>
<property name="maxMemoryUsedInBytes">
<value>${scripts.execution.maxMemoryUsedInBytes}</value>
</property>
<property name="observerInstructionCount">
<value>${scripts.execution.observerInstructionCount}</value>
</property>
</bean> </bean>
<!-- base config implementation that script extension beans extend from - for auto registration <!-- base config implementation that script extension beans extend from - for auto registration

View File

@@ -58,8 +58,11 @@ import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.mozilla.javascript.Context; import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.UniqueTag;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -435,6 +438,102 @@ public class RhinoScriptTest extends TestCase
} }
// MNT-23158
public void testScopeData()
{
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
Context cx = Context.enter();
try
{
Scriptable sharedScope = new ImporterTopLevel(cx, true);
Scriptable scope = cx.newObject(sharedScope);
scope.setPrototype(sharedScope);
scope.setParentScope(null);
// Executes a first script
Object result = cx.evaluateString(scope, "var a = 10; var b = 20; var sum = a+b;", "TestJS1", 1, null);
assertTrue(Undefined.isUndefined(result));
// Test sum value
Object sum = scope.get("sum", scope);
assertEquals(30.0, Context.toNumber(sum));
// No 'sum' property should be found in the shared scope
sum = sharedScope.get("sum", sharedScope);
assertEquals(sum, UniqueTag.NOT_FOUND);
// No 'b' property should be found in the shared scope
Object b = ScriptableObject.getProperty(sharedScope, "b");
assertEquals(b, UniqueTag.NOT_FOUND);
// Cleans scope
unsetScope(scope);
// Executes a second script using the same scope
result = cx.evaluateString(scope, "var test = 'test';", "TestJS2", 1, null);
// 'sum' property should be null
sum = scope.get("sum", scope);
assertNull(sum);
// New scope initialization
scope = cx.newObject(sharedScope);
scope.setPrototype(sharedScope);
scope.setParentScope(null);
// check 'test' property
Object test = scope.get("test", scope);
assertEquals(test, UniqueTag.NOT_FOUND);
}
finally
{
Context.exit();
}
return null;
}
});
}
private void unsetScope(Scriptable scope)
{
if (scope != null)
{
Object[] ids = scope.getIds();
if (ids != null)
{
for (Object id : ids)
{
try
{
deleteProperty(scope, id.toString());
}
catch (Exception e)
{
// Do nothing
}
}
}
}
}
private void deleteProperty(Scriptable scope, String name)
{
if (scope != null && name != null)
{
if (!ScriptableObject.deleteProperty(scope, name))
{
ScriptableObject.putProperty(scope, name, null);
}
scope.delete(name);
}
}
private static final String TESTSCRIPT_CLASSPATH1 = "org/alfresco/repo/jscript/test_script1.js"; private static final String TESTSCRIPT_CLASSPATH1 = "org/alfresco/repo/jscript/test_script1.js";
private static final String TESTSCRIPT_CLASSPATH2 = "org/alfresco/repo/jscript/test_script2.js"; private static final String TESTSCRIPT_CLASSPATH2 = "org/alfresco/repo/jscript/test_script2.js";
private static final String TESTSCRIPT_CLASSPATH3 = "org/alfresco/repo/jscript/test_script3.js"; private static final String TESTSCRIPT_CLASSPATH3 = "org/alfresco/repo/jscript/test_script3.js";