diff --git a/pom.xml b/pom.xml
index 97c2bc579b..edcf07d5b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,7 +62,7 @@
2.11.2
3.4.0
1.1.0
- 2.0.20
+ 2.0.21
8.8
1.66
3.5.11
@@ -81,7 +81,7 @@
2.5.9
1.6.2
1.24.1
- 5.2.1.RELEASE
+ 5.3.4.RELEASE
7.7.10
4.1.2
1.4
diff --git a/repository/pom.xml b/repository/pom.xml
index c101232f73..c0db473a9c 100644
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -142,7 +142,7 @@
org.mozilla
rhino
- 1.7.12
+ 1.7.13
org.springframework
diff --git a/repository/src/main/java/org/alfresco/opencmis/TransactionAwareHolder.java b/repository/src/main/java/org/alfresco/opencmis/TransactionAwareHolder.java
index a5c5991583..e35d75d413 100644
--- a/repository/src/main/java/org/alfresco/opencmis/TransactionAwareHolder.java
+++ b/repository/src/main/java/org/alfresco/opencmis/TransactionAwareHolder.java
@@ -81,22 +81,19 @@ public class TransactionAwareHolder extends Holder
{
this.internalHolder = internalHolder;
this.value = internalHolder.getValue();
- txListener = new TxAwareHolderListener();
}
@Override
public T getValue()
{
- if (TransactionSynchronizationManager.isSynchronizationActive())
- {
- AlfrescoTransactionSupport.bindListener(txListener);
- }
+ registerTxListenerIfNeeded();
return this.value;
}
@Override
public void setValue(T value)
{
+ registerTxListenerIfNeeded();
this.value = value;
}
@@ -109,6 +106,17 @@ public class TransactionAwareHolder extends Holder
'}';
}
+ // MNT-21800 CMIS Web Service Check Out returns error
+ private void registerTxListenerIfNeeded()
+ {
+ if (this.txListener == null && TransactionSynchronizationManager.isSynchronizationActive())
+ {
+ TxAwareHolderListener listener = new TxAwareHolderListener();
+ AlfrescoTransactionSupport.bindListener(listener);
+ this.txListener = listener;
+ }
+ }
+
private class TxAwareHolderListener extends TransactionListenerAdapter
{
@Override
diff --git a/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java b/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
index 774cccc9bd..8d7b54d07d 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java
@@ -430,8 +430,8 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
// {
// setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false);
// }
- // Already replaced
- if(acl.equals(sharedAclToReplace))
+ // Still has old shared ACL or already replaced
+ if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom))
{
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
}
diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/impl/SimplePermissionReference.java b/repository/src/main/java/org/alfresco/repo/security/permissions/impl/SimplePermissionReference.java
index e34f22b0c8..9ff1ebc3ab 100644
--- a/repository/src/main/java/org/alfresco/repo/security/permissions/impl/SimplePermissionReference.java
+++ b/repository/src/main/java/org/alfresco/repo/security/permissions/impl/SimplePermissionReference.java
@@ -1,35 +1,35 @@
-/*
- * #%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 .
- * #L%
- */
+/*
+ * #%L
+ * Alfresco Repository
+ * %%
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ * #L%
+ */
package org.alfresco.repo.security.permissions.impl;
-import java.util.HashMap;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.Pair;
/**
* A simple permission reference.
@@ -37,62 +37,30 @@ import org.alfresco.service.namespace.QName;
* @author andyh
*/
public final class SimplePermissionReference extends AbstractPermissionReference
-{
+{
private static final long serialVersionUID = 637302438293417818L;
- private static ReadWriteLock lock = new ReentrantReadWriteLock();
-
- private static HashMap> instances = new HashMap>();
+ //Use thread-safe map initiallized with a slightly larger capacity to reduce the posibility of two or more threads attempting to resize at the same time
+ private static ConcurrentMap, SimplePermissionReference> instances = new ConcurrentHashMap<>(100, 0.9f, 2);
/**
- * Factory method to create simple permission refrences
+ * Factory method to create simple permission references
*
* @return a simple permission reference
*/
public static SimplePermissionReference getPermissionReference(QName qName, String name)
{
- lock.readLock().lock();
- try
- {
- HashMap typed = instances.get(qName);
- if(typed != null)
+ Pair key = new Pair<>(qName, name);
+ SimplePermissionReference instance = instances.get(key);
+ if (instance == null)
{
- SimplePermissionReference instance = typed.get(name);
- if(instance != null)
- {
- return instance;
- }
- }
- }
- finally
- {
- lock.readLock().unlock();
- }
-
- lock.writeLock().lock();
- try
- {
- HashMap typed = instances.get(qName);
- if(typed == null)
- {
- typed = new HashMap();
- instances.put(qName, typed);
- }
- SimplePermissionReference instance = typed.get(name);
- if(instance == null)
- {
- instance = new SimplePermissionReference(qName, name);
- typed.put(name, instance);
+ instance = new SimplePermissionReference(qName, name);
+ instances.putIfAbsent(key, instance);
}
+
return instance;
- }
- finally
- {
- lock.writeLock().unlock();
- }
}
-
/*
* The type
*/
diff --git a/repository/src/main/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java b/repository/src/main/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
index 95a240a523..4a45bc649b 100644
--- a/repository/src/main/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
+++ b/repository/src/main/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
@@ -691,20 +691,18 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
return new ArrayList(visited);
}
-
+ /** Get properties that we want to be indexed. */
protected Map getProperties(Long nodeId)
{
- Map props = null;
-
// ALF-10641
- // Residual properties are un-indexed -> break serlialisation
+ // Residual properties are un-indexed -> break serialisation
nodeDAO.setCheckNodeConsistency();
Map sourceProps = nodeDAO.getNodeProperties(nodeId);
- props = new HashMap((int)(sourceProps.size() * 1.3));
+ Map props = new HashMap<>(sourceProps.size());
for(QName propertyQName : sourceProps.keySet())
{
PropertyDefinition propDef = dictionaryService.getProperty(propertyQName);
- if(propDef != null)
+ if(propDef != null && propDef.isIndexed())
{
props.put(propertyQName, sourceProps.get(propertyQName));
}
diff --git a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql
index 2599697199..76a1107baa 100644
--- a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql
+++ b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql
@@ -169,7 +169,9 @@ CREATE TABLE alf_transaction
change_txn_id VARCHAR(56) NOT NULL,
commit_time_ms BIGINT,
PRIMARY KEY (id),
- KEY idx_alf_txn_ctms (commit_time_ms)
+ KEY idx_alf_txn_ctms (commit_time_ms, id),
+ KEY idx_alf_txn_ctms_sc (commit_time_ms),
+ key idx_alf_txn_id_ctms (id, commit_time_ms)
) ENGINE=InnoDB;
CREATE TABLE alf_store
@@ -210,6 +212,8 @@ CREATE TABLE alf_node
KEY idx_alf_node_crd (audit_created, store_id, type_qname_id),
KEY idx_alf_node_mor (audit_modifier, store_id, type_qname_id),
KEY idx_alf_node_mod (audit_modified, store_id, type_qname_id),
+ KEY idx_alf_node_ver (version),
+ KEY idx_alf_node_txn (transaction_id),
CONSTRAINT fk_alf_node_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id),
CONSTRAINT fk_alf_node_store FOREIGN KEY (store_id) REFERENCES alf_store (id),
CONSTRAINT fk_alf_node_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id),
diff --git a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ALF.xml b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ALF.xml
index ae71a60993..7d6c902e4d 100644
--- a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ALF.xml
+++ b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/Schema-Reference-ALF.xml
@@ -1681,6 +1681,16 @@
type_qname_id
+
+
+ version
+
+
+
+
+ transaction_id
+
+
@@ -2630,6 +2640,18 @@
commit_time_ms
+ id
+
+
+
+
+ commit_time_ms
+
+
+
+
+ id
+ commit_time_ms
diff --git a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql
index 393e9accec..364625ea54 100644
--- a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql
+++ b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql
@@ -184,6 +184,8 @@ CREATE TABLE alf_transaction
PRIMARY KEY (id)
);
CREATE INDEX idx_alf_txn_ctms ON alf_transaction (commit_time_ms, id);
+CREATE INDEX idx_alf_txn_ctms_sc ON alf_transaction (commit_time_ms);
+CREATE INDEX idx_alf_txn_id_ctms ON alf_transaction (id, commit_time_ms);
CREATE SEQUENCE alf_store_seq START WITH 1 INCREMENT BY 1;
CREATE TABLE alf_store
@@ -231,6 +233,8 @@ CREATE INDEX fk_alf_node_acl ON alf_node (acl_id);
CREATE INDEX fk_alf_node_store ON alf_node (store_id);
CREATE INDEX idx_alf_node_tqn ON alf_node (type_qname_id, store_id, id);
CREATE INDEX fk_alf_node_loc ON alf_node (locale_id);
+CREATE INDEX idx_alf_node_ver ON alf_node (version);
+CREATE INDEX idx_alf_node_txn ON alf_node (transaction_id);
CREATE INDEX fk_alf_store_root ON alf_store (root_node_id);
ALTER TABLE alf_store ADD CONSTRAINT fk_alf_store_root FOREIGN KEY (root_node_id) REFERENCES alf_node (id);
diff --git a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/Schema-Reference-ALF.xml b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/Schema-Reference-ALF.xml
index b4fc5abffd..312c35c6d5 100644
--- a/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/Schema-Reference-ALF.xml
+++ b/repository/src/main/resources/alfresco/dbscripts/create/org.alfresco.repo.domain.dialect.PostgreSQLDialect/Schema-Reference-ALF.xml
@@ -1739,6 +1739,16 @@
id
+
+
+ version
+
+
+
+
+ transaction_id
+
+
@@ -2703,6 +2713,17 @@
id
+
+
+ commit_time_ms
+
+
+
+
+ id
+ commit_time_ms
+
+
diff --git a/repository/src/main/resources/alfresco/dbscripts/db-schema-context.xml b/repository/src/main/resources/alfresco/dbscripts/db-schema-context.xml
index c8ef744642..786ff0e5d0 100644
--- a/repository/src/main/resources/alfresco/dbscripts/db-schema-context.xml
+++ b/repository/src/main/resources/alfresco/dbscripts/db-schema-context.xml
@@ -55,6 +55,7 @@
+
diff --git a/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/add-indexes-node-transaction.sql b/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/add-indexes-node-transaction.sql
new file mode 100644
index 0000000000..9040ee0d81
--- /dev/null
+++ b/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.MySQLInnoDBDialect/add-indexes-node-transaction.sql
@@ -0,0 +1,35 @@
+--
+-- Title: Update alf_node and alf_transaction indexes for more performance
+-- Database: MySQL
+-- Since: V6.3
+-- Author: Eva Vasques
+--
+-- Please contact support@alfresco.com if you need assistance with the upgrade.
+--
+
+DROP INDEX idx_alf_node_ver; --(optional)
+CREATE INDEX idx_alf_node_ver ON alf_node (version);
+
+DROP INDEX idx_alf_node_txn; --(optional)
+CREATE INDEX idx_alf_node_txn ON alf_node (transaction_id);
+
+DROP INDEX idx_alf_txn_ctms; --(optional)
+CREATE INDEX idx_alf_txn_ctms ON alf_transaction (commit_time_ms, id);
+
+DROP INDEX idx_alf_txn_ctms_sc; --(optional)
+CREATE INDEX idx_alf_txn_ctms_sc ON alf_transaction (commit_time_ms);
+
+DROP INDEX idx_alf_txn_id_ctms; --(optional)
+CREATE INDEX idx_alf_txn_id_ctms ON alf_transaction (id, commit_time_ms);
+
+--
+-- Record script finish
+--
+DELETE FROM alf_applied_patch WHERE id = 'patch.db-V6.3-add-indexes-node-transaction';
+INSERT INTO alf_applied_patch
+ (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
+ VALUES
+ (
+ 'patch.db-V6.3-add-indexes-node-transaction', 'Create aditional indexes on alf_node and alf_transaction',
+ 0, 14001, -1, 14002, null, 'UNKNOWN', ${TRUE}, ${TRUE}, 'Script completed'
+ );
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.PostgreSQLDialect/add-indexes-node-transaction.sql b/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.PostgreSQLDialect/add-indexes-node-transaction.sql
new file mode 100644
index 0000000000..10fba2d958
--- /dev/null
+++ b/repository/src/main/resources/alfresco/dbscripts/upgrade/6.3/org.alfresco.repo.domain.dialect.PostgreSQLDialect/add-indexes-node-transaction.sql
@@ -0,0 +1,32 @@
+--
+-- Title: Update alf_node and alf_transaction indexes for more performance
+-- Database: PostgreSQL
+-- Since: V6.3
+-- Author: Eva Vasques
+--
+-- Please contact support@alfresco.com if you need assistance with the upgrade.
+--
+
+DROP INDEX idx_alf_node_ver; --(optional)
+CREATE INDEX idx_alf_node_ver ON alf_node (version);
+
+DROP INDEX idx_alf_node_txn; --(optional)
+CREATE INDEX idx_alf_node_txn ON alf_node (transaction_id);
+
+DROP INDEX idx_alf_txn_ctms_sc; --(optional)
+CREATE INDEX idx_alf_txn_ctms_sc ON alf_transaction (commit_time_ms);
+
+DROP INDEX idx_alf_txn_id_ctms; --(optional)
+CREATE INDEX idx_alf_txn_id_ctms ON alf_transaction (id, commit_time_ms);
+
+--
+-- Record script finish
+--
+DELETE FROM alf_applied_patch WHERE id = 'patch.db-V6.3-add-indexes-node-transaction';
+INSERT INTO alf_applied_patch
+ (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
+ VALUES
+ (
+ 'patch.db-V6.3-add-indexes-node-transaction', 'Create aditional indexes on alf_node and alf_transaction',
+ 0, 14001, -1, 14002, null, 'UNKNOWN', ${TRUE}, ${TRUE}, 'Script completed'
+ );
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/messages/patch-service.properties b/repository/src/main/resources/alfresco/messages/patch-service.properties
index 4b90cc7e23..915718a744 100644
--- a/repository/src/main/resources/alfresco/messages/patch-service.properties
+++ b/repository/src/main/resources/alfresco/messages/patch-service.properties
@@ -402,4 +402,6 @@ patch.db-V5.2-remove-jbpm-tables-from-db.description=Removes all JBPM related ta
patch.db-V6.0-change-set-indexes.description=Add additional indexes to support acl tracking.
-patch.db-V6.3-remove-alf_server-table.description=Remove alf_server table.
\ No newline at end of file
+patch.db-V6.3-remove-alf_server-table.description=Remove alf_server table.
+
+patch.db-V6.3-add-indexes-node-transaction.description=Create additional indexes on alf_node and alf_transaction
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/patch/patch-services-context.xml b/repository/src/main/resources/alfresco/patch/patch-services-context.xml
index 797813a1a4..6bc9a5a6a4 100644
--- a/repository/src/main/resources/alfresco/patch/patch-services-context.xml
+++ b/repository/src/main/resources/alfresco/patch/patch-services-context.xml
@@ -1408,4 +1408,16 @@
classpath:alfresco/dbscripts/upgrade/6.3/${db.script.dialect}/remove-alf_server-table.sql
+
+
+ patch.db-V6.3-add-indexes-node-transaction
+ patch.db-V6.3-add-indexes-node-transaction.description
+ 0
+ 14001
+ 14002
+ ${system.new-node-transaction-indexes.ignored}
+
+ classpath:alfresco/dbscripts/upgrade/6.3/${db.script.dialect}/add-indexes-node-transaction.sql
+
+
diff --git a/repository/src/main/resources/alfresco/repository.properties b/repository/src/main/resources/alfresco/repository.properties
index 773f76d83b..dc06cb26f6 100644
--- a/repository/src/main/resources/alfresco/repository.properties
+++ b/repository/src/main/resources/alfresco/repository.properties
@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
-version.schema=14001
+version.schema=14002
# Directory configuration
@@ -1332,4 +1332,7 @@ system.prop_table_cleaner.algorithm=V2
# Configure the expiration time of the direct access url. This is the length of time in seconds that the link is valid for.
# Note: It is up to the actual ContentStore implementation if it can fulfil this request or not.
-alfresco.content.directAccessUrl.lifetimeInSec=300
\ No newline at end of file
+alfresco.content.directAccessUrl.lifetimeInSec=300
+
+# Creates additional indexes on alf_node and alf_transaction. Recommended for large repositories.
+system.new-node-transaction-indexes.ignored=true
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/subsystems/Search/solr4/solr-search-context.xml b/repository/src/main/resources/alfresco/subsystems/Search/solr4/solr-search-context.xml
index c111fb94ac..52f5a18f82 100644
--- a/repository/src/main/resources/alfresco/subsystems/Search/solr4/solr-search-context.xml
+++ b/repository/src/main/resources/alfresco/subsystems/Search/solr4/solr-search-context.xml
@@ -153,18 +153,15 @@
-
-
-
-
-
-
-
+
+
+
+
diff --git a/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java b/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
index 16b787afb2..70566e8d0f 100644
--- a/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
+++ b/repository/src/test/java/org/alfresco/repo/domain/permissions/FixedAclUpdaterTest.java
@@ -25,7 +25,10 @@
*/
package org.alfresco.repo.domain.permissions;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
@@ -41,6 +44,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
@@ -69,6 +73,7 @@ public class FixedAclUpdaterTest extends TestCase
private Repository repository;
private FixedAclUpdater fixedAclUpdater;
private NodeRef folderAsyncCallNodeRef;
+ private NodeRef folderAsyncCallWithCreateNodeRef;
private NodeRef folderSyncCallNodeRef;
private PermissionsDaoComponent permissionsDaoComponent;
private PermissionService permissionService;
@@ -100,6 +105,10 @@ public class FixedAclUpdaterTest extends TestCase
filesPerLevel);
folderSyncCallNodeRef = txnHelper.doInTransaction(cb2);
+ RetryingTransactionCallback cb3 = createFolderHierchyCallback(home, fileFolderService,
+ "rootFolderAsyncWithCreateCall", filesPerLevel);
+ folderAsyncCallWithCreateNodeRef = txnHelper.doInTransaction(cb3);
+
// change setFixedAclMaxTransactionTime to lower value so setInheritParentPermissions on created folder
// hierarchy require async call
setFixedAclMaxTransactionTime(permissionsDaoComponent, home, 50);
@@ -147,8 +156,10 @@ public class FixedAclUpdaterTest extends TestCase
aspect.add(ContentModel.ASPECT_TEMPORARY);
nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderAsyncCallNodeRef).getFirst(), aspect);
nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderSyncCallNodeRef).getFirst(), aspect);
+ nodeDAO.addNodeAspects(nodeDAO.getNodePair(folderAsyncCallWithCreateNodeRef).getFirst(), aspect);
fileFolderService.delete(folderAsyncCallNodeRef);
fileFolderService.delete(folderSyncCallNodeRef);
+ fileFolderService.delete(folderAsyncCallWithCreateNodeRef);
return null;
}, false, true);
}
@@ -189,7 +200,34 @@ public class FixedAclUpdaterTest extends TestCase
testWork(folderAsyncCallNodeRef, true);
}
+ @Test
+ public void testAsyncWithNodeCreation()
+ {
+ testWorkWithNodeCreation(folderAsyncCallWithCreateNodeRef, true);
+ }
+
private void testWork(NodeRef folderRef, boolean asyncCall)
+ {
+ setPermissionsOnTree(folderRef, asyncCall);
+ triggerFixedACLJob(folderRef);
+ }
+
+ private void testWorkWithNodeCreation(NodeRef folderRef, boolean asyncCall)
+ {
+ setPermissionsOnTree(folderRef, asyncCall);
+
+ // MNT-21847 - Create a new content in folder that has the aspect applied
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ NodeRef folderWithPendingAcl = getFirstFolderWithAclPending(folderRef);
+ assertNotNull("No children folders were found with pendingFixACl aspect", folderWithPendingAcl);
+ createFile(fileFolderService, folderWithPendingAcl, "NewFile", ContentModel.TYPE_CONTENT);
+ return null;
+ }, false, true);
+
+ triggerFixedACLJob(folderRef);
+ }
+
+ private void setPermissionsOnTree(NodeRef folderRef, boolean asyncCall)
{
// kick it off by setting inherit parent permissions == false
txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
@@ -203,21 +241,61 @@ public class FixedAclUpdaterTest extends TestCase
assertTrue("There are no nodes to process", getNodesCountWithPendingFixedAclAspect() > 0);
return null;
}, false, true);
+ }
- // run the fixedAclUpdater until there is nothing more to fix (running the updater
- // may create more to fix up)
+ private void triggerFixedACLJob(NodeRef folder)
+ {
+ // run the fixedAclUpdater until there is nothing more to fix (running the updater may create more to fix up) or
+ // the count doesn't change, meaning we have a problem.
txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
int count = 0;
+ int previousCount = 0;
do
{
+ previousCount = count;
count = fixedAclUpdater.execute();
- } while (count > 0);
+ } while (count > 0 && previousCount != count);
return null;
}, false, true);
// check if nodes with ASPECT_PENDING_FIX_ACL are processed
txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
assertEquals("Not all nodes were processed", 0, getNodesCountWithPendingFixedAclAspect());
+ //Remove the tree that failed so it does not influence the other test results
+ removeNodesWithPendingAcl(folder);
+ return null;
+ }, false, true);
+ }
+
+ private NodeRef getFirstFolderWithAclPending(NodeRef parentNodeRef)
+ {
+ NodeRef folderWithPendingFixedAcl = null;
+ List primaryChildFolders = fileFolderService.listFolders(parentNodeRef);
+ for (int i = 0; i < primaryChildFolders.size(); i++)
+ {
+ NodeRef thisChildFolder = primaryChildFolders.get(i).getNodeRef();
+ Long thisChildNodeId = nodeDAO.getNodePair(thisChildFolder).getFirst();
+ if (nodeDAO.hasNodeAspect(thisChildNodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
+ {
+ folderWithPendingFixedAcl = thisChildFolder;
+ break;
+ }
+
+ if (folderWithPendingFixedAcl == null)
+ {
+ folderWithPendingFixedAcl = getFirstFolderWithAclPending(thisChildFolder);
+ }
+ }
+ return folderWithPendingFixedAcl;
+ }
+
+ private void removeNodesWithPendingAcl(NodeRef folder)
+ {
+ txnHelper.doInTransaction((RetryingTransactionCallback) () -> {
+ Set aspect = new HashSet<>();
+ aspect.add(ContentModel.ASPECT_TEMPORARY);
+ nodeDAO.addNodeAspects(nodeDAO.getNodePair(folder).getFirst(), aspect);
+ fileFolderService.delete(folder);
return null;
}, false, true);
}
diff --git a/repository/src/test/java/org/alfresco/repo/solr/SOLRTrackingComponentUnitTest.java b/repository/src/test/java/org/alfresco/repo/solr/SOLRTrackingComponentUnitTest.java
new file mode 100644
index 0000000000..316f5398f0
--- /dev/null
+++ b/repository/src/test/java/org/alfresco/repo/solr/SOLRTrackingComponentUnitTest.java
@@ -0,0 +1,115 @@
+/*
+ * #%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 .
+ * #L%
+ */
+package org.alfresco.repo.solr;
+
+import static java.util.Collections.emptyMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.alfresco.repo.domain.node.NodeDAO;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.QName;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+/** Unit tests for {@link org.alfresco.repo.solr.SOLRTrackingComponent}. */
+public class SOLRTrackingComponentUnitTest
+{
+ /** A pair of QNames for use in the tests. */
+ private static final QName FIRST_PROPERTY = QName.createQName("the://first/property");
+ private static final QName SECOND_PROPERTY = QName.createQName("the://second/property");
+ /** A node id for use in the tests. */
+ private static final long NODE_ID = 123L;
+
+ /** The class under test. */
+ @InjectMocks
+ private SOLRTrackingComponentImpl solrTrackingComponent;
+ @Mock
+ private NodeDAO nodeDAO;
+ @Mock
+ private DictionaryService dictionaryService;
+
+ @Before
+ public void setUp()
+ {
+ initMocks(this);
+ }
+
+ /** Check that properties of different types can be returned. */
+ @Test
+ public void testGetProperties_indexedPropertiesPassedThrough()
+ {
+ Map propertiesFromDB = Map.of(FIRST_PROPERTY, "value1", SECOND_PROPERTY, 2);
+ when(nodeDAO.getNodeProperties(NODE_ID)).thenReturn(propertiesFromDB);
+ PropertyDefinition firstDefinition = mock(PropertyDefinition.class);
+ when(firstDefinition.isIndexed()).thenReturn(true);
+ when(dictionaryService.getProperty(FIRST_PROPERTY)).thenReturn(firstDefinition);
+ PropertyDefinition secondDefinition = mock(PropertyDefinition.class);
+ when(secondDefinition.isIndexed()).thenReturn(true);
+ when(dictionaryService.getProperty(SECOND_PROPERTY)).thenReturn(secondDefinition);
+
+ Map properties = solrTrackingComponent.getProperties(NODE_ID);
+
+ assertEquals("Expected both properties to be returned.", propertiesFromDB, properties);
+ }
+
+ /** Check that a property is not indexed if it is not registered in the dictionary service. */
+ @Test
+ public void testGetProperties_propertyWithoutModelIsNotIndexed()
+ {
+ Map propertiesFromDB = Map.of(FIRST_PROPERTY, "value1");
+ when(nodeDAO.getNodeProperties(NODE_ID)).thenReturn(propertiesFromDB);
+ when(dictionaryService.getProperty(FIRST_PROPERTY)).thenReturn(null);
+
+ Map properties = solrTrackingComponent.getProperties(NODE_ID);
+
+ assertEquals("Expected residual property to be skipped.", emptyMap(), properties);
+ }
+
+ /** Check that a property is not indexed if the model contains */
+ @Test
+ public void testGetProperties_propertySkippedIfIndexFalseSet()
+ {
+ Map propertiesFromDB = Map.of(FIRST_PROPERTY, "value1");
+ when(nodeDAO.getNodeProperties(NODE_ID)).thenReturn(propertiesFromDB);
+ PropertyDefinition firstDefinition = mock(PropertyDefinition.class);
+ when(firstDefinition.isIndexed()).thenReturn(false);
+ when(dictionaryService.getProperty(FIRST_PROPERTY)).thenReturn(firstDefinition);
+
+ Map properties = solrTrackingComponent.getProperties(NODE_ID);
+
+ assertEquals("Unexpected property when index enabled set to false.", emptyMap(), properties);
+ }
+}