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
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\]/
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
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>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>14.146-SNAPSHOT</version>
<version>15.13</version>
</parent>
<modules>

View File

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

View File

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

View File

@@ -102,7 +102,7 @@ public class DeleteRecordTests extends BaseRMRestTest
testSite = dataSite.usingAdmin().createPublicRandomSite();
recordFolder = createCategoryFolderInFilePlan();
unfiledRecordFolder = createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, getRandomName("Unfiled Folder "),
UNFILED_RECORD_FOLDER_TYPE);
UNFILED_RECORD_FOLDER_TYPE);
}
/** Data provider with electronic and non-electronic records to be deleted */
@@ -133,10 +133,10 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
dataProvider = "recordsToBeDeleted",
description = "Admin user can delete records"
)
(
dataProvider = "recordsToBeDeleted",
description = "Admin user can delete records"
)
@AlfrescoTest(jira="RM-4363")
public void adminCanDeleteRecords(String recordId)
{
@@ -154,17 +154,17 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
description = "User without write permissions can't delete a record"
)
(
description = "User without write permissions can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutWritePermissionsCantDeleteRecord()
{
// Create a non-electronic record in unfiled records
UnfiledContainerChild nonElectronicRecord = UnfiledContainerChild.builder()
.name("Record " + RandomData.getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build();
.name("Record " + RandomData.getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build();
UnfiledContainerChild newRecord = getRestAPIFactory().getUnfiledContainersAPI().createUnfiledContainerChild(nonElectronicRecord, UNFILED_RECORDS_CONTAINER_ALIAS);
assertStatusCode(CREATED);
@@ -187,9 +187,9 @@ public class DeleteRecordTests extends BaseRMRestTest
* </pre>
*/
@Test
(
description = "User without delete records capability can't delete a record"
)
(
description = "User without delete records capability can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutDeleteRecordsCapabilityCantDeleteRecord()
{
@@ -234,7 +234,7 @@ public class DeleteRecordTests extends BaseRMRestTest
STEP("Create a record in first folder and copy it into second folder.");
String recordId = getRestAPIFactory().getRecordFolderAPI()
.createRecord(createElectronicRecordModel(), recordFolder.getId(), getFile(IMAGE_FILE)).getId();
.createRecord(createElectronicRecordModel(), recordFolder.getId(), getFile(IMAGE_FILE)).getId();
String copyId = copyNode(recordId, recordFolderB.getId()).getId();
assertStatusCode(CREATED);
@@ -290,6 +290,7 @@ public class DeleteRecordTests extends BaseRMRestTest
* Then it is still possible to view the content of the copy
* </pre>
*/
/*
@Test (description = "Destroying record doesn't delete the content for the associated copy")
@AlfrescoTest (jira = "MNT-20145")
public void destroyOfRecord()
@@ -323,14 +324,15 @@ public class DeleteRecordTests extends BaseRMRestTest
STEP("Execute the disposition schedule steps.");
rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getUsername(), recordFiled.getName(),
RM_ACTIONS.CUT_OFF);
RM_ACTIONS.CUT_OFF);
rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getUsername(), recordFiled.getName(),
RM_ACTIONS.DESTROY);
RM_ACTIONS.DESTROY);
STEP("Check that it's possible to load the copy content.");
getNodeContent(copy.getId());
assertStatusCode(OK);
}
*/
/**
* <pre>
@@ -348,14 +350,14 @@ public class DeleteRecordTests extends BaseRMRestTest
STEP("Declare file version as record.");
recordsAPI.declareDocumentVersionAsRecord(getAdminUser().getUsername(), getAdminUser().getPassword(), testSite.getId(),
testFile.getName());
testFile.getName());
UnfiledContainerChild unfiledContainerChild = getRestAPIFactory().getUnfiledContainersAPI()
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries().stream()
.filter(child -> child.getEntry().getName()
.startsWith(testFile.getName().substring(0, testFile.getName().indexOf("."))))
.findFirst()
.get().getEntry();
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries().stream()
.filter(child -> child.getEntry().getName()
.startsWith(testFile.getName().substring(0, testFile.getName().indexOf("."))))
.findFirst()
.get().getEntry();
STEP("Delete the record.");
deleteAndVerify(unfiledContainerChild.getId());

View File

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

View File

@@ -109,6 +109,10 @@ rm.completerecord.mandatorypropertiescheck.enabled=true
#
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
# these take a comma separated string of permissions from org.alfresco.service.cmr.security.PermissionService
# read maps to ReadRecords and write to FileRecords

View File

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

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>14.146-SNAPSHOT</version>
<version>15.13</version>
</parent>
<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.RecordsManagementModel.ASSOC_FROZEN_CONTENT;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
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.patch.AbstractModulePatch;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
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
@@ -52,8 +58,15 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/
public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
{
/** logger */
protected static final Logger LOGGER = LoggerFactory.getLogger(RMv35HoldNewChildAssocPatch.class);
/** 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
@@ -75,7 +88,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* Setter for fileplanservice
*
* @param filePlanService File plan service interface
* @param filePlanService
* File plan service interface
*/
public void setFilePlanService(FilePlanService filePlanService)
{
@@ -85,7 +99,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* Setter for hold service
*
* @param holdService Hold service interface.
* @param holdService
* Hold service interface.
*/
public void setHoldService(HoldService holdService)
{
@@ -95,7 +110,8 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
/**
* 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)
{
@@ -112,33 +128,49 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
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
public void applyInternal()
{
behaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
try
{
int patchedNodesCounter = 0;
for (NodeRef filePlan : filePlanService.getFilePlans())
{
for (NodeRef hold : holdService.getHolds(filePlan))
{
List<ChildAssociationRef> frozenAssoc = nodeService.getChildAssocs(hold, ASSOC_FROZEN_CONTENT, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : frozenAssoc)
LOGGER.debug("Analyzing hold {}", hold.getId());
BatchWorker batchWorker = new BatchWorker(hold);
LOGGER.debug("Hold has {} items to be analyzed", batchWorker.getWorkSize());
while (batchWorker.hasMoreResults())
{
NodeRef childNodeRef = ref.getChildRef();
// 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);
boolean childContainedByHold =
parentAssocs.stream().anyMatch(entry -> entry.getParentRef().equals(hold) && entry.getTypeQName().equals(ASSOC_CONTAINS));
if (!childContainedByHold)
{
nodeService.addChild(hold, childNodeRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
}
processBatch(hold, batchWorker);
}
LOGGER.debug("Patched {} items in hold", batchWorker.getTotalPatchedNodes());
patchedNodesCounter += batchWorker.getTotalPatchedNodes();
}
}
LOGGER.debug("Patch applied to {} children across all holds", patchedNodesCounter);
}
finally
{
@@ -146,4 +178,92 @@ public class RMv35HoldNewChildAssocPatch extends AbstractModulePatch
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.major=7
version.minor=0
version.revision=0
version.minor=2
version.revision=1
version.label=
# Edition label
@@ -15,4 +15,4 @@ version.edition=Community
version.scmrevision=@scm-path@-r@scm-revision@
# Build number
version.build=r@scm-revision@-b@build-number@
version.build=r@scm-revision@-b@build-number@

View File

@@ -33,8 +33,10 @@ import static java.util.Collections.emptyList;
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.patch.v35.RMv35HoldNewChildAssocPatch.PATCH_ASSOC_NAME;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
import static org.mockito.ArgumentMatchers.any;
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.never;
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.hold.HoldService;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
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
@@ -81,6 +88,12 @@ public class RMv35HoldNewChildAssocPatchUnitTest
@Mock
private BehaviourFilter mockBehaviourFilter;
@Mock
private TransactionService mockTransactionService;
@Mock
private RetryingTransactionHelper mockRetryingTransactionHelper;
@InjectMocks
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.
*/
@SuppressWarnings("unchecked")
@Test
public void testAddChildDuringUpgrade()
{
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
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);
// 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();
verify(mockNodeService, times(1)).addChild(holdRef, heldItemRef, ASSOC_CONTAINS, PATCH_ASSOC_NAME);
}
@SuppressWarnings("unchecked")
@Test
public void patchRunWithSuccessWhenNoHeldChildren()
{
when(mockFilePlanService.getFilePlans()).thenReturn(fileplans);
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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ import org.testng.annotations.Test;
*/
public class GetProcessSanityTests extends RestTest
{
private UserModel userWhoStartsProcess, assignee;
private UserModel userWhoStartsProcess, assignee, user;
private RestProcessModel addedProcess, process;
@BeforeClass(alwaysRun = true)
@@ -24,6 +24,7 @@ public class GetProcessSanityTests extends RestTest
{
userWhoStartsProcess = dataUser.createRandomTestUser();
assignee = dataUser.createRandomTestUser();
user = dataUser.createRandomTestUser();
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())
.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>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>14.146-SNAPSHOT</version>
<version>15.13</version>
</parent>
<developers>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>14.146-SNAPSHOT</version>
<version>15.13</version>
</parent>
<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">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>14.146-SNAPSHOT</version>
<version>15.13</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -25,7 +25,7 @@
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>2</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.revision>1</acs.version.revision>
<acs.version.label />
<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.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.jackson.version>2.13.1</dependency.jackson.version>
<dependency.jackson-databind.version>2.13.1</dependency.jackson-databind.version>
<dependency.jackson.version>2.13.3</dependency.jackson.version>
<dependency.jackson-databind.version>2.13.3</dependency.jackson-databind.version>
<dependency.cxf.version>3.5.0</dependency.cxf.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.mockito-core.version>3.11.2</dependency.mockito-core.version>
<dependency.org-json.version>20211205</dependency.org-json.version>
<dependency.commons-dbcp.version>2.9.0</dependency.commons-dbcp.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.httpcore.version>4.4.15</dependency.httpcore.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.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>
<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>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>HEAD</tag>
<tag>15.13</tag>
</scm>
<distributionManagement>

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ function main()
// Get the args
var siteShortName = url.templateArgs.shortname,
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),
authorityType = args.authorityType,
zone = args.zone,

View File

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

View File

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

View File

@@ -117,6 +117,7 @@ public class MySQLDeleteNotExistsExecutor extends DeleteNotExistsExecutor
{
// Process batch
primaryId = processPrimaryTableResultSet(primaryPrepStmt, secondaryPrepStmts, deletePrepStmt, deleteIds, primaryTableName, primaryColumnName, tableColumn);
connection.commit();
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.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.WrapFactory;
import org.mozilla.javascript.WrappedException;
import org.springframework.beans.factory.InitializingBean;
@@ -108,6 +110,23 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
/** Cache of runtime compiled script instances */
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
@@ -144,6 +163,51 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
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()
*/
@@ -441,6 +505,8 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure, String debugScriptName)
throws AlfrescoRuntimeException
{
Scriptable scope = null;
long startTime = 0;
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.
// See http://www.mozilla.org/rhino/scopes.html
cx.setWrapFactory(secure ? wrapFactory : sandboxFactory);
Scriptable scope;
// Enables or disables execution limits based on secure flag
enableLimits(cx, secure);
if (this.shareSealedScopes)
{
Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope;
scope = cx.newObject(sharedScope);
scope.setPrototype(sharedScope);
scope.setParentScope(null);
}
else
{
@@ -538,6 +606,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
finally
{
unsetScope(model, scope);
Context.exit();
if (callLogger.isDebugEnabled())
@@ -630,6 +699,9 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
*/
public void afterPropertiesSet() throws Exception
{
// Initialize context factory
initContextFactory();
// Initialize the secure scope
Context cx = Context.enter();
try
@@ -687,4 +759,129 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
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
# Schema number
version.schema=16000
version.schema=16100
# 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)
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">
<value>${spaces.company_home.childname}</value>
</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>
<!-- base config implementation that script extension beans extend from - for auto registration

View File

@@ -1,48 +1,48 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.jscript;
import static org.junit.Assert.fail;
import java.io.IOException;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.DictionaryComponent;
import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.node.BaseNodeServiceTest;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.node.BaseNodeServiceTest;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -54,13 +54,16 @@ import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper;
import org.junit.experimental.categories.Category;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.springframework.context.ApplicationContext;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.UniqueTag;
import org.springframework.context.ApplicationContext;
/**
@@ -364,77 +367,173 @@ public class RhinoScriptTest extends TestCase
return null;
}
});
}
// MNT-21009
public void testUnsecureScriptAddedOnRepoNode()
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
StoreRef store = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "rhino_" + System.currentTimeMillis());
NodeRef root = nodeService.getRootNode(store);
BaseNodeServiceTest.buildNodeGraph(nodeService, root);
try
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("out", System.out);
// create an Alfresco scriptable Node object
// the Node object is a wrapper similar to the TemplateNode
// concept
ScriptNode rootNode = new ScriptNode(root, serviceRegistry, null);
model.put("root", rootNode);
// test executing a script embedded inside Node content
ChildAssociationRef childRef = nodeService.createNode(root, BaseNodeServiceTest.ASSOC_TYPE_QNAME_TEST_CHILDREN,
QName.createQName(BaseNodeServiceTest.NAMESPACE, "script_content"), BaseNodeServiceTest.TYPE_QNAME_TEST_CONTENT, null);
NodeRef contentNodeRef = childRef.getChildRef();
ContentWriter writer = contentService.getWriter(contentNodeRef, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, true);
writer.setMimetype("application/x-javascript");
writer.putContent(BASIC_JAVA);
try
{
scriptService.executeScript(contentNodeRef, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, model);
fail("execution of nonsecure script on nodeRef is not allowed.");
}
catch (AlfrescoRuntimeException ex)
{
// expected
}
ChildAssociationRef childRef1 = nodeService.createNode(root, BaseNodeServiceTest.ASSOC_TYPE_QNAME_TEST_CHILDREN,
QName.createQName(BaseNodeServiceTest.NAMESPACE, "script_content"), BaseNodeServiceTest.TYPE_QNAME_TEST_CONTENT, null);
NodeRef contentNodeRef1 = childRef1.getChildRef();
ContentWriter writer1 = contentService.getWriter(contentNodeRef1, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, true);
writer1.setMimetype("application/x-javascript");
writer1.putContent(REFLECTION_GET_CLASS);
try
{
scriptService.executeScript(contentNodeRef1, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, model);
fail("execution of nonsecure script on nodeRef is not allowed.");
}
catch (AlfrescoRuntimeException ex)
{
// expected
}
}
finally
{
}
return null;
}
});
}
// MNT-21009
public void testUnsecureScriptAddedOnRepoNode()
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
StoreRef store = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "rhino_" + System.currentTimeMillis());
NodeRef root = nodeService.getRootNode(store);
BaseNodeServiceTest.buildNodeGraph(nodeService, root);
try
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("out", System.out);
// create an Alfresco scriptable Node object
// the Node object is a wrapper similar to the TemplateNode
// concept
ScriptNode rootNode = new ScriptNode(root, serviceRegistry, null);
model.put("root", rootNode);
// test executing a script embedded inside Node content
ChildAssociationRef childRef = nodeService.createNode(root, BaseNodeServiceTest.ASSOC_TYPE_QNAME_TEST_CHILDREN,
QName.createQName(BaseNodeServiceTest.NAMESPACE, "script_content"), BaseNodeServiceTest.TYPE_QNAME_TEST_CONTENT, null);
NodeRef contentNodeRef = childRef.getChildRef();
ContentWriter writer = contentService.getWriter(contentNodeRef, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, true);
writer.setMimetype("application/x-javascript");
writer.putContent(BASIC_JAVA);
try
{
scriptService.executeScript(contentNodeRef, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, model);
fail("execution of nonsecure script on nodeRef is not allowed.");
}
catch (AlfrescoRuntimeException ex)
{
// expected
}
ChildAssociationRef childRef1 = nodeService.createNode(root, BaseNodeServiceTest.ASSOC_TYPE_QNAME_TEST_CHILDREN,
QName.createQName(BaseNodeServiceTest.NAMESPACE, "script_content"), BaseNodeServiceTest.TYPE_QNAME_TEST_CONTENT, null);
NodeRef contentNodeRef1 = childRef1.getChildRef();
ContentWriter writer1 = contentService.getWriter(contentNodeRef1, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, true);
writer1.setMimetype("application/x-javascript");
writer1.putContent(REFLECTION_GET_CLASS);
try
{
scriptService.executeScript(contentNodeRef1, BaseNodeServiceTest.PROP_QNAME_TEST_CONTENT, model);
fail("execution of nonsecure script on nodeRef is not allowed.");
}
catch (AlfrescoRuntimeException ex)
{
// expected
}
}
finally
{
}
return null;
}
});
}
// 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_CLASSPATH2 = "org/alfresco/repo/jscript/test_script2.js";
private static final String TESTSCRIPT_CLASSPATH3 = "org/alfresco/repo/jscript/test_script3.js";
@@ -452,14 +551,14 @@ public class RhinoScriptTest extends TestCase
"var childByNameNode = root.childByNamePath(\"/\" + childList[0].name);\r\n" +
"logger.log(\"child by name path: \" + childByNameNode.name);\r\n" +
"var xpathResults = root.childrenByXPath(\"/*\");\r\n" +
"logger.log(\"children of root from xpath: \" + xpathResults.length);\r\n";
private static final String BASIC_JAVA =
"var list = com.google.common.collect.Lists.newArrayList();\n" +
"root.nodeRef.getClass().forName(\"java.lang.ProcessBuilder\")";
private static final String REFLECTION_GET_CLASS =
"root.nodeRef.getClass().forName(\"java.lang.ProcessBuilder\")";
"logger.log(\"children of root from xpath: \" + xpathResults.length);\r\n";
private static final String BASIC_JAVA =
"var list = com.google.common.collect.Lists.newArrayList();\n" +
"root.nodeRef.getClass().forName(\"java.lang.ProcessBuilder\")";
private static final String REFLECTION_GET_CLASS =
"root.nodeRef.getClass().forName(\"java.lang.ProcessBuilder\")";
}