mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-24 14:32:01 +00:00
Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
576b6faac9 | ||
|
d86415401d | ||
|
460cc1f2cd | ||
|
370fef10fd | ||
|
efadc239d4 | ||
|
de90e37578 | ||
|
6e438d2e4f | ||
|
a86fa21880 | ||
|
db74a6e7f2 | ||
|
8c773ac97c | ||
|
5a2b3cf64d | ||
|
8ab910d2b1 | ||
|
fa70f1cd45 | ||
|
75a2e0f901 | ||
|
84997bcf86 | ||
|
536b3ddd6d | ||
|
bb86c97b11 | ||
|
558f117f24 | ||
|
bbae71658d | ||
|
9ee9653463 | ||
|
44570cec8a | ||
|
33eb0354fa | ||
|
0d3e2dc8bb | ||
|
ac62c52a33 | ||
|
0d30d40d8f | ||
|
87e365df7e | ||
|
f6a12760c9 | ||
|
560a050af3 | ||
|
5ed82930d2 | ||
|
f8a32022c3 | ||
|
137df0ff4c | ||
|
23bd8c064c | ||
|
e3384eaee4 | ||
|
c7e5716a4a | ||
|
7fa0d30100 | ||
|
71849cd4ac | ||
|
686ffcb19c |
@@ -1539,7 +1539,7 @@
|
||||
"filename": "repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java",
|
||||
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||
"is_verified": false,
|
||||
"line_number": 127,
|
||||
"line_number": 130,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1888,5 +1888,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2025-05-14T14:31:49Z"
|
||||
"generated_at": "2025-05-15T21:47:13Z"
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
@@ -26,13 +26,6 @@
|
||||
*/
|
||||
package org.alfresco.rest.rm.community.hold;
|
||||
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
|
||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -44,12 +37,25 @@ import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
|
||||
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
|
||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import org.alfresco.dataprep.CMISUtil;
|
||||
import org.alfresco.dataprep.ContentActions;
|
||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
|
||||
@@ -71,10 +77,6 @@ import org.alfresco.utility.constants.UserRole;
|
||||
import org.alfresco.utility.model.FileModel;
|
||||
import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* API tests for adding items to holds via the bulk process
|
||||
@@ -82,7 +84,7 @@ import org.testng.annotations.Test;
|
||||
public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
{
|
||||
private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied. You do not have the appropriate " +
|
||||
"permissions to perform this operation.";
|
||||
"permissions to perform this operation.";
|
||||
private static final int NUMBER_OF_FILES = 5;
|
||||
private final List<FileModel> addedFiles = new ArrayList<>();
|
||||
private final List<UserModel> users = new ArrayList<>();
|
||||
@@ -102,8 +104,9 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
{
|
||||
STEP("Create a hold.");
|
||||
hold = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
holds.add(hold);
|
||||
|
||||
STEP("Create test files.");
|
||||
@@ -117,8 +120,8 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
for (int i = 0; i < NUMBER_OF_FILES; i++)
|
||||
{
|
||||
FileModel documentHeld = dataContent.usingAdmin()
|
||||
.usingResource(i % 2 == 0 ? folder1 : folder2)
|
||||
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||
.usingResource(i % 2 == 0 ? folder1 : folder2)
|
||||
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||
addedFiles.add(documentHeld);
|
||||
}
|
||||
|
||||
@@ -128,29 +131,37 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are searchable.");
|
||||
await().atMost(30, TimeUnit.SECONDS)
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
RestRequestQueryModel ancestorReq = getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion());
|
||||
SearchRequest ancestorSearchRequest = new SearchRequest();
|
||||
ancestorSearchRequest.setQuery(ancestorReq);
|
||||
|
||||
STEP("Wait until paths are indexed.");
|
||||
// to improve stability on CI - seems that sometimes during big load we need to wait longer for the condition
|
||||
await().atMost(120, TimeUnit.SECONDS)
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(ancestorSearchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
holdBulkOperation = HoldBulkOperation.builder()
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
*/
|
||||
@Test
|
||||
public void addContentFromTestSiteToHoldUsingBulkAPI()
|
||||
{
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userAddHoldPermission);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(ACCEPTED);
|
||||
@@ -158,50 +169,49 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(20, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold.getId()).getEntries().size() == NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId).toList();
|
||||
.getChildren(hold.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
STEP("Check the bulk status.");
|
||||
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 0, null, holdBulkOperation);
|
||||
|
||||
STEP("Check the bulk statuses.");
|
||||
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatuses(hold.getId());
|
||||
.getBulkStatuses(hold.getId());
|
||||
assertEquals(Arrays.asList(holdBulkStatus),
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a folder and all subfolders to a hold using the bulk API
|
||||
* Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a folder and all subfolders to a hold using the bulk API Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
*/
|
||||
@Test
|
||||
public void addContentFromFolderAndAllSubfoldersToHoldUsingBulkAPI()
|
||||
{
|
||||
hold3 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
holds.add(hold3);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold3.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator, hold3.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userAddHoldPermission);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
// Get content from folder and all subfolders of the root folder
|
||||
HoldBulkOperation bulkOperation = HoldBulkOperation.builder()
|
||||
.query(getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion()))
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
.query(getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion()))
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.startBulkProcess(bulkOperation, hold3.getId());
|
||||
.startBulkProcess(bulkOperation, hold3.getId());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(ACCEPTED);
|
||||
@@ -209,43 +219,40 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(20, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold3.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold3.getId()).getEntries().size() == NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold3.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId).toList();
|
||||
.getChildren(hold3.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
STEP("Check the bulk status.");
|
||||
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold3.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
.getBulkStatus(hold3.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 0, null, bulkOperation);
|
||||
|
||||
STEP("Check the bulk statuses.");
|
||||
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatuses(hold3.getId());
|
||||
.getBulkStatuses(hold3.getId());
|
||||
assertEquals(List.of(holdBulkStatus),
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the add to hold capability
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives access denied error
|
||||
* Given a user without the add to hold capability When the user adds content from a site to a hold using the bulk API Then the user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutAddToHoldCapability()
|
||||
{
|
||||
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole
|
||||
.SiteCollaborator,
|
||||
hold.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator,
|
||||
hold.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
users.add(userWithoutAddToHoldCapability);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
getRestAPIFactory().getHoldsAPI(userWithoutAddToHoldCapability)
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
|
||||
STEP("Verify the response status code and the error message.");
|
||||
assertStatusCode(FORBIDDEN);
|
||||
@@ -253,21 +260,19 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the filing permission on a hold
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives access denied error
|
||||
* Given a user without the filing permission on a hold When the user adds content from a site to a hold using the bulk API Then the user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutFilingPermissionOnAHold()
|
||||
{
|
||||
// User without filing permission on a hold
|
||||
UserModel userWithoutPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS);
|
||||
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS);
|
||||
users.add(userWithoutPermission);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
|
||||
STEP("Verify the response status code and the error message.");
|
||||
assertStatusCode(FORBIDDEN);
|
||||
@@ -276,68 +281,63 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the write permission on all the content
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then all processed items are marked as errors and the last error message contains access denied error
|
||||
* Given a user without the write permission on all the content When the user adds content from a site to a hold using the bulk API Then all processed items are marked as errors and the last error message contains access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutWritePermissionOnTheContent()
|
||||
{
|
||||
// User without write permission on the content
|
||||
UserModel userWithoutPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(
|
||||
testSite, UserRole.SiteConsumer,
|
||||
hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
testSite, UserRole.SiteConsumer,
|
||||
hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userWithoutPermission);
|
||||
|
||||
// Wait until permissions are reverted
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.setQuery(holdBulkOperation.getQuery());
|
||||
await().atMost(30, TimeUnit.SECONDS)
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(userWithoutPermission).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(userWithoutPermission).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(
|
||||
userWithoutPermission).startBulkProcess(holdBulkOperation, hold.getId());
|
||||
userWithoutPermission).startBulkProcess(holdBulkOperation, hold.getId());
|
||||
|
||||
STEP("Verify the response.");
|
||||
assertStatusCode(ACCEPTED);
|
||||
|
||||
await().atMost(20, TimeUnit.SECONDS).until(() ->
|
||||
Objects.equals(getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
await().atMost(20, TimeUnit.SECONDS).until(() -> Objects.equals(getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId()).getStatus(), "DONE"));
|
||||
|
||||
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, NUMBER_OF_FILES, ACCESS_DENIED_ERROR_MESSAGE,
|
||||
holdBulkOperation);
|
||||
holdBulkOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the write permission on one file
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then all processed items are added to the hold except the one that the user does not have write permission
|
||||
* And the status of the bulk operation is DONE, contains the error message and the number of errors is 1
|
||||
* Given a user without the write permission on one file When the user adds content from a site to a hold using the bulk API Then all processed items are added to the hold except the one that the user does not have write permission And the status of the bulk operation is DONE, contains the error message and the number of errors is 1
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutWritePermissionOnOneFile()
|
||||
{
|
||||
hold2 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
holds.add(hold2);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold2.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator, hold2.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userAddHoldPermission);
|
||||
|
||||
contentActions.setPermissionForUser(getAdminUser().getUsername(), getAdminUser().getPassword(),
|
||||
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
|
||||
UserRole.SiteConsumer.getRoleId(), false);
|
||||
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
|
||||
UserRole.SiteConsumer.getRoleId(), false);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.startBulkProcess(holdBulkOperation, hold2.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold2.getId());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(ACCEPTED);
|
||||
@@ -345,56 +345,50 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(30, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold2.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES - 1);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold2.getId()).getEntries().size() == NUMBER_OF_FILES - 1);
|
||||
await().atMost(30, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId()).getProcessedItems()
|
||||
== NUMBER_OF_FILES);
|
||||
() -> getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId()).getProcessedItems() == NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold2.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId).toList();
|
||||
.getChildren(hold2.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
assertEquals(addedFiles.stream().skip(1).map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
STEP("Check the bulk status.");
|
||||
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId());
|
||||
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 1, ACCESS_DENIED_ERROR_MESSAGE, holdBulkOperation);
|
||||
|
||||
STEP("Check the bulk statuses.");
|
||||
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatuses(hold2.getId());
|
||||
.getBulkStatuses(hold2.getId());
|
||||
assertEquals(List.of(holdBulkStatus),
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
|
||||
|
||||
// Revert the permissions
|
||||
contentActions.setPermissionForUser(getAdminUser().getUsername(), getAdminUser().getPassword(),
|
||||
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
|
||||
UserRole.SiteCollaborator.getRoleId(), true);
|
||||
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
|
||||
UserRole.SiteCollaborator.getRoleId(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an unauthenticated user
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives unauthorized error
|
||||
* Given an unauthenticated user When the user adds content from a site to a hold using the bulk API Then the user receives unauthorized error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessAsUnauthenticatedUser()
|
||||
{
|
||||
STEP("Start bulk process as unauthenticated user");
|
||||
getRestAPIFactory().getHoldsAPI(new UserModel(getAdminUser().getUsername(), "wrongPassword"))
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold.getId());
|
||||
|
||||
STEP("Verify the response status code.");
|
||||
assertStatusCode(UNAUTHORIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessForNonExistentHold()
|
||||
@@ -407,10 +401,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* and the bulk operation is invalid
|
||||
* Then the user receives bad request error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API and the bulk operation is invalid Then the user receives bad request error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusesForInvalidOperation()
|
||||
@@ -418,7 +409,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
STEP("Start bulk process for non existent hold");
|
||||
|
||||
HoldBulkOperation invalidHoldBulkOperation = HoldBulkOperation.builder().op(null)
|
||||
.query(holdBulkOperation.getQuery()).build();
|
||||
.query(holdBulkOperation.getQuery()).build();
|
||||
getRestAPIFactory().getHoldsAPI(getAdminUser()).startBulkProcess(invalidHoldBulkOperation, hold.getId());
|
||||
|
||||
STEP("Verify the response status code.");
|
||||
@@ -426,10 +417,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusForNonExistentHold()
|
||||
@@ -442,10 +430,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the bulk status does not exist
|
||||
* Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the bulk status does not exist Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusForNonExistentBulkStatus()
|
||||
@@ -458,10 +443,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusesForNonExistentHold()
|
||||
@@ -474,9 +456,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from all sites to a hold using the bulk API to exceed the limit (30 items)
|
||||
* Then the user receives bad request error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from all sites to a hold using the bulk API to exceed the limit (30 items) Then the user receives bad request error
|
||||
*/
|
||||
@Test
|
||||
public void testExceedingBulkOperationLimit()
|
||||
@@ -486,8 +466,8 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
queryReq.setLanguage("afts");
|
||||
|
||||
HoldBulkOperation exceedLimitOp = HoldBulkOperation.builder()
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
|
||||
STEP("Start bulk process to exceed the limit");
|
||||
getRestAPIFactory().getHoldsAPI(getAdminUser()).startBulkProcess(exceedLimitOp, hold.getId());
|
||||
@@ -497,26 +477,24 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And then the user cancels the bulk operation
|
||||
* Then the user receives OK status code
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And then the user cancels the bulk operation Then the user receives OK status code
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessCancellationWithAllowedUser()
|
||||
{
|
||||
Hold hold4 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
holds.add(hold4);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold4.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator, hold4.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userAddHoldPermission);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.startBulkProcess(holdBulkOperation, hold4.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold4.getId());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(ACCEPTED);
|
||||
@@ -524,47 +502,44 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Cancel the bulk operation.");
|
||||
getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.cancelBulkOperation(hold4.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
|
||||
.cancelBulkOperation(hold4.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And a 2nd user without the add to hold capability cancels the bulk operation
|
||||
* Then the 2nd user receives access denied error
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And a 2nd user without the add to hold capability cancels the bulk operation Then the 2nd user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessCancellationWithUserWithoutAddToHoldCapability()
|
||||
{
|
||||
Hold hold5 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
holds.add(hold5);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator, hold5.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator, hold5.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
|
||||
users.add(userAddHoldPermission);
|
||||
|
||||
STEP("Add content from the site to the hold using the bulk API.");
|
||||
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.startBulkProcess(holdBulkOperation, hold5.getId());
|
||||
.startBulkProcess(holdBulkOperation, hold5.getId());
|
||||
|
||||
// Verify the status code
|
||||
assertStatusCode(ACCEPTED);
|
||||
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
|
||||
|
||||
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole
|
||||
.SiteCollaborator,
|
||||
hold5.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
UserRole.SiteCollaborator,
|
||||
hold5.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
users.add(userWithoutAddToHoldCapability);
|
||||
|
||||
STEP("Cancel the bulk operation.");
|
||||
getRestAPIFactory().getHoldsAPI(userWithoutAddToHoldCapability)
|
||||
.cancelBulkOperation(hold5.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
|
||||
.cancelBulkOperation(hold5.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
|
||||
|
||||
STEP("Verify the response status code and the error message.");
|
||||
assertStatusCode(FORBIDDEN);
|
||||
@@ -572,7 +547,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
private void assertBulkProcessStatus(HoldBulkStatus holdBulkStatus, long expectedProcessedItems,
|
||||
int expectedErrorsCount, String expectedErrorMessage, HoldBulkOperation holdBulkOperation)
|
||||
int expectedErrorsCount, String expectedErrorMessage, HoldBulkOperation holdBulkOperation)
|
||||
{
|
||||
assertEquals("DONE", holdBulkStatus.getStatus());
|
||||
assertEquals(expectedProcessedItems, holdBulkStatus.getTotalItems());
|
||||
|
@@ -23,7 +23,7 @@ Recorded content can be explicitly destroyed whilst maintaining the original nod
|
||||
* License: Alfresco Community
|
||||
* Issue Tracker Link: [JIRA RM](https://issues.alfresco.com/jira/projects/RM/summary)
|
||||
* Contribution Model: Alfresco Closed Source
|
||||
* Documentation: [docs.alfresco.com (Records Management)](http://docs.alfresco.com/rm2.4/concepts/welcome-rm.html)
|
||||
* Documentation: [docs.alfresco.com (Records Management)](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services-Community-Edition/23.4/Alfresco-Governance-Services-Community-Edition/Introduction)
|
||||
|
||||
***
|
||||
|
||||
|
@@ -21,18 +21,18 @@ RM is split into two main parts - a repository integration and a Share integrati
|
||||
* [Community License](../LICENSE.txt)
|
||||
* [Enterprise License](../../rm-enterprise/LICENSE.txt) (this file will only be present in clones of the Enterprise repository)
|
||||
* [Issue Tracker Link](https://issues.alfresco.com/jira/projects/RM)
|
||||
* [Community Documentation Link](http://docs.alfresco.com/rm-community/concepts/welcome-rm.html)
|
||||
* [Enterprise Documentation Link](http://docs.alfresco.com/rm/concepts/welcome-rm.html)
|
||||
* [Community Documentation Link](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services-Community-Edition/23.4/Alfresco-Governance-Services-Community-Edition/Introduction)
|
||||
* [Enterprise Documentation Link](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services/23.4/Alfresco-Governance-Services/Introduction)
|
||||
* [Contribution Model](../../CONTRIBUTING.md)
|
||||
|
||||
***
|
||||
|
||||
### Prerequisite Knowledge
|
||||
An understanding of Alfresco Content Services is assumed. The following pages from the [developer documentation](http://docs.alfresco.com/5.2/concepts/dev-for-developers.html) give useful background information:
|
||||
An understanding of Alfresco Content Services is assumed. The following pages from the [developer documentation](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Develop) give useful background information:
|
||||
|
||||
* [ACS Architecture](http://docs.alfresco.com/5.2/concepts/dev-arch-overview.html)
|
||||
* [Platform Extensions](http://docs.alfresco.com/5.2/concepts/dev-platform-extensions.html)
|
||||
* [Share Extensions](http://docs.alfresco.com/5.2/concepts/dev-extensions-share.html)
|
||||
* [ACS Architecture](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Software-Architecture)
|
||||
* [Platform Extensions](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Extension-Points-Overview)
|
||||
* [Share Extensions](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Share-UI-Extension-Points)
|
||||
|
||||
***
|
||||
|
||||
@@ -44,12 +44,12 @@ The RM Share module communicates with the repository module via REST APIs. Inter
|
||||
* A DAO layer responsible for CRUD operations against the database.
|
||||
|
||||
#### REST API
|
||||
The REST API endpoints fall into two main types - v0 (Webscripts) and v1. The [v0 API](http://docs.alfresco.com/5.2/references/dev-extension-points-webscripts.html) is older and not recommended for integrations. The [v1 API](http://docs.alfresco.com/5.1/pra/1/topics/pra-welcome-aara.html) is newer but isn't yet feature complete. If you are running RM locally then the GS API Explorer will be available at [this link](http://localhost:8080/gs-api-explorer/).
|
||||
The REST API endpoints fall into two main types - v0 (Webscripts) and v1. The [v0 API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Web-Scripts) is older and not recommended for integrations. The [v1 API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide) is newer but isn't yet feature complete. If you are running RM locally then the GS API Explorer will be available at [this link](http://localhost:8080/gs-api-explorer/).
|
||||
|
||||
Internally the GS v1 REST API is built on the [Alfresco v1 REST API framework](https://community.alfresco.com/community/ecm/blog/2016/10/11/v1-rest-api-part-1-introduction). It aims to be consistent with this in terms of behaviour and naming.
|
||||
|
||||
#### Java Public API
|
||||
The Java service layer is fronted by a [Java Public API](http://docs.alfresco.com/5.2/concepts/java-public-api-list.html), which we will ensure backward compatible with previous releases. Before we remove any methods there will first be a release containing that method deprecated to allow third party integrations to migrate to a new method. The Java Public API also includes a set of POJO objects which are needed to communicate with the services. It is easy to identify classes that are part of the Java Public API as they are annotated `@AlfrescoPublicApi`.
|
||||
The Java service layer is fronted by a [Java Public API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Reference/Java-Foundation-API), which we will ensure backward compatible with previous releases. Before we remove any methods there will first be a release containing that method deprecated to allow third party integrations to migrate to a new method. The Java Public API also includes a set of POJO objects which are needed to communicate with the services. It is easy to identify classes that are part of the Java Public API as they are annotated `@AlfrescoPublicApi`.
|
||||
|
||||
Each Java service will have at least four beans defined for it:
|
||||
|
||||
@@ -61,7 +61,7 @@ Each Java service will have at least four beans defined for it:
|
||||
#### DAOs
|
||||
The DAOs are not part of the Java Public API, but handle CRUD operations against RM stored data. We have some custom queries to improve performance for particularly heavy operations.
|
||||
|
||||
We use standard Alfresco [data modelling](http://docs.alfresco.com/5.2/references/dev-extension-points-content-model.html) to store RM metadata. We extend the [Alfresco patching mechanism](http://docs.alfresco.com/5.2/references/dev-extension-points-patch.html) to provide community and enterprise schema upgrades.
|
||||
We use standard Alfresco [data modelling](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Content-Model-Extension-Point) to store RM metadata. We extend the [Alfresco patching mechanism](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Patches) to provide community and enterprise schema upgrades.
|
||||
|
||||
***
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -80,6 +80,11 @@ function runAction(p_params)
|
||||
{
|
||||
result.fileExist = true;
|
||||
}
|
||||
if (error.indexOf("FolderExistsException") != -1)
|
||||
{
|
||||
result.fileExist = true;
|
||||
result.type = "folder";
|
||||
}
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
|
||||
## Synopsis
|
||||
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **CMIS** is the project that handles the automated tests related only to CMIS API integrated with Alfresco One [Alfresco CMIS API](http://docs.alfresco.com/5.1/pra/1/topics/cmis-welcome.html).
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **CMIS** is the project that handles the automated tests related only to CMIS API integrated with Alfresco One [Alfresco CMIS API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Reference/CMIS-API).
|
||||
|
||||
It is based on Apache Maven, compatible with major IDEs and is using also Spring capabilities for dependency injection.
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<organization>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -27,7 +27,7 @@ Back to [TAS Master Documentation](https://git.alfresco.com/tas/alfresco-tas-uti
|
||||
|
||||
## Synopsis
|
||||
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **RESTAPI** is the project that handles the automated tests related only to [Alfresco REST API](http://docs.alfresco.com/5.1/pra/1/topics/pra-welcome.html).
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **RESTAPI** is the project that handles the automated tests related only to [Alfresco REST API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide).
|
||||
|
||||
It is based on Apache Maven, compatible with major IDEs and is using also Spring capabilities for dependency injection.
|
||||
|
||||
@@ -271,7 +271,7 @@ restClient.onResponse().assertThat().body("entry.modifiedBy.firstName", org.hamc
|
||||
|
||||
### How to generate models or check coverage
|
||||
|
||||
There are some simple generators that could parse [Swagger YAML](http://docs.alfresco.com/community/concepts/alfresco-sdk-tutorials-using-rest-api-explorer.html) files and provide some usefull information to you like:
|
||||
There are some simple generators that could parse [Swagger YAML](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide/Things-to-Know-Before-You-Start/The-API-Explorer-is-Your-Source-of-Truth) files and provide some usefull information to you like:
|
||||
|
||||
a) Show on screen the actual coverage of TAS vs requests that exists in each YAML file - defined in pom.xml)
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -74,7 +74,7 @@ ModuleDetails shareServicesModule = moduleService.getModule("alfresco-share-serv
|
||||
<div class="index-list">
|
||||
<h4><%=descriptorService.getServerDescriptor().getEdition()%></h4>
|
||||
<p></p>
|
||||
<p><a href="http://docs.alfresco.com/">Online Documentation</a></p>
|
||||
<p><a href="https://support.hyland.com/p/alfresco">Online Documentation</a></p>
|
||||
<p></p>
|
||||
<%
|
||||
if (shareServicesModule != null && ModuleInstallState.INSTALLED.equals(shareServicesModule.getInstallState()))
|
||||
|
14
pom.xml
14
pom.xml
@@ -2,7 +2,7 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Alfresco Community Repo Parent</name>
|
||||
|
||||
@@ -58,10 +58,10 @@
|
||||
|
||||
<dependency.aspectj.version>1.9.22.1</dependency.aspectj.version>
|
||||
<dependency.spring.version>6.1.14</dependency.spring.version>
|
||||
<dependency.spring-security.version>6.3.4</dependency.spring-security.version>
|
||||
<dependency.spring-security.version>6.3.8</dependency.spring-security.version>
|
||||
<dependency.antlr.version>3.5.3</dependency.antlr.version>
|
||||
<dependency.jackson.version>2.17.2</dependency.jackson.version>
|
||||
<dependency.cxf.version>4.0.5</dependency.cxf.version>
|
||||
<dependency.cxf.version>4.1.0</dependency.cxf.version>
|
||||
<dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version>
|
||||
<dependency.webscripts.version>9.4</dependency.webscripts.version>
|
||||
<dependency.bouncycastle.version>1.78.1</dependency.bouncycastle.version>
|
||||
@@ -85,8 +85,8 @@
|
||||
<dependency.truezip.version>7.7.10</dependency.truezip.version>
|
||||
<dependency.poi.version>5.4.1</dependency.poi.version>
|
||||
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
|
||||
<dependency.camel.version>4.6.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.netty.version>4.1.113.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
|
||||
<dependency.camel.version>4.10.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.netty.version>4.1.118.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
|
||||
<dependency.activemq.version>5.18.3</dependency.activemq.version>
|
||||
<dependency.apache-compress.version>1.27.1</dependency.apache-compress.version>
|
||||
<dependency.awaitility.version>4.2.2</dependency.awaitility.version>
|
||||
@@ -111,7 +111,7 @@
|
||||
<dependency.jakarta-ee-json-api.version>2.1.3</dependency.jakarta-ee-json-api.version>
|
||||
<dependency.jakarta-ee-json-impl.version>1.1.7</dependency.jakarta-ee-json-impl.version>
|
||||
<dependency.jakarta-json-path.version>2.9.0</dependency.jakarta-json-path.version>
|
||||
<dependency.json-smart.version>2.5.1</dependency.json-smart.version>
|
||||
<dependency.json-smart.version>2.5.2</dependency.json-smart.version>
|
||||
<alfresco.googledrive.version>4.1.0</alfresco.googledrive.version>
|
||||
<alfresco.aos-module.version>3.3.0-A1</alfresco.aos-module.version>
|
||||
<alfresco.api-explorer.version>23.4.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
|
||||
@@ -154,7 +154,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>23.5.0.10</tag>
|
||||
<tag>23.5.0.17</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin Console
|
||||
admin-console.help=Help
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Successfully saved values.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Konzole pro spr\u00e1vce
|
||||
admin-console.help=N\u00e1pov\u011bda
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Hodnoty byly \u00fasp\u011b\u0161n\u011b ulo\u017eeny.
|
||||
|
||||
admin-console.host=Hostitel
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Administrationskonsol
|
||||
admin-console.help=Hj\u00e6lp
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=V\u00e6rdierne blev gemt.
|
||||
|
||||
admin-console.host=V\u00e6rt
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Administratorkonsole
|
||||
admin-console.help=Hilfe
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Erfolgreich gespeicherte Werte.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Consola de administraci\u00f3n
|
||||
admin-console.help=Ayuda
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Valores guardados correctamente.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Hallintakonsoli
|
||||
admin-console.help=Ohje
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Arvot tallennettiin.
|
||||
|
||||
admin-console.host=Is\u00e4nt\u00e4
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console d'administration
|
||||
admin-console.help=Aide
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Les valeurs ont bien \u00e9t\u00e9 enregistr\u00e9es.
|
||||
|
||||
admin-console.host=H\u00f4te
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console di amministrazione
|
||||
admin-console.help=Aiuto
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=I valori sono stati salvati.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb
|
||||
admin-console.help=\u30d8\u30eb\u30d7
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=\u5024\u3092\u6b63\u5e38\u306b\u4fdd\u5b58\u3057\u307e\u3057\u305f\u3002
|
||||
|
||||
admin-console.host=\u30db\u30b9\u30c8
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin-konsoll
|
||||
admin-console.help=Hjelp
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Verdier som ble lagret.
|
||||
|
||||
admin-console.host=Vert
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Beheerconsole
|
||||
admin-console.help=Help
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Waarden zijn opgeslagen.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Konsola administracyjna
|
||||
admin-console.help=Pomoc
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Warto\u015bci zosta\u0142y zapisane pomy\u015blnie.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console de administra\u00e7\u00e3o
|
||||
admin-console.help=Ajuda
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=Valores salvos com sucesso.
|
||||
|
||||
admin-console.host=Host
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u041a\u043e\u043d\u0441\u043e\u043b\u044c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430
|
||||
admin-console.help=\u0421\u043f\u0440\u0430\u0432\u043a\u0430
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=\u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.
|
||||
|
||||
admin-console.host=\u0425\u043e\u0441\u0442
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin-konsol
|
||||
admin-console.help=Hj\u00e4lp
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=V\u00e4rden sparades.
|
||||
|
||||
admin-console.host=V\u00e4rd
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u7ba1\u7406\u63a7\u5236\u53f0
|
||||
admin-console.help=\u5e2e\u52a9
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.success=\u5df2\u6210\u529f\u4fdd\u5b58\u7684\u503c\u3002
|
||||
|
||||
admin-console.host=\u4e3b\u673a
|
||||
|
@@ -12,9 +12,9 @@
|
||||
<#macro page title readonly=false controller=DEFAULT_CONTROLLER!"/admin" params="" dialog=false>
|
||||
<#assign FORM_ID="admin-jmx-form" />
|
||||
<#if server.edition == "Community">
|
||||
<#assign docsEdition = "community" />
|
||||
<#assign docsEdition = "/Alfresco-Content-Services-Community-Edition/" + server.getVersionMajor() + "." + server.getVersionMinor() + "/Alfresco-Content-Services-Community-Edition" />
|
||||
<#elseif server.edition == "Enterprise" >
|
||||
<#assign docsEdition = server.getVersionMajor() + "." + server.getVersionMinor() />
|
||||
<#assign docsEdition = "/Alfresco-Content-Services/" + server.getVersionMajor() + "." + server.getVersionMinor() + "/Alfresco-Content-Services" />
|
||||
</#if>
|
||||
<#if metadata??>
|
||||
<#assign HOSTNAME>${msg("admin-console.host")}: ${metadata.hostname}</#assign>
|
||||
@@ -551,7 +551,7 @@ Admin.addEventListener(window, 'load', function() {
|
||||
Template for a full page view
|
||||
-->
|
||||
<div class="sticky-wrapper">
|
||||
|
||||
|
||||
<div class="header">
|
||||
<span><a href="${url.serviceContext}${DEFAULT_CONTROLLER!"/admin"}">${msg("admin-console.header")}</a></span><#if metadata??><span class="meta">${HOSTNAME}</span><span class="meta">${HOSTADDR}</span></#if>
|
||||
<div style="float:right"><a href="${msg("admin-console.help-link", docsEdition)}" target="_blank">${msg("admin-console.help")}</a></div>
|
||||
@@ -908,4 +908,4 @@ Admin.addEventListener(window, 'load', function() {
|
||||
<#macro button label description="" onclick="" style="" id="" class="" disabled="false">
|
||||
<input class="<#if class?has_content>${class?html}<#else>inline</#if>" <#if id?has_content>id="${id?html}"</#if> <#if style?has_content>style="${style?html}"</#if> type="button" value="${label?html}" onclick="${onclick?html}" <#if disabled="true">disabled="true"</#if> />
|
||||
<#if description?has_content><span class="description">${description?html}</span></#if>
|
||||
</#macro>
|
||||
</#macro>
|
||||
|
@@ -40,6 +40,7 @@
|
||||
"items":
|
||||
[
|
||||
<#list results as row>
|
||||
<#if row.item.hasPermission("Read")>
|
||||
{
|
||||
"type": "${row.item.typeShort}",
|
||||
"parentType": "${row.item.parentTypeShort!""}",
|
||||
@@ -75,9 +76,10 @@
|
||||
"nodeRef": "${row.item.nodeRef}"<#if row.selectable?exists>,
|
||||
"selectable" : ${row.selectable?string}</#if>
|
||||
}<#if row_has_next>,</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
]
|
||||
}
|
||||
}
|
||||
</#escape>
|
||||
</#macro>
|
||||
</#macro>
|
||||
|
@@ -27,7 +27,7 @@ to integrate with a number of external Authentication providers including
|
||||
* https://github.com/Alfresco/alfresco-data-model/tree/master/src/main/java/org/alfresco/repo/security/authentication
|
||||
* License: LGPL
|
||||
* Issue Tracker Link: https://issues.alfresco.com/jira/issues/?jql=project%3DREPO
|
||||
* Documentation Link: http://docs.alfresco.com/5.2/concepts/auth-intro.html
|
||||
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Administer/Manage-Security/Authentication-and-sync
|
||||
* Contribution Model: Alfresco Open Source
|
||||
***
|
||||
|
||||
|
@@ -16,7 +16,7 @@
|
||||
* Source Code Link:m https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/
|
||||
* License: LGPL
|
||||
* Issue Tracker Link: https://issues.alfresco.com/jira/secure/RapidBoard.jspa?projectKey=REPO&useStoredSettings=true&rapidView=379
|
||||
* Documentation Link: http://docs.alfresco.com/5.1/concepts/versioning.html
|
||||
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Configure/Repository/About-Versioning
|
||||
* Contribution Model: Alfresco publishes the source code and will review proposed patch requests
|
||||
***
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.5.0.10</version>
|
||||
<version>23.5.0.17</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -2,93 +2,96 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 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
|
||||
* 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.action.executer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
|
||||
/**
|
||||
* Add features action executor implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
/**
|
||||
* Action constants
|
||||
*/
|
||||
public static final String NAME = "add-features";
|
||||
public static final String PARAM_ASPECT_NAME = "aspect-name";
|
||||
public static final String PARAM_CONSTRAINT = "ac-aspects";
|
||||
|
||||
/**
|
||||
* The node service
|
||||
*/
|
||||
private NodeService nodeService;
|
||||
|
||||
/** Transaction Service, used for retrying operations */
|
||||
private TransactionService transactionService;
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction service
|
||||
*
|
||||
* @param transactionService the transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adhoc properties are allowed for this executor
|
||||
*/
|
||||
@Override
|
||||
protected boolean getAdhocPropertiesAllowed()
|
||||
{
|
||||
return true;
|
||||
package org.alfresco.repo.action.executer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.access.ActionAccessRestriction;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
|
||||
/**
|
||||
* Add features action executor implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
/**
|
||||
* Action constants
|
||||
*/
|
||||
public static final String NAME = "add-features";
|
||||
public static final String PARAM_ASPECT_NAME = "aspect-name";
|
||||
public static final String PARAM_CONSTRAINT = "ac-aspects";
|
||||
|
||||
/**
|
||||
* The node service
|
||||
*/
|
||||
private NodeService nodeService;
|
||||
|
||||
/** Transaction Service, used for retrying operations */
|
||||
private TransactionService transactionService;
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService
|
||||
* the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction service
|
||||
*
|
||||
* @param transactionService
|
||||
* the transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adhoc properties are allowed for this executor
|
||||
*/
|
||||
@Override
|
||||
protected boolean getAdhocPropertiesAllowed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,55 +99,61 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
*/
|
||||
public void executeImpl(final Action ruleAction, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
if (this.nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
QName aspectQName = null;
|
||||
|
||||
if(! nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
// Node has gone away, skip
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build the aspect details
|
||||
Map<String, Serializable> paramValues = ruleAction.getParameterValues();
|
||||
for (Map.Entry<String, Serializable> entry : paramValues.entrySet())
|
||||
{
|
||||
if (entry.getKey().equals(PARAM_ASPECT_NAME) == true)
|
||||
{
|
||||
aspectQName = (QName)entry.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must be an adhoc property
|
||||
QName propertyQName = QName.createQName(entry.getKey());
|
||||
Serializable propertyValue = entry.getValue();
|
||||
properties.put(propertyQName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the aspect
|
||||
nodeService.addAspect(actionedUponNodeRef, aspectQName, properties);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_ASPECT_NAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASPECT_NAME), false, "ac-aspects"));
|
||||
}
|
||||
|
||||
}
|
||||
if (this.nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
QName aspectQName = null;
|
||||
|
||||
if (!nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
// Node has gone away, skip
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build the aspect details
|
||||
Map<String, Serializable> paramValues = ruleAction.getParameterValues();
|
||||
removeActionContextParameter(paramValues);
|
||||
for (Map.Entry<String, Serializable> entry : paramValues.entrySet())
|
||||
{
|
||||
if (entry.getKey().equals(PARAM_ASPECT_NAME) == true)
|
||||
{
|
||||
aspectQName = (QName) entry.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must be an adhoc property
|
||||
QName propertyQName = QName.createQName(entry.getKey());
|
||||
Serializable propertyValue = entry.getValue();
|
||||
properties.put(propertyQName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the aspect
|
||||
nodeService.addAspect(actionedUponNodeRef, aspectQName, properties);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_ASPECT_NAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASPECT_NAME), false, "ac-aspects"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove actionContext from the parameter values to declassify as an adhoc property
|
||||
*/
|
||||
private void removeActionContextParameter(Map<String, Serializable> paramValues)
|
||||
{
|
||||
paramValues.remove(ActionAccessRestriction.ACTION_CONTEXT_PARAM_NAME);
|
||||
}
|
||||
}
|
||||
|
@@ -58,6 +58,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FolderExistsException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
@@ -73,6 +74,7 @@ import org.alfresco.util.TempFileProvider;
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@SuppressWarnings("PMD.PreserveStackTrace")
|
||||
public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "import";
|
||||
@@ -366,7 +368,11 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// TODO: add failed file info to status message?
|
||||
throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
|
||||
if (e.getType().equalsIgnoreCase("folder"))
|
||||
{
|
||||
throw new FolderExistsException(root, file.getName());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -542,10 +542,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent applicationEvent)
|
||||
{
|
||||
if (eventSender != null)
|
||||
{
|
||||
eventSender.destroy();
|
||||
}
|
||||
// NOOP
|
||||
}
|
||||
|
||||
protected class EventTransactionListener extends TransactionListenerAdapter
|
||||
|
@@ -52,7 +52,7 @@ public interface EventSender
|
||||
}
|
||||
|
||||
/**
|
||||
* It's called when the application context is closing, allowing {@link org.alfresco.repo.event2.EventGenerator} to perform cleanup operations.
|
||||
* It's called when the bean instance is destroyed, allowing to perform cleanup operations.
|
||||
*/
|
||||
default void destroy()
|
||||
{
|
||||
|
@@ -25,15 +25,16 @@
|
||||
*/
|
||||
package org.alfresco.repo.event2;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
|
||||
public class EventSenderFactoryBean extends AbstractFactoryBean<EventSender>
|
||||
{
|
||||
@@ -51,7 +52,7 @@ public class EventSenderFactoryBean extends AbstractFactoryBean<EventSender>
|
||||
private boolean legacySkipQueueConfig;
|
||||
|
||||
public EventSenderFactoryBean(@Autowired PropertyResolver propertyResolver, Event2MessageProducer event2MessageProducer,
|
||||
Executor enqueueThreadPoolExecutor, Executor dequeueThreadPoolExecutor)
|
||||
Executor enqueueThreadPoolExecutor, Executor dequeueThreadPoolExecutor)
|
||||
{
|
||||
super();
|
||||
PropertyCheck.mandatory(this, "propertyResolver", propertyResolver);
|
||||
@@ -155,4 +156,13 @@ public class EventSenderFactoryBean extends AbstractFactoryBean<EventSender>
|
||||
{
|
||||
return event2MessageProducer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyInstance(EventSender eventSender)
|
||||
{
|
||||
if (eventSender != null)
|
||||
{
|
||||
eventSender.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.transform.config.CoreFunction;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -46,6 +47,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
|
||||
@@ -68,6 +70,7 @@ public class LocalTransformClient implements TransformClient, InitializingBean
|
||||
private ContentService contentService;
|
||||
private RenditionService2Impl renditionService2;
|
||||
private boolean directAccessUrlEnabled;
|
||||
private int threadPoolSize;
|
||||
|
||||
private ExecutorService executorService;
|
||||
private ThreadLocal<LocalTransform> transform = new ThreadLocal<>();
|
||||
@@ -97,6 +100,11 @@ public class LocalTransformClient implements TransformClient, InitializingBean
|
||||
this.directAccessUrlEnabled = directAccessUrlEnabled;
|
||||
}
|
||||
|
||||
public void setThreadPoolSize(int threadPoolSize)
|
||||
{
|
||||
this.threadPoolSize = threadPoolSize;
|
||||
}
|
||||
|
||||
public void setExecutorService(ExecutorService executorService)
|
||||
{
|
||||
this.executorService = executorService;
|
||||
@@ -110,9 +118,11 @@ public class LocalTransformClient implements TransformClient, InitializingBean
|
||||
PropertyCheck.mandatory(this, "contentService", contentService);
|
||||
PropertyCheck.mandatory(this, "renditionService2", renditionService2);
|
||||
PropertyCheck.mandatory(this, "directAccessUrlEnabled", directAccessUrlEnabled);
|
||||
PropertyCheck.mandatory(this, "threadPoolSize", threadPoolSize);
|
||||
if (executorService == null)
|
||||
{
|
||||
executorService = Executors.newCachedThreadPool();
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("local-transform-%d").build();
|
||||
executorService = Executors.newFixedThreadPool(threadPoolSize, threadFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,35 +25,27 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.NotAuditable;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Async Rendition service. Replaces the original rendition services which included synchronous renditions and
|
||||
* asynchronous methods with Java call backs.<p/>
|
||||
* The Async Rendition service. Replaces the original rendition services which included synchronous renditions and asynchronous methods with Java call backs.
|
||||
* <p/>
|
||||
*
|
||||
* Renditions are defined as {@link RenditionDefinition2}s and may be registered and looked by the associated
|
||||
* {@link RenditionDefinitionRegistry2}.<p/>
|
||||
* Renditions are defined as {@link RenditionDefinition2}s and may be registered and looked by the associated {@link RenditionDefinitionRegistry2}.
|
||||
* <p/>
|
||||
*
|
||||
* Unlike the original RenditionService this service, it:
|
||||
* <ul>
|
||||
* <li>Performs async renditions without a Java callback, as another node in the cluster may complete the rendition.
|
||||
* The current node requests a transform, but another node might take the resulting transform and turn it into a
|
||||
* rendition if the external Transform Service is used.</li>
|
||||
* <li>Reduces the configurable options to do with with the associations of rendition nodes, their type. They
|
||||
* are identical to 'hidden' (not normally seen as nodes in their own right in a
|
||||
* UI) renditions produced by the original service. So, they are always directly under the source node connected by a
|
||||
* {@code}rn:rendition{@code} association with the name of the rendition.</li>
|
||||
* <li>The rendition nodes additionally have a {@code}rn:rendition2{@code} aspect and a {@code}contentUrlHashCode{@code}
|
||||
* property. This property contains a value that allows the service to work out if it holds a rendition of the
|
||||
* source node's current content.</li>
|
||||
* <li>Failures are handled by setting the rendition node's content to null.</li>
|
||||
* <li>When a rendition is requested via the REST API, only the newer service is used.</li>
|
||||
* <li>Where possible old service renditions migrate automatically over to the new service when content on a
|
||||
* source node is updated.</li>
|
||||
* <li>Performs async renditions without a Java callback, as another node in the cluster may complete the rendition. The current node requests a transform, but another node might take the resulting transform and turn it into a rendition if the external Transform Service is used.</li>
|
||||
* <li>Reduces the configurable options to do with with the associations of rendition nodes, their type. They are identical to 'hidden' (not normally seen as nodes in their own right in a UI) renditions produced by the original service. So, they are always directly under the source node connected by a {@code}rn:rendition{@code} association with the name of the rendition.</li>
|
||||
* <li>The rendition nodes additionally have a {@code}rn:rendition2{@code} aspect and a {@code}contentUrlHashCode{@code} property. This property contains a value that allows the service to work out if it holds a rendition of the source node's current content.</li>
|
||||
* <li>Failures are handled by setting the rendition node's content to null.</li>
|
||||
* <li>When a rendition is requested via the REST API, only the newer service is used.</li>
|
||||
* <li>Where possible old service renditions migrate automatically over to the new service when content on a source node is updated.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author adavis
|
||||
@@ -66,29 +58,30 @@ public interface RenditionService2
|
||||
RenditionDefinitionRegistry2 getRenditionDefinitionRegistry2();
|
||||
|
||||
/**
|
||||
* This method asynchronously transforms content to a target mimetype with transform options supplied in the
|
||||
* {@code transformDefinition}. A response is set on a message queue once the transform is complete or fails,
|
||||
* together with some client supplied data. The response queue and client data are also included in the
|
||||
* transformDefinition.<p>
|
||||
* This method asynchronously transforms content to a target mimetype with transform options supplied in the {@code transformDefinition}. A response is set on a message queue once the transform is complete or fails, together with some client supplied data. The response queue and client data are also included in the transformDefinition.
|
||||
* <p>
|
||||
*
|
||||
* This method does not create a rendition node, but uses the same code as renditions to perform the transform. The
|
||||
* {@code transformDefinition} extends {@link RenditionDefinition2}, but is not stored in a
|
||||
* {@link RenditionDefinitionRegistry2}, as it is transient in nature.
|
||||
* This method does not create a rendition node, but uses the same code as renditions to perform the transform. The {@code transformDefinition} extends {@link RenditionDefinition2}, but is not stored in a {@link RenditionDefinitionRegistry2}, as it is transient in nature.
|
||||
*
|
||||
* @param sourceNodeRef the node from which the content is retrieved.
|
||||
* @param transformDefinition which defines the transform, where to sent the response and some client specified data.
|
||||
* @throws UnsupportedOperationException if the transform is not supported.
|
||||
* @param sourceNodeRef
|
||||
* the node from which the content is retrieved.
|
||||
* @param transformDefinition
|
||||
* which defines the transform, where to sent the response and some client specified data.
|
||||
* @throws UnsupportedOperationException
|
||||
* if the transform is not supported.
|
||||
*/
|
||||
@NotAuditable
|
||||
public void transform(NodeRef sourceNodeRef, TransformDefinition transformDefinition);
|
||||
|
||||
/**
|
||||
* This method asynchronously renders content as specified by the {@code renditionName}. The content to be
|
||||
* rendered is provided by {@code sourceNodeRef}.
|
||||
* This method asynchronously renders content as specified by the {@code renditionName}. The content to be rendered is provided by {@code sourceNodeRef}.
|
||||
*
|
||||
* @param sourceNodeRef the node from which the content is retrieved.
|
||||
* @param renditionName the rendition to be performed.
|
||||
* @throws UnsupportedOperationException if the transform is not supported AND the rendition has not been created before.
|
||||
* @param sourceNodeRef
|
||||
* the node from which the content is retrieved.
|
||||
* @param renditionName
|
||||
* the rendition to be performed.
|
||||
* @throws UnsupportedOperationException
|
||||
* if the transform is not supported AND the rendition has not been created before.
|
||||
*/
|
||||
@NotAuditable
|
||||
public void render(NodeRef sourceNodeRef, String renditionName);
|
||||
@@ -104,10 +97,11 @@ public interface RenditionService2
|
||||
/**
|
||||
* This method gets the rendition of the {@code sourceNodeRef} identified by its name.
|
||||
*
|
||||
* @param sourceNodeRef the source node for the renditions
|
||||
* @param renditionName the renditionName used to identify a rendition.
|
||||
* @return the {@link ChildAssociationRef} which links the source node to the
|
||||
* rendition or <code>null</code> if there is no rendition or it is not up to date.
|
||||
* @param sourceNodeRef
|
||||
* the source node for the renditions
|
||||
* @param renditionName
|
||||
* the renditionName used to identify a rendition.
|
||||
* @return the {@link ChildAssociationRef} which links the source node to the rendition or <code>null</code> if there is no rendition or it is not up to date.
|
||||
*/
|
||||
@NotAuditable
|
||||
ChildAssociationRef getRenditionByName(NodeRef sourceNodeRef, String renditionName);
|
||||
@@ -115,7 +109,8 @@ public interface RenditionService2
|
||||
/**
|
||||
* This method clears source nodeRef rendition content and content hash code using supplied rendition name.
|
||||
*
|
||||
* @param renditionNode the rendition node
|
||||
* @param renditionNode
|
||||
* the rendition node
|
||||
*/
|
||||
@NotAuditable
|
||||
void clearRenditionContentDataInTransaction(NodeRef renditionNode);
|
||||
@@ -124,4 +119,13 @@ public interface RenditionService2
|
||||
* Indicates if renditions are enabled. Set using the {@code system.thumbnail.generate} value.
|
||||
*/
|
||||
boolean isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method forces the content hash code for every {@code sourceNodeRef} renditions.
|
||||
*
|
||||
* @param sourceNodeRef
|
||||
* the source node to update renditions hash code
|
||||
*/
|
||||
@NotAuditable
|
||||
void forceRenditionsContentHashCode(NodeRef sourceNodeRef);
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,6 +25,24 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.model.RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE;
|
||||
import static org.alfresco.service.namespace.QName.createQName;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.content.ContentServicePolicies;
|
||||
@@ -51,23 +69,6 @@ import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.model.RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE;
|
||||
import static org.alfresco.service.namespace.QName.createQName;
|
||||
|
||||
/**
|
||||
* The Async Rendition service. Replaces the original deprecated RenditionService.
|
||||
@@ -95,12 +96,10 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
abstract RenditionDefinition2 getRenditionDefinition();
|
||||
|
||||
void handleUnsupported(UnsupportedOperationException e)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void throwIllegalStateExceptionIfAlreadyDone(int sourceContentHashCode)
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
|
||||
private TransactionService transactionService;
|
||||
@@ -217,8 +216,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
@Override
|
||||
public void transform(NodeRef sourceNodeRef, TransformDefinition transformDefinition)
|
||||
{
|
||||
requestAsyncTransformOrRendition(sourceNodeRef, new RenderOrTransformCallBack()
|
||||
{
|
||||
requestAsyncTransformOrRendition(sourceNodeRef, new RenderOrTransformCallBack() {
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
@@ -237,8 +235,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
@Override
|
||||
public void render(NodeRef sourceNodeRef, String renditionName)
|
||||
{
|
||||
requestAsyncTransformOrRendition(sourceNodeRef, new RenderOrTransformCallBack()
|
||||
{
|
||||
requestAsyncTransformOrRendition(sourceNodeRef, new RenderOrTransformCallBack() {
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
@@ -261,7 +258,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
@Override
|
||||
public void handleUnsupported(UnsupportedOperationException e)
|
||||
{
|
||||
// On the initial request for a rendition throw the exception.
|
||||
// On the initial request for a rendition throw the exception.
|
||||
NodeRef renditionNode = getRenditionNode(sourceNodeRef, renditionName);
|
||||
if (renditionNode == null)
|
||||
{
|
||||
@@ -277,7 +274,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
int renditionContentHashCode = getRenditionContentHashCode(renditionNode);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(getName() + ": Source " + sourceContentHashCode + " rendition " + renditionContentHashCode+ " hashCodes");
|
||||
logger.debug(getName() + ": Source " + sourceContentHashCode + " rendition " + renditionContentHashCode + " hashCodes");
|
||||
}
|
||||
if (renditionContentHashCode == sourceContentHashCode)
|
||||
{
|
||||
@@ -299,14 +296,14 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
|
||||
if (!nodeService.exists(sourceNodeRef))
|
||||
{
|
||||
throw new IllegalArgumentException(renderOrTransform.getName()+ ": The supplied sourceNodeRef "+sourceNodeRef+" does not exist.");
|
||||
throw new IllegalArgumentException(renderOrTransform.getName() + ": The supplied sourceNodeRef " + sourceNodeRef + " does not exist.");
|
||||
}
|
||||
|
||||
RenditionDefinition2 renditionDefinition = renderOrTransform.getRenditionDefinition();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(renderOrTransform.getName()+ ": transform " +sourceNodeRef);
|
||||
logger.debug(renderOrTransform.getName() + ": transform " + sourceNodeRef);
|
||||
}
|
||||
|
||||
AtomicBoolean supported = new AtomicBoolean(true);
|
||||
@@ -328,14 +325,13 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
String user = AuthenticationUtil.getRunAsUser();
|
||||
RetryingTransactionHelper.RetryingTransactionCallback callback = () ->
|
||||
{
|
||||
RetryingTransactionHelper.RetryingTransactionCallback callback = () -> {
|
||||
int sourceContentHashCode = getSourceContentHashCode(sourceNodeRef);
|
||||
if (!supported.get())
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(renderOrTransform.getName() +" is not supported. " +
|
||||
logger.debug(renderOrTransform.getName() + " is not supported. " +
|
||||
"The content might be too big or the source mimetype cannot be converted.");
|
||||
}
|
||||
failure(sourceNodeRef, renditionDefinition, sourceContentHashCode);
|
||||
@@ -372,26 +368,24 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
public void failure(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, int transformContentHashCode)
|
||||
{
|
||||
// The original transaction may have already have failed
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
consume(sourceNodeRef, null, renditionDefinition, transformContentHashCode);
|
||||
return null;
|
||||
}, false, true));
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
consume(sourceNodeRef, null, renditionDefinition, transformContentHashCode);
|
||||
return null;
|
||||
}, false, true));
|
||||
}
|
||||
|
||||
public void consume(NodeRef sourceNodeRef, InputStream transformInputStream, RenditionDefinition2 renditionDefinition,
|
||||
int transformContentHashCode)
|
||||
int transformContentHashCode)
|
||||
{
|
||||
int sourceContentHashCode = getSourceContentHashCode(sourceNodeRef);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Consume: Source " + sourceContentHashCode + " and transform's source " + transformContentHashCode+" hashcodes");
|
||||
logger.debug("Consume: Source " + sourceContentHashCode + " and transform's source " + transformContentHashCode + " hashcodes");
|
||||
}
|
||||
|
||||
if (renditionDefinition instanceof TransformDefinition)
|
||||
{
|
||||
TransformDefinition transformDefinition = (TransformDefinition)renditionDefinition;
|
||||
TransformDefinition transformDefinition = (TransformDefinition) renditionDefinition;
|
||||
String targetMimetype = transformDefinition.getTargetMimetype();
|
||||
if (AsynchronousExtractor.isMetadataExtractMimetype(targetMimetype))
|
||||
{
|
||||
@@ -413,7 +407,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
private void consumeExtractedMetadata(NodeRef nodeRef, int sourceContentHashCode, InputStream transformInputStream,
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
{
|
||||
if (transformInputStream == null)
|
||||
{
|
||||
@@ -440,7 +434,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
private void consumeEmbeddedMetadata(NodeRef nodeRef, int sourceContentHashCode, InputStream transformInputStream,
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
{
|
||||
if (transformInputStream == null)
|
||||
{
|
||||
@@ -468,7 +462,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
private void consumeTransformReply(NodeRef sourceNodeRef, InputStream transformInputStream,
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
TransformDefinition transformDefinition, int transformContentHashCode)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
@@ -484,12 +478,10 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a transformation (InputStream) and attaches it as a rendition to the source node.
|
||||
* Does nothing if there is already a newer rendition.
|
||||
* If the transformInputStream is null, this is taken to be a transform failure.
|
||||
* Takes a transformation (InputStream) and attaches it as a rendition to the source node. Does nothing if there is already a newer rendition. If the transformInputStream is null, this is taken to be a transform failure.
|
||||
*/
|
||||
private void consumeRendition(NodeRef sourceNodeRef, int sourceContentHashCode, InputStream transformInputStream,
|
||||
RenditionDefinition2 renditionDefinition, int transformContentHashCode)
|
||||
RenditionDefinition2 renditionDefinition, int transformContentHashCode)
|
||||
{
|
||||
String renditionName = renditionDefinition.getRenditionName();
|
||||
if (transformContentHashCode != sourceContentHashCode)
|
||||
@@ -507,93 +499,92 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
(transformInputStream == null ? " to null as the transform failed" : " to the transform result"));
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
// Ensure that the creation of a rendition does not cause updates to the modified, modifier properties on the source node
|
||||
NodeRef renditionNode = getRenditionNode(sourceNodeRef, renditionName);
|
||||
boolean createRenditionNode = renditionNode == null;
|
||||
boolean sourceHasAspectRenditioned = nodeService.hasAspect(sourceNodeRef, RenditionModel.ASPECT_RENDITIONED);
|
||||
try
|
||||
{
|
||||
ruleService.disableRuleType(RuleType.UPDATE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
|
||||
// If they do not exist create the rendition association and the rendition node.
|
||||
if (createRenditionNode)
|
||||
{
|
||||
renditionNode = createRenditionNode(sourceNodeRef, renditionDefinition);
|
||||
}
|
||||
else if (!nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2))
|
||||
{
|
||||
nodeService.addAspect(renditionNode, RenditionModel.ASPECT_RENDITION2, null);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Added rendition2 aspect to rendition " + renditionName + " on " + sourceNodeRef);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Set ThumbnailLastModified for " + renditionName);
|
||||
}
|
||||
setThumbnailLastModified(sourceNodeRef, renditionName);
|
||||
|
||||
if (transformInputStream != null)
|
||||
{
|
||||
// Ensure that the creation of a rendition does not cause updates to the modified, modifier properties on the source node
|
||||
NodeRef renditionNode = getRenditionNode(sourceNodeRef, renditionName);
|
||||
boolean createRenditionNode = renditionNode == null;
|
||||
boolean sourceHasAspectRenditioned = nodeService.hasAspect(sourceNodeRef, RenditionModel.ASPECT_RENDITIONED);
|
||||
try
|
||||
{
|
||||
ruleService.disableRuleType(RuleType.UPDATE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
// Set or replace rendition content
|
||||
ContentWriter contentWriter = contentService.getWriter(renditionNode, DEFAULT_RENDITION_CONTENT_PROP, true);
|
||||
String targetMimetype = renditionDefinition.getTargetMimetype();
|
||||
contentWriter.setMimetype(targetMimetype);
|
||||
contentWriter.setEncoding(DEFAULT_ENCODING);
|
||||
ContentWriter renditionWriter = contentWriter;
|
||||
renditionWriter.putContent(transformInputStream);
|
||||
|
||||
// If they do not exist create the rendition association and the rendition node.
|
||||
if (createRenditionNode)
|
||||
ContentReader contentReader = renditionWriter.getReader();
|
||||
long sizeOfRendition = contentReader.getSize();
|
||||
if (sizeOfRendition > 0L)
|
||||
{
|
||||
renditionNode = createRenditionNode(sourceNodeRef, renditionDefinition);
|
||||
}
|
||||
else if (!nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2))
|
||||
{
|
||||
nodeService.addAspect(renditionNode, RenditionModel.ASPECT_RENDITION2, null);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Added rendition2 aspect to rendition " + renditionName + " on " + sourceNodeRef);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Set ThumbnailLastModified for " + renditionName);
|
||||
}
|
||||
setThumbnailLastModified(sourceNodeRef, renditionName);
|
||||
|
||||
if (transformInputStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set or replace rendition content
|
||||
ContentWriter contentWriter = contentService.getWriter(renditionNode, DEFAULT_RENDITION_CONTENT_PROP, true);
|
||||
String targetMimetype = renditionDefinition.getTargetMimetype();
|
||||
contentWriter.setMimetype(targetMimetype);
|
||||
contentWriter.setEncoding(DEFAULT_ENCODING);
|
||||
ContentWriter renditionWriter = contentWriter;
|
||||
renditionWriter.putContent(transformInputStream);
|
||||
|
||||
ContentReader contentReader = renditionWriter.getReader();
|
||||
long sizeOfRendition = contentReader.getSize();
|
||||
if (sizeOfRendition > 0L)
|
||||
{
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Set rendition hashcode for " + renditionName);
|
||||
}
|
||||
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error("Transform was zero bytes for " + renditionName + " on " + sourceNodeRef);
|
||||
clearRenditionContentData(renditionNode);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error("Failed to copy transform InputStream into rendition " + renditionName + " on " + sourceNodeRef);
|
||||
throw e;
|
||||
logger.debug("Set rendition hashcode for " + renditionName);
|
||||
}
|
||||
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error("Transform was zero bytes for " + renditionName + " on " + sourceNodeRef);
|
||||
clearRenditionContentData(renditionNode);
|
||||
}
|
||||
|
||||
if (!sourceHasAspectRenditioned)
|
||||
{
|
||||
nodeService.addAspect(sourceNodeRef, RenditionModel.ASPECT_RENDITIONED, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RenditionService2Exception(TRANSFORMING_ERROR_MESSAGE + e.getMessage(), e);
|
||||
logger.error("Failed to copy transform InputStream into rendition " + renditionName + " on " + sourceNodeRef);
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
ruleService.enableRuleType(RuleType.UPDATE);
|
||||
}
|
||||
return null;
|
||||
}, false, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
clearRenditionContentData(renditionNode);
|
||||
}
|
||||
|
||||
if (!sourceHasAspectRenditioned)
|
||||
{
|
||||
nodeService.addAspect(sourceNodeRef, RenditionModel.ASPECT_RENDITIONED, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RenditionService2Exception(TRANSFORMING_ERROR_MESSAGE + e.getMessage(), e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
ruleService.enableRuleType(RuleType.UPDATE);
|
||||
}
|
||||
return null;
|
||||
}, false, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,14 +625,14 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("Setting thumbnail last modified date to " + lastModifiedValue +" on source node: " + sourceNodeRef);
|
||||
logger.trace("Setting thumbnail last modified date to " + lastModifiedValue + " on source node: " + sourceNodeRef);
|
||||
}
|
||||
|
||||
if (nodeService.hasAspect(sourceNodeRef, ContentModel.ASPECT_THUMBNAIL_MODIFICATION))
|
||||
{
|
||||
List<String> thumbnailMods = (List<String>) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA);
|
||||
String target = null;
|
||||
for (String currThumbnailMod: thumbnailMods)
|
||||
for (String currThumbnailMod : thumbnailMods)
|
||||
{
|
||||
if (currThumbnailMod.startsWith(prefix))
|
||||
{
|
||||
@@ -665,8 +656,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code of the source node's content url. As transformations may be returned in a different
|
||||
* sequences to which they were requested, this is used work out if a rendition should be replaced.
|
||||
* Returns the hash code of the source node's content url. As transformations may be returned in a different sequences to which they were requested, this is used work out if a rendition should be replaced.
|
||||
*/
|
||||
private int getSourceContentHashCode(NodeRef sourceNodeRef)
|
||||
{
|
||||
@@ -675,7 +665,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
if (contentData != null)
|
||||
{
|
||||
// Originally we used the contentData URL, but that is not enough if the mimetype changes.
|
||||
String contentString = contentData.getContentUrl()+contentData.getMimetype();
|
||||
String contentString = contentData.getContentUrl() + contentData.getMimetype();
|
||||
if (contentString != null)
|
||||
{
|
||||
hashCode = contentString.hashCode();
|
||||
@@ -685,13 +675,11 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code of source node's content url on the rendition node (node may be null) if it does not exist.
|
||||
* Used work out if a rendition should be replaced. {@code -2} is returned if the rendition does not exist or was
|
||||
* not created by RenditionService2. {@code -1} is returned if there was no source content or the rendition failed.
|
||||
* Returns the hash code of source node's content url on the rendition node (node may be null) if it does not exist. Used work out if a rendition should be replaced. {@code -2} is returned if the rendition does not exist or was not created by RenditionService2. {@code -1} is returned if there was no source content or the rendition failed.
|
||||
*/
|
||||
private int getRenditionContentHashCode(NodeRef renditionNode)
|
||||
{
|
||||
if ( renditionNode == null || !nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2))
|
||||
if (renditionNode == null || !nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2))
|
||||
{
|
||||
return RENDITION2_DOES_NOT_EXIST;
|
||||
}
|
||||
@@ -699,7 +687,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
Serializable hashCode = nodeService.getProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE);
|
||||
return hashCode == null
|
||||
? SOURCE_HAS_NO_CONTENT
|
||||
: (int)hashCode;
|
||||
: (int) hashCode;
|
||||
}
|
||||
|
||||
private NodeRef getRenditionNode(NodeRef sourceNodeRef, String renditionName)
|
||||
@@ -773,11 +761,12 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the specified source node is of a content class which has been registered for
|
||||
* rendition prevention.
|
||||
* This method checks whether the specified source node is of a content class which has been registered for rendition prevention.
|
||||
*
|
||||
* @param sourceNode the node to check.
|
||||
* @throws RenditionService2PreventedException if the source node is configured for rendition prevention.
|
||||
* @param sourceNode
|
||||
* the node to check.
|
||||
* @throws RenditionService2PreventedException
|
||||
* if the source node is configured for rendition prevention.
|
||||
*/
|
||||
// This code is based on the old RenditionServiceImpl.checkSourceNodeForPreventionClass(...)
|
||||
private void checkSourceNodeForPreventionClass(NodeRef sourceNode)
|
||||
@@ -823,7 +812,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
|
||||
for (ChildAssociationRef childAssoc : childAsocs)
|
||||
{
|
||||
NodeRef renditionNode = childAssoc.getChildRef();
|
||||
NodeRef renditionNode = childAssoc.getChildRef();
|
||||
if (isRenditionAvailable(sourceNodeRef, renditionNode))
|
||||
{
|
||||
result.add(childAssoc);
|
||||
@@ -833,8 +822,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the rendition is available. Failed renditions (there was an error) don't have a contentUrl
|
||||
* and out of date renditions or those still being created don't have a matching contentHashCode.
|
||||
* Indicates if the rendition is available. Failed renditions (there was an error) don't have a contentUrl and out of date renditions or those still being created don't have a matching contentHashCode.
|
||||
*/
|
||||
public boolean isRenditionAvailable(NodeRef sourceNodeRef, NodeRef renditionNode)
|
||||
{
|
||||
@@ -852,7 +840,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
int renditionContentHashCode = getRenditionContentHashCode(renditionNode);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("isRenditionAvailable source " + sourceContentHashCode + " and rendition " + renditionContentHashCode+" hashcodes");
|
||||
logger.debug("isRenditionAvailable source " + sourceContentHashCode + " and rendition " + renditionContentHashCode + " hashcodes");
|
||||
}
|
||||
if (sourceContentHashCode != renditionContentHashCode)
|
||||
{
|
||||
@@ -892,19 +880,17 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
ChildAssociationRef childAssoc = renditions.get(0);
|
||||
NodeRef renditionNode = childAssoc.getChildRef();
|
||||
return !isRenditionAvailable(sourceNodeRef, renditionNode) ? null: childAssoc;
|
||||
return !isRenditionAvailable(sourceNodeRef, renditionNode) ? null : childAssoc;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRenditionContentDataInTransaction(NodeRef renditionNode)
|
||||
{
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
clearRenditionContentData(renditionNode);
|
||||
return null;
|
||||
}, false, true));
|
||||
AuthenticationUtil.runAsSystem((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
clearRenditionContentData(renditionNode);
|
||||
return null;
|
||||
}, false, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -950,4 +936,35 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRenditionsContentHashCode(NodeRef sourceNodeRef)
|
||||
{
|
||||
if (sourceNodeRef != null && nodeService.exists(sourceNodeRef))
|
||||
{
|
||||
List<ChildAssociationRef> renditions = getRenditionChildAssociations(sourceNodeRef);
|
||||
if (renditions != null)
|
||||
{
|
||||
int sourceContentHashCode = getSourceContentHashCode(sourceNodeRef);
|
||||
for (ChildAssociationRef rendition : renditions)
|
||||
{
|
||||
NodeRef renditionNode = rendition.getChildRef();
|
||||
if (nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2))
|
||||
{
|
||||
int renditionContentHashCode = getRenditionContentHashCode(renditionNode);
|
||||
String renditionName = rendition.getQName().getLocalName();
|
||||
if (sourceContentHashCode != renditionContentHashCode)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Update content hash code for rendition " + renditionName + " of node "
|
||||
+ sourceNodeRef);
|
||||
}
|
||||
nodeService.setProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE,
|
||||
sourceContentHashCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -23,41 +23,55 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.service.cmr.model;
|
||||
|
||||
import org.alfresco.api.AlfrescoPublicApi;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Common exception thrown when an operation fails because of a name clash.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
@AlfrescoPublicApi
|
||||
public class FileExistsException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final String MESSAGE_ID = "file_folder_service.file_exists_message";
|
||||
|
||||
private static final long serialVersionUID = -4133713912784624118L;
|
||||
|
||||
private NodeRef parentNodeRef;
|
||||
private String name;
|
||||
|
||||
public FileExistsException(NodeRef parentNodeRef, String name)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[] { name });
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NodeRef getParentNodeRef()
|
||||
{
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
package org.alfresco.service.cmr.model;
|
||||
|
||||
import org.alfresco.api.AlfrescoPublicApi;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Common exception thrown when an operation fails because of a name clash.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
@AlfrescoPublicApi
|
||||
public class FileExistsException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final String MESSAGE_ID = "file_folder_service.file_exists_message";
|
||||
|
||||
private static final long serialVersionUID = -4133713912784624118L;
|
||||
|
||||
private NodeRef parentNodeRef;
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
public FileExistsException(NodeRef parentNodeRef, String name)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[]{name});
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public FileExistsException(NodeRef parentNodeRef, String name, String type)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[]{name});
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public NodeRef getParentNodeRef()
|
||||
{
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.service.cmr.model;
|
||||
|
||||
import org.alfresco.api.AlfrescoPublicApi;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Common exception thrown when an operation fails because of a name clash of folder.
|
||||
*
|
||||
*/
|
||||
@AlfrescoPublicApi
|
||||
public class FolderExistsException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final String MESSAGE_ID = "file_folder_service.file_exists_message";
|
||||
|
||||
private static final long serialVersionUID = -4133713912784624118L;
|
||||
|
||||
private NodeRef parentNodeRef;
|
||||
private String name;
|
||||
|
||||
public FolderExistsException(NodeRef parentNodeRef, String name)
|
||||
{
|
||||
super(MESSAGE_ID, new Object[]{name});
|
||||
this.parentNodeRef = parentNodeRef;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NodeRef getParentNodeRef()
|
||||
{
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Vlastnost ''{0}'' nebyla nastavena: {1} ({2})
|
||||
system.err.duplicate_name=Duplicitn\u00ed n\u00e1zvy pod\u0159\u00edzen\u00fdch objekt\u016f nejsou povoleny ({0})
|
||||
system.err.lucene_not_supported=Subsyst\u00e9m hled\u00e1n\u00ed Lucene nen\u00ed podporov\u00e1n. Viz http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=Subsyst\u00e9m hled\u00e1n\u00ed Lucene nen\u00ed podporov\u00e1n. Viz https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Egenskaben ''{0}'' er ikke blevet indstillet: {1} ({2})
|
||||
system.err.duplicate_name=Duplikeret navn p\u00e5 underordnet er ikke tilladt: {0}
|
||||
system.err.lucene_not_supported=Lucene-s\u00f8geundersystemet underst\u00f8ttes ikke. Se http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=Lucene-s\u00f8geundersystemet underst\u00f8ttes ikke. Se https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Ominaisuutta {0} ei ole m\u00e4\u00e4ritetty: {1} ({2})
|
||||
system.err.duplicate_name=P\u00e4\u00e4llekk\u00e4ist\u00e4 alatasonime\u00e4 ei sallita: {0}
|
||||
system.err.lucene_not_supported=Lucene-hakualij\u00e4rjestelm\u00e4\u00e4 ei tueta. Saat lis\u00e4tietoja osoitteesta http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=Lucene-hakualij\u00e4rjestelm\u00e4\u00e4 ei tueta. Saat lis\u00e4tietoja osoitteesta https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set : {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed : {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Nie ustawiono w\u0142a\u015bciwo\u015bci ''{0}'': {1} ({2})
|
||||
system.err.duplicate_name=Zduplikowane nazwy element\u00f3w podrz\u0119dnych s\u0105 niedozwolone: {0}
|
||||
system.err.lucene_not_supported=Podsystem wyszukiwania Lucene nie jest obs\u0142ugiwany. Zobacz http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=Podsystem wyszukiwania Lucene nie jest obs\u0142ugiwany. Zobacz https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Egenskap ''{0}'' har inte st\u00e4llts in: {1} ({2})
|
||||
system.err.duplicate_name=Dubbelt underordnat namn inte till\u00e5tet: {0}
|
||||
system.err.lucene_not_supported=Lucene-s\u00f6kundersystemet st\u00f6ds inte. Se http://docs.alfresco.com/{0}/uppgifter/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=Lucene-s\u00f6kundersystemet st\u00f6ds inte. Se https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
|
||||
system.err.duplicate_name=Duplicate child name not allowed: {0}
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see http://docs.alfresco.com/{0}/tasks/lucene-solr4-migration.html
|
||||
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
|
||||
|
||||
# Bootstrap configuration check messages
|
||||
|
||||
|
@@ -82,6 +82,7 @@
|
||||
<property name="contentService" ref="contentService" />
|
||||
<property name="renditionService2" ref="renditionService2" />
|
||||
<property name="directAccessUrlEnabled" value="${local.transform.directAccessUrl.enabled}"/>
|
||||
<property name="threadPoolSize" value="${local.transform.threadPoolSize}" />
|
||||
</bean>
|
||||
|
||||
<bean id="synchronousTransformClient" parent="localSynchronousTransformClient" />
|
||||
|
@@ -1351,6 +1351,9 @@ restApi.directAccessUrl.defaultExpiryTimeInSec=30
|
||||
# Controls whether direct access url URLs may be used in transforms.
|
||||
local.transform.directAccessUrl.enabled=true
|
||||
|
||||
# Controls size of thread pool used for transforms.
|
||||
local.transform.threadPoolSize=8
|
||||
|
||||
# Creates additional indexes on alf_node and alf_transaction. Recommended for large repositories.
|
||||
system.new-node-transaction-indexes.ignored=true
|
||||
|
||||
|
@@ -161,5 +161,4 @@
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -171,5 +171,4 @@
|
||||
<value>urldecode</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -1,164 +1,177 @@
|
||||
/*
|
||||
* #%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.action.executer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Add features action execution test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
@Transactional
|
||||
public class AddFeaturesActionExecuterTest extends BaseSpringTest
|
||||
{
|
||||
/**
|
||||
* The node service
|
||||
*/
|
||||
private NodeService nodeService;
|
||||
|
||||
/**
|
||||
* The store reference
|
||||
*/
|
||||
private StoreRef testStoreRef;
|
||||
|
||||
/**
|
||||
* The root node reference
|
||||
*/
|
||||
private NodeRef rootNodeRef;
|
||||
|
||||
/**
|
||||
* The test node reference
|
||||
*/
|
||||
private NodeRef nodeRef;
|
||||
|
||||
/**
|
||||
* The add features action executer
|
||||
*/
|
||||
private AddFeaturesActionExecuter executer;
|
||||
|
||||
/**
|
||||
* Id used to identify the test action created
|
||||
*/
|
||||
private final static String ID = GUID.generate();
|
||||
|
||||
/**
|
||||
* Called at the begining of all tests
|
||||
*/
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
this.nodeService = (NodeService)this.applicationContext.getBean("nodeService");
|
||||
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
|
||||
|
||||
// Create the store and get the root node
|
||||
this.testStoreRef = this.nodeService.createStore(
|
||||
StoreRef.PROTOCOL_WORKSPACE, "Test_"
|
||||
+ System.currentTimeMillis());
|
||||
this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef);
|
||||
|
||||
// Create the node used for tests
|
||||
this.nodeRef = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}testnode"),
|
||||
ContentModel.TYPE_CONTENT).getChildRef();
|
||||
|
||||
// Get the executer instance
|
||||
this.executer = (AddFeaturesActionExecuter)this.applicationContext.getBean(AddFeaturesActionExecuter.NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execution
|
||||
*/
|
||||
@Test
|
||||
public void testExecution()
|
||||
{
|
||||
// Check that the node does not have the classifiable aspect
|
||||
assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE));
|
||||
|
||||
// Execute the action
|
||||
ActionImpl action = new ActionImpl(null, ID, AddFeaturesActionExecuter.NAME, null);
|
||||
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE);
|
||||
this.executer.execute(action, this.nodeRef);
|
||||
|
||||
// Check that the node now has the classifiable aspect applied
|
||||
assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE));
|
||||
}
|
||||
|
||||
/**
|
||||
* MNT-15802
|
||||
*/
|
||||
@Test
|
||||
public void testCheckLocalizedParamDefintionWithConstraint()
|
||||
{
|
||||
// test for other than default locale
|
||||
I18NUtil.setLocale(Locale.GERMAN);
|
||||
|
||||
ActionDefinition actionDef = executer.getActionDefinition();
|
||||
|
||||
List<ParameterDefinition> paramDef = actionDef.getParameterDefinitions();
|
||||
assertNotNull(paramDef);
|
||||
|
||||
String constraintName = paramDef.get(0).getParameterConstraintName();
|
||||
assertNotNull(constraintName);
|
||||
assertEquals(AddFeaturesActionExecuter.PARAM_CONSTRAINT, constraintName);
|
||||
|
||||
// test for other than default locale
|
||||
I18NUtil.setLocale(Locale.ITALY);
|
||||
|
||||
actionDef = executer.getActionDefinition();
|
||||
|
||||
paramDef = actionDef.getParameterDefinitions();
|
||||
assertNotNull(paramDef);
|
||||
|
||||
constraintName = paramDef.get(0).getParameterConstraintName();
|
||||
assertNotNull(constraintName);
|
||||
assertEquals(AddFeaturesActionExecuter.PARAM_CONSTRAINT, constraintName);
|
||||
|
||||
I18NUtil.setLocale(Locale.getDefault());
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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.action.executer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.repo.action.access.ActionAccessRestriction;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
/**
|
||||
* Add features action execution test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
@Transactional
|
||||
public class AddFeaturesActionExecuterTest extends BaseSpringTest
|
||||
{
|
||||
/**
|
||||
* Id used to identify the test action created
|
||||
*/
|
||||
private final static String ID = GUID.generate();
|
||||
/**
|
||||
* The node service
|
||||
*/
|
||||
private NodeService nodeService;
|
||||
/**
|
||||
* The store reference
|
||||
*/
|
||||
private StoreRef testStoreRef;
|
||||
/**
|
||||
* The root node reference
|
||||
*/
|
||||
private NodeRef rootNodeRef;
|
||||
/**
|
||||
* The test node reference
|
||||
*/
|
||||
private NodeRef nodeRef;
|
||||
/**
|
||||
* The add features action executer
|
||||
*/
|
||||
private AddFeaturesActionExecuter executer;
|
||||
|
||||
/**
|
||||
* Called at the begining of all tests
|
||||
*/
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
this.nodeService = (NodeService) this.applicationContext.getBean("nodeService");
|
||||
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
|
||||
|
||||
// Create the store and get the root node
|
||||
this.testStoreRef = this.nodeService.createStore(
|
||||
StoreRef.PROTOCOL_WORKSPACE, "Test_"
|
||||
+ System.currentTimeMillis());
|
||||
this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef);
|
||||
|
||||
// Create the node used for tests
|
||||
this.nodeRef = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}testnode"),
|
||||
ContentModel.TYPE_CONTENT).getChildRef();
|
||||
|
||||
// Get the executer instance
|
||||
this.executer = (AddFeaturesActionExecuter) this.applicationContext.getBean(AddFeaturesActionExecuter.NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execution
|
||||
*/
|
||||
@Test
|
||||
public void testExecution()
|
||||
{
|
||||
// Check that the node does not have the classifiable aspect
|
||||
assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE));
|
||||
|
||||
// Execute the action
|
||||
ActionImpl action = new ActionImpl(null, ID, AddFeaturesActionExecuter.NAME, null);
|
||||
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE);
|
||||
this.executer.execute(action, this.nodeRef);
|
||||
|
||||
// Check that the node now has the classifiable aspect applied
|
||||
assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE));
|
||||
}
|
||||
|
||||
/**
|
||||
* MNT-15802
|
||||
*/
|
||||
@Test
|
||||
public void testCheckLocalizedParamDefintionWithConstraint()
|
||||
{
|
||||
// test for other than default locale
|
||||
I18NUtil.setLocale(Locale.GERMAN);
|
||||
|
||||
ActionDefinition actionDef = executer.getActionDefinition();
|
||||
|
||||
List<ParameterDefinition> paramDef = actionDef.getParameterDefinitions();
|
||||
assertNotNull(paramDef);
|
||||
|
||||
String constraintName = paramDef.get(0).getParameterConstraintName();
|
||||
assertNotNull(constraintName);
|
||||
assertEquals(AddFeaturesActionExecuter.PARAM_CONSTRAINT, constraintName);
|
||||
|
||||
// test for other than default locale
|
||||
I18NUtil.setLocale(Locale.ITALY);
|
||||
|
||||
actionDef = executer.getActionDefinition();
|
||||
|
||||
paramDef = actionDef.getParameterDefinitions();
|
||||
assertNotNull(paramDef);
|
||||
|
||||
constraintName = paramDef.get(0).getParameterConstraintName();
|
||||
assertNotNull(constraintName);
|
||||
assertEquals(AddFeaturesActionExecuter.PARAM_CONSTRAINT, constraintName);
|
||||
|
||||
I18NUtil.setLocale(Locale.getDefault());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test check actionContext param is removed from adhoc properties
|
||||
*/
|
||||
@Test
|
||||
public void testCheckActionContext()
|
||||
{
|
||||
// Execute the action
|
||||
ActionImpl action = new ActionImpl(null, ID, AddFeaturesActionExecuter.NAME, null);
|
||||
action.setParameterValue(ActionAccessRestriction.ACTION_CONTEXT_PARAM_NAME, ActionAccessRestriction.V1_ACTION_CONTEXT);
|
||||
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE);
|
||||
this.executer.execute(action, this.nodeRef);
|
||||
|
||||
// Ensure the actionContext parameter has been removed
|
||||
assertFalse(nodeService.getProperties(this.nodeRef).containsKey(QName.createQName(ActionAccessRestriction.ACTION_CONTEXT_PARAM_NAME)));
|
||||
}
|
||||
}
|
||||
|
@@ -48,6 +48,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.model.FolderExistsException;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -62,7 +63,7 @@ import org.alfresco.util.test.junitrules.ApplicationContextInit;
|
||||
*
|
||||
* @author abalmus
|
||||
*/
|
||||
@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
|
||||
@SuppressWarnings("PMD.UnitTestsShouldIncludeAssert")
|
||||
public class ImporterActionExecuterTest
|
||||
{
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
@@ -340,6 +341,49 @@ public class ImporterActionExecuterTest
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateUnzipping() throws IOException
|
||||
{
|
||||
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
|
||||
|
||||
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
|
||||
{
|
||||
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
// create test data
|
||||
NodeRef zipFileNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTENT).getChildRef();
|
||||
NodeRef targetFolderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_FOLDER).getChildRef();
|
||||
|
||||
putContent(zipFileNodeRef, "import-archive-test/accentCharTestZip.zip");
|
||||
|
||||
Action action = createAction(zipFileNodeRef, "ImporterActionExecuterTestActionDefinition", targetFolderNodeRef);
|
||||
|
||||
try
|
||||
{
|
||||
importerActionExecuter.setUncompressedBytesLimit("100000");
|
||||
importerActionExecuter.execute(action, zipFileNodeRef);
|
||||
// unzip again to duplicate node
|
||||
importerActionExecuter.execute(action, zipFileNodeRef);
|
||||
}
|
||||
catch (FolderExistsException e)
|
||||
{
|
||||
assertTrue(e.getMessage().contains("File or folder accentCharTestZip already exists"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// clean test data
|
||||
nodeService.deleteNode(targetFolderNodeRef);
|
||||
nodeService.deleteNode(zipFileNodeRef);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void putContent(NodeRef zipFileNodeRef, String resource)
|
||||
{
|
||||
URL url = AbstractContentTransformerTest.class.getClassLoader().getResource(resource);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -26,6 +26,7 @@
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import static java.lang.Thread.sleep;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.model.RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE;
|
||||
import static org.alfresco.repo.content.MimetypeMap.EXTENSION_BINARY;
|
||||
@@ -35,6 +36,15 @@ import java.io.FileNotFoundException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.quartz.CronExpression;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.metadata.AsynchronousExtractor;
|
||||
@@ -45,6 +55,7 @@ import org.alfresco.repo.thumbnail.ThumbnailRegistry;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
@@ -52,6 +63,7 @@ import org.alfresco.service.cmr.repository.MimetypeService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
@@ -61,15 +73,6 @@ import org.alfresco.transform.registry.TransformServiceRegistry;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.quartz.CronExpression;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
/**
|
||||
* Class unites common utility methods for {@link org.alfresco.repo.rendition2} package tests.
|
||||
@@ -128,6 +131,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
|
||||
protected static final String ADMIN = "admin";
|
||||
protected static final String DOC_LIB = "doclib";
|
||||
protected static final String PDF = "pdf";
|
||||
|
||||
private CronExpression origLocalTransCron;
|
||||
private CronExpression origRenditionCron;
|
||||
@@ -152,7 +156,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
|
||||
// Strict MimetypeCheck
|
||||
System.setProperty("transformer.strict.mimetype.check", "true");
|
||||
// Retry on DifferentMimetype
|
||||
// Retry on DifferentMimetype
|
||||
System.setProperty("content.transformer.retryOn.different.mimetype", "true");
|
||||
}
|
||||
|
||||
@@ -181,7 +185,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
|
||||
if (transformServiceRegistry instanceof LocalTransformServiceRegistry)
|
||||
{
|
||||
((LocalTransformServiceRegistry)transformServiceRegistry).setEnabled(localTransformServiceEnabled);
|
||||
((LocalTransformServiceRegistry) transformServiceRegistry).setEnabled(localTransformServiceEnabled);
|
||||
}
|
||||
|
||||
thumbnailRegistry.setTransformServiceRegistry(transformServiceRegistry);
|
||||
@@ -257,9 +261,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
// Creates a new source node as the given user in its own transaction.
|
||||
protected NodeRef createSource(String user, String testFileName)
|
||||
{
|
||||
return AuthenticationUtil.runAs(() ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
createSource(testFileName)), user);
|
||||
return AuthenticationUtil.runAs(() -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> createSource(testFileName)), user);
|
||||
}
|
||||
|
||||
// Creates a new source node as the current user in the current transaction.
|
||||
@@ -271,12 +273,10 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
// Changes the content of a source node as the given user in its own transaction.
|
||||
protected void updateContent(String user, NodeRef sourceNodeRef, String testFileName)
|
||||
{
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
updateContent(sourceNodeRef, testFileName);
|
||||
return null;
|
||||
}), user);
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
updateContent(sourceNodeRef, testFileName);
|
||||
return null;
|
||||
}), user);
|
||||
}
|
||||
|
||||
// Changes the content of a source node as the current user in the current transaction.
|
||||
@@ -295,12 +295,10 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
// Clears the content of a source node as the given user in its own transaction.
|
||||
protected void clearContent(String user, NodeRef sourceNodeRef)
|
||||
{
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
clearContent(sourceNodeRef);
|
||||
return null;
|
||||
}), user);
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
clearContent(sourceNodeRef);
|
||||
return null;
|
||||
}), user);
|
||||
}
|
||||
|
||||
// Clears the content of a source node as the current user in the current transaction.
|
||||
@@ -312,23 +310,19 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
// Requests a new rendition as the given user in its own transaction.
|
||||
protected void render(String user, NodeRef sourceNode, String renditionName)
|
||||
{
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
render(sourceNode, renditionName);
|
||||
return null;
|
||||
}), user);
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
render(sourceNode, renditionName);
|
||||
return null;
|
||||
}), user);
|
||||
}
|
||||
|
||||
// Requests a new metadata extract as the given user in its own transaction.
|
||||
protected void extract(String user, NodeRef sourceNode)
|
||||
{
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
extract(sourceNode);
|
||||
return null;
|
||||
}), user);
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
extract(sourceNode);
|
||||
return null;
|
||||
}), user);
|
||||
}
|
||||
|
||||
// Requests a new rendition as the current user in the current transaction.
|
||||
@@ -357,7 +351,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof AssertionFailedError)
|
||||
{
|
||||
throw (AssertionFailedError)cause;
|
||||
throw (AssertionFailedError) cause;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -375,7 +369,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof AssertionFailedError)
|
||||
{
|
||||
throw (AssertionFailedError)cause;
|
||||
throw (AssertionFailedError) cause;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -386,16 +380,15 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
{
|
||||
long maxMillis = 10000;
|
||||
ChildAssociationRef assoc = null;
|
||||
for (int i = (int)(maxMillis / 1000); i >= 0; i--)
|
||||
for (int i = (int) (maxMillis / 1000); i >= 0; i--)
|
||||
{
|
||||
// Must create a new transaction in order to see changes that take place after this method started.
|
||||
assoc = transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
renditionService2.getRenditionByName(sourceNodeRef, renditionName), true, true);
|
||||
assoc = transactionService.getRetryingTransactionHelper().doInTransaction(() -> renditionService2.getRenditionByName(sourceNodeRef, renditionName), true, true);
|
||||
if (assoc != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
logger.debug("RenditionService2.getRenditionByName(...) sleep "+i);
|
||||
logger.debug("RenditionService2.getRenditionByName(...) sleep " + i);
|
||||
sleep(1000);
|
||||
}
|
||||
if (shouldExist)
|
||||
@@ -415,11 +408,10 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
{
|
||||
long maxMillis = 5000;
|
||||
boolean nodeModified = true;
|
||||
for (int i = (int)(maxMillis / 1000); i >= 0; i--)
|
||||
for (int i = (int) (maxMillis / 1000); i >= 0; i--)
|
||||
{
|
||||
// Must create a new transaction in order to see changes that take place after this method started.
|
||||
nodeModified = transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
nodeModified = transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
Serializable created = nodeService.getProperty(sourceNodeRef, ContentModel.PROP_CREATED);
|
||||
Serializable modified = nodeService.getProperty(sourceNodeRef, ContentModel.PROP_MODIFIED);
|
||||
return !created.equals(modified);
|
||||
@@ -428,7 +420,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
{
|
||||
break;
|
||||
}
|
||||
logger.debug("waitForExtract sleep "+i);
|
||||
logger.debug("waitForExtract sleep " + i);
|
||||
sleep(1000);
|
||||
}
|
||||
if (nodePropsShouldChange)
|
||||
@@ -445,7 +437,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
protected String getTestFileName(String sourceMimetype) throws FileNotFoundException
|
||||
{
|
||||
String extension = mimetypeMap.getExtension(sourceMimetype);
|
||||
String testFileName = extension.equals(EXTENSION_BINARY) ? null : "quick."+extension;
|
||||
String testFileName = extension.equals(EXTENSION_BINARY) ? null : "quick." + extension;
|
||||
if (testFileName != null)
|
||||
{
|
||||
try
|
||||
@@ -491,8 +483,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
|
||||
String createRandomUser()
|
||||
{
|
||||
return AuthenticationUtil.runAs(() ->
|
||||
{
|
||||
return AuthenticationUtil.runAs(() -> {
|
||||
String username = generateNewUsernameString();
|
||||
createUser(username);
|
||||
return username;
|
||||
@@ -505,13 +496,12 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
}
|
||||
|
||||
void createUser(final String username,
|
||||
final String firstName,
|
||||
final String lastName,
|
||||
final String jobTitle,
|
||||
final long quota)
|
||||
final String firstName,
|
||||
final String lastName,
|
||||
final String jobTitle,
|
||||
final long quota)
|
||||
{
|
||||
RetryingTransactionHelper.RetryingTransactionCallback<Void> createUserCallback = () ->
|
||||
{
|
||||
RetryingTransactionHelper.RetryingTransactionCallback<Void> createUserCallback = () -> {
|
||||
authenticationService.createAuthentication(username, PASSWORD.toCharArray());
|
||||
|
||||
PropertyMap personProperties = new PropertyMap();
|
||||
@@ -519,7 +509,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
personProperties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, "title" + username);
|
||||
personProperties.put(ContentModel.PROP_FIRSTNAME, firstName);
|
||||
personProperties.put(ContentModel.PROP_LASTNAME, lastName);
|
||||
personProperties.put(ContentModel.PROP_EMAIL, username+"@example.com");
|
||||
personProperties.put(ContentModel.PROP_EMAIL, username + "@example.com");
|
||||
personProperties.put(ContentModel.PROP_JOBTITLE, jobTitle);
|
||||
if (quota > 0)
|
||||
{
|
||||
@@ -548,14 +538,12 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which gets the content hash code from the supplied rendition node without specific validations (the
|
||||
* equivalent method from {@link RenditionService2Impl} is not exposed)
|
||||
* Helper method which gets the content hash code from the supplied rendition node without specific validations (the equivalent method from {@link RenditionService2Impl} is not exposed)
|
||||
*
|
||||
* @param renditionNodeRef
|
||||
* the rendition node
|
||||
*
|
||||
* @return -1 in case of there is no content, -2 in case rendition doesn't exist, the actual content hash code
|
||||
* otherwise
|
||||
* @return -1 in case of there is no content, -2 in case rendition doesn't exist, the actual content hash code otherwise
|
||||
*/
|
||||
protected int getRenditionContentHashCode(NodeRef renditionNodeRef)
|
||||
{
|
||||
@@ -569,4 +557,28 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
|
||||
return renditionContentHashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which gets the content hash code from the supplied source node (the equivalent method from {@link RenditionService2Impl} is not public)
|
||||
*
|
||||
* @param sourceNodeRef
|
||||
* the source node
|
||||
*
|
||||
* @return -1 in case of there is no content, otherwise, the actual content hash code otherwise
|
||||
*/
|
||||
protected int getSourceContentHashCode(NodeRef sourceNodeRef)
|
||||
{
|
||||
int hashCode = -1;
|
||||
ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, nodeService.getProperty(sourceNodeRef, PROP_CONTENT));
|
||||
if (contentData != null)
|
||||
{
|
||||
// Originally we used the contentData URL, but that is not enough if the mimetype changes.
|
||||
String contentString = contentData.getContentUrl() + contentData.getMimetype();
|
||||
if (contentString != null)
|
||||
{
|
||||
hashCode = contentString.hashCode();
|
||||
}
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,14 +25,18 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -44,8 +48,6 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RenditionService2}
|
||||
@@ -62,37 +64,37 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
// PDF transformation
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfToJpegMedium()
|
||||
public void testLocalRenderPdfToJpegMedium()
|
||||
{
|
||||
checkRendition("quick.pdf", "medium", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfToDoclib()
|
||||
public void testLocalRenderPdfToDoclib()
|
||||
{
|
||||
checkRendition("quick.pdf", "doclib", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfJpegImgpreview()
|
||||
public void testLocalRenderPdfJpegImgpreview()
|
||||
{
|
||||
checkRendition("quick.pdf", "imgpreview", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfPngAvatar()
|
||||
public void testLocalRenderPdfPngAvatar()
|
||||
{
|
||||
checkRendition("quick.pdf", "avatar", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfPngAvatar32()
|
||||
public void testLocalRenderPdfPngAvatar32()
|
||||
{
|
||||
checkRendition("quick.pdf", "avatar32", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderPdfFlashWebpreview()
|
||||
public void testLocalRenderPdfFlashWebpreview()
|
||||
{
|
||||
checkRendition("quick.pdf", "webpreview", false);
|
||||
}
|
||||
@@ -100,43 +102,43 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
// DOCX transformation
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxJpegMedium()
|
||||
public void testLocalRenderDocxJpegMedium()
|
||||
{
|
||||
checkRendition("quick.docx", "medium", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxDoclib()
|
||||
public void testLocalRenderDocxDoclib()
|
||||
{
|
||||
checkRendition("quick.docx", "doclib", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxJpegImgpreview()
|
||||
public void testLocalRenderDocxJpegImgpreview()
|
||||
{
|
||||
checkRendition("quick.docx", "imgpreview", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxPngAvatar()
|
||||
public void testLocalRenderDocxPngAvatar()
|
||||
{
|
||||
checkRendition("quick.docx", "avatar", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxPngAvatar32()
|
||||
public void testLocalRenderDocxPngAvatar32()
|
||||
{
|
||||
checkRendition("quick.docx", "avatar32", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxFlashWebpreview()
|
||||
public void testLocalRenderDocxFlashWebpreview()
|
||||
{
|
||||
checkRendition("quick.docx", "webpreview", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRenderDocxPdf()
|
||||
public void testLocalRenderDocxPdf()
|
||||
{
|
||||
checkRendition("quick.docx", "pdf", true);
|
||||
}
|
||||
@@ -150,7 +152,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changedSourceToNullContent()
|
||||
public void changedSourceToNullContent()
|
||||
{
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
@@ -158,8 +160,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
|
||||
clearContent(ADMIN, sourceNodeRef);
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
ChildAssociationRef assoc = AuthenticationUtil.runAs(() ->
|
||||
renditionService2.getRenditionByName(sourceNodeRef, DOC_LIB), ADMIN);
|
||||
ChildAssociationRef assoc = AuthenticationUtil.runAs(() -> renditionService2.getRenditionByName(sourceNodeRef, DOC_LIB), ADMIN);
|
||||
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, false);
|
||||
assertNull("There should be no rendition as there was no content", assoc);
|
||||
}
|
||||
@@ -190,8 +191,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
|
||||
clearContent(ADMIN, sourceNodeRef);
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
ChildAssociationRef assoc = AuthenticationUtil.runAs(() ->
|
||||
renditionService2.getRenditionByName(sourceNodeRef, DOC_LIB), ADMIN);
|
||||
ChildAssociationRef assoc = AuthenticationUtil.runAs(() -> renditionService2.getRenditionByName(sourceNodeRef, DOC_LIB), ADMIN);
|
||||
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, false);
|
||||
assertNull("There should be no rendition as there was no content", assoc);
|
||||
|
||||
@@ -201,7 +201,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRenditionByUser()
|
||||
public void testCreateRenditionByUser()
|
||||
{
|
||||
String userName = createRandomUser();
|
||||
NodeRef sourceNodeRef = createSource(userName, "quick.jpg");
|
||||
@@ -211,13 +211,12 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadRenditionByOtherUser()
|
||||
public void testReadRenditionByOtherUser()
|
||||
{
|
||||
String ownerUserName = createRandomUser();
|
||||
NodeRef sourceNodeRef = createSource(ownerUserName, "quick.jpg");
|
||||
String otherUserName = createRandomUser();
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
permissionService.setPermission(sourceNodeRef, otherUserName, PermissionService.READ, true);
|
||||
return null;
|
||||
});
|
||||
@@ -231,13 +230,12 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderByReader()
|
||||
public void testRenderByReader()
|
||||
{
|
||||
String ownerUserName = createRandomUser();
|
||||
NodeRef sourceNodeRef = createSource(ownerUserName, "quick.jpg");
|
||||
String otherUserName = createRandomUser();
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
permissionService.setPermission(sourceNodeRef, otherUserName, PermissionService.READ, true);
|
||||
return null;
|
||||
});
|
||||
@@ -251,14 +249,13 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessWithNoPermissions()
|
||||
public void testAccessWithNoPermissions()
|
||||
{
|
||||
String ownerUserName = createRandomUser();
|
||||
NodeRef sourceNodeRef = createSource(ownerUserName, "quick.jpg");
|
||||
render(ownerUserName, sourceNodeRef, DOC_LIB);
|
||||
String noPermissionsUser = createRandomUser();
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
permissionService.setPermission(sourceNodeRef, noPermissionsUser, PermissionService.ALL_PERMISSIONS, false);
|
||||
return null;
|
||||
});
|
||||
@@ -280,12 +277,9 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
NodeRef sourceNodeRef = createSource(ownerUserName, "quick.jpg");
|
||||
final QName doclibRendDefQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
renditionService.render(sourceNodeRef, doclibRendDefQName), ownerUserName));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> renditionService.render(sourceNodeRef, doclibRendDefQName), ownerUserName));
|
||||
|
||||
NodeRef oldRendition = AuthenticationUtil.runAs(() ->
|
||||
renditionService.getRenditionByName(sourceNodeRef, doclibRendDefQName).getChildRef(), ownerUserName);
|
||||
NodeRef oldRendition = AuthenticationUtil.runAs(() -> renditionService.getRenditionByName(sourceNodeRef, doclibRendDefQName).getChildRef(), ownerUserName);
|
||||
assertFalse("The rendition should be generated by old Rendition Service",
|
||||
AuthenticationUtil.runAs(() -> nodeService.hasAspect(oldRendition, RenditionModel.ASPECT_RENDITION2), ownerUserName));
|
||||
|
||||
@@ -335,12 +329,10 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
renditionService2.setEnabled(false);
|
||||
|
||||
// Call 'clearRenditionContentData' method directly to prove rendition content will be cleaned
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
renditionService2.clearRenditionContentData(sourceNodeRef, DOC_LIB);
|
||||
return null;
|
||||
}), ADMIN);
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||
renditionService2.clearRenditionContentData(sourceNodeRef, DOC_LIB);
|
||||
return null;
|
||||
}), ADMIN);
|
||||
|
||||
// The rendition should not have content by now
|
||||
assertNull("Rendition has content", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
|
||||
@@ -356,8 +348,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
/**
|
||||
* Tests if a rendition without content (but with contentHashCode) can be generated again.
|
||||
* <p>
|
||||
* If the rendition consumption receives a null InputStream, the contentHashCode should be cleaned from the
|
||||
* rendition node, allowing new requests to generate the rendition.
|
||||
* If the rendition consumption receives a null InputStream, the contentHashCode should be cleaned from the rendition node, allowing new requests to generate the rendition.
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@@ -369,8 +360,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
/**
|
||||
* Tests if a rendition without content (but with contentHashCode) can be generated again.
|
||||
* <p>
|
||||
* If the rendition consumption receives a zero length InputStream, the contentHashCode should be cleaned from the
|
||||
* rendition node, allowing new requests to generate the rendition.
|
||||
* If the rendition consumption receives a zero length InputStream, the contentHashCode should be cleaned from the rendition node, allowing new requests to generate the rendition.
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@@ -455,6 +445,61 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
assertEquals(TOTAL_NODES, countModifier(nodes, user1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForceRenditionsContentHashCode()
|
||||
{
|
||||
|
||||
// Create a node
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.docx");
|
||||
assertNotNull("Node not generated", sourceNodeRef);
|
||||
|
||||
// Get content hash code for the source node
|
||||
int sourceNodeContentHashCode = getSourceContentHashCode(sourceNodeRef);
|
||||
|
||||
// Trigger the pdf rendition
|
||||
render(ADMIN, sourceNodeRef, PDF);
|
||||
NodeRef pdfRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, PDF, true);
|
||||
assertNotNull("pdf rendition was not generated", pdfRenditionNodeRef);
|
||||
assertNotNull("pdf rendition was not generated", nodeService.getProperty(pdfRenditionNodeRef, PROP_CONTENT));
|
||||
|
||||
// Check the pdf rendition content hash code is valid
|
||||
int pdfRenditionContentHashCode = getRenditionContentHashCode(pdfRenditionNodeRef);
|
||||
assertEquals("pdf rendition content hash code is different from source node content hash code", sourceNodeContentHashCode, pdfRenditionContentHashCode);
|
||||
|
||||
// Trigger the doc lib rendition
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
NodeRef docLibRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
assertNotNull("doc lib rendition was not generated", docLibRenditionNodeRef);
|
||||
assertNotNull("doc lib rendition was not generated", nodeService.getProperty(docLibRenditionNodeRef, PROP_CONTENT));
|
||||
|
||||
// Check the doc lib rendition content hash code is valid
|
||||
int docLibenditionContentHashCode = getRenditionContentHashCode(docLibRenditionNodeRef);
|
||||
assertEquals("doc lib rendition content hash code is different from source node content hash code", sourceNodeContentHashCode, docLibenditionContentHashCode);
|
||||
|
||||
// Update the source node content
|
||||
updateContent(ADMIN, sourceNodeRef, "quick.docx");
|
||||
|
||||
// Get source node content hash code after update
|
||||
int sourceNodeContentHashCode2 = getSourceContentHashCode(sourceNodeRef);
|
||||
|
||||
// Check content hash code are different after content update
|
||||
assertNotEquals("Source node content hash code is the same after content update", sourceNodeContentHashCode, sourceNodeContentHashCode2);
|
||||
assertNotEquals("pdf rendition content hash code is the same after content update", sourceNodeContentHashCode2, pdfRenditionContentHashCode);
|
||||
assertNotEquals("doc lib rendition content hash code is the same after content update", sourceNodeContentHashCode2, docLibenditionContentHashCode);
|
||||
|
||||
// Forces the content hash code for every source node renditions
|
||||
AuthenticationUtil.runAs(() -> {
|
||||
renditionService2.forceRenditionsContentHashCode(sourceNodeRef);
|
||||
return null;
|
||||
}, ADMIN);
|
||||
|
||||
// Check the renditions content hash code are now the same as the latest source node content hash code
|
||||
int pdfRenditionContentHashCode2 = getRenditionContentHashCode(pdfRenditionNodeRef);
|
||||
int docLibenditionContentHashCode2 = getRenditionContentHashCode(docLibRenditionNodeRef);
|
||||
assertEquals("pdf rendition content hash code is different from latest source node content hash code", sourceNodeContentHashCode2, pdfRenditionContentHashCode2);
|
||||
assertEquals("doc lib rendition content hash code is different from latest source node content hash code", sourceNodeContentHashCode2, docLibenditionContentHashCode2);
|
||||
}
|
||||
|
||||
private int countModifier(List<NodeRef> nodes, String user)
|
||||
{
|
||||
int count = 0;
|
||||
@@ -492,22 +537,16 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
final QName doclibRendDefQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
assertNotNull("The old renditions service did not render", waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true));
|
||||
List<String> lastThumbnailModification = transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
(List<String>) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA), ADMIN));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> (List<String>) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA), ADMIN));
|
||||
updateContent(ADMIN, sourceNodeRef, "quick.png");
|
||||
List<String> newThumbnailModification = null;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
newThumbnailModification = transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
(List<String>) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA), ADMIN));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> (List<String>) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA), ADMIN));
|
||||
if (!newThumbnailModification.equals(lastThumbnailModification))
|
||||
{
|
||||
break;
|
||||
@@ -579,9 +618,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
final QName doclibRendDefQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
|
||||
renditionService2.setEnabled(true);
|
||||
@@ -652,9 +689,7 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
final QName doclibRendDefQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() ->
|
||||
AuthenticationUtil.runAs(() ->
|
||||
renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(() -> renditionService.render(sourceNodeRef, doclibRendDefQName), ADMIN));
|
||||
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
|
||||
renditionService2.setEnabled(true);
|
||||
@@ -682,4 +717,63 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
renditionService2.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecreationOfRendition2()
|
||||
{
|
||||
renditionService2.setEnabled(true);
|
||||
try
|
||||
{
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.docx");
|
||||
assertNotNull("Node not generated", sourceNodeRef);
|
||||
|
||||
// Get content hash code for the source node.
|
||||
int sourceNodeContentHashCode = getSourceContentHashCode(sourceNodeRef);
|
||||
|
||||
// Trigger the pdf rendition.
|
||||
render(ADMIN, sourceNodeRef, PDF);
|
||||
NodeRef pdfRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, PDF, true);
|
||||
assertNotNull("pdf rendition was not generated", pdfRenditionNodeRef);
|
||||
assertNotNull("pdf rendition was not generated",
|
||||
nodeService.getProperty(pdfRenditionNodeRef, PROP_CONTENT));
|
||||
|
||||
// Check the pdf rendition content hash code is valid
|
||||
int pdfRenditionContentHashCode = getRenditionContentHashCode(pdfRenditionNodeRef);
|
||||
assertEquals("pdf rendition content hash code is different from source node content hash code",
|
||||
sourceNodeContentHashCode, pdfRenditionContentHashCode);
|
||||
|
||||
// Calling 'clearRenditionContentData' method directly so that rendition content will be cleaned.
|
||||
AuthenticationUtil.runAs(
|
||||
(AuthenticationUtil.RunAsWork<Void>) () -> transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() -> {
|
||||
renditionService2.clearRenditionContentData(sourceNodeRef, PDF);
|
||||
return null;
|
||||
}),
|
||||
ADMIN);
|
||||
|
||||
assertNull("Rendition has content", nodeService.getProperty(pdfRenditionNodeRef, PROP_CONTENT));
|
||||
|
||||
pdfRenditionContentHashCode = getRenditionContentHashCode(pdfRenditionNodeRef);
|
||||
assertFalse("Rendition has content hash code",
|
||||
isValidRenditionContentHashCode(pdfRenditionContentHashCode));
|
||||
|
||||
renditionService2.setEnabled(false);
|
||||
|
||||
final QName pdfRendDefQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "pdf");
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(() -> AuthenticationUtil.runAs(
|
||||
() -> renditionService.render(sourceNodeRef, pdfRendDefQName), ADMIN));
|
||||
|
||||
renditionService2.setEnabled(true);
|
||||
|
||||
NodeRef pdfRecreatedRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, PDF, true);
|
||||
assertNotEquals(" Rendition before deletion and after previewing are identical",
|
||||
pdfRenditionNodeRef.getId(), pdfRecreatedRenditionNodeRef.getId());
|
||||
}
|
||||
finally
|
||||
{
|
||||
renditionService2.setEnabled(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@
|
||||
</onException>
|
||||
<transacted />
|
||||
<loadBalance>
|
||||
<roundRobin/>
|
||||
<roundRobinLoadBalancer/>
|
||||
<to uri="bean:mockExceptionThrowingConsumer"/>
|
||||
<to uri="bean:mockConsumer"/>
|
||||
</loadBalance>
|
||||
|
Reference in New Issue
Block a user