diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index c1660ca394..0dc044d49e 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -33,6 +33,9 @@ ${system.maximumStringLength} + + ${system.hibernateMaxExecutions} + ${db.schema.update} diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index a8525fc01a..21bcaf7d78 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -23,16 +23,31 @@ + + + + + false + + + + + + + + + + @@ -289,13 +304,19 @@ + + + + + + - + - - - - + + + + @@ -360,10 +381,17 @@ + + + + + + + \ No newline at end of file diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 7ea4a682ee..4030e94773 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -2,6 +2,7 @@ patch.service.not_relevant=Not relevant to schema {0} patch.executer.checking=Checking for patches to apply ... patch.service.applying_patch=\tApplying patch ''{0}'' ({1}). +patch.progress=\t\tPatch {0}% complete, estimated complete at {1}. patch.executer.no_patches_required=No patches were required. patch.executer.system_readonly=Patches cannot be applied to a read-only system. Possible incompatibilities may exist between the application code and the existing data. patch.executer.not_executed =\n=== Recorded patch (not executed) === \nID: {0}\nRESULT: \n{1}\n===================================== diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 352ba2f5d0..2d5c559160 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1268,6 +1268,9 @@ + + + @@ -1380,6 +1383,9 @@ + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index be8003abf5..48de829525 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -74,6 +74,13 @@ system.acl.maxPermissionChecks=1000 # org.alfresco.repo.domain.schema.SchemaBootstrap for V2.1.2 system.maximumStringLength=-1 +# +# Limit hibernate session size by trying to amalgamate events for the L2 session invalidation +# - hibernate works as is up to this size +# - after the limit is hit events that can be grouped invalidate the L2 cache by type and not instance +# events may not group if there are post action listener registered (this is not the case with the default distribution) +system.hibernateMaxExecutions=20000 + # #################### # # Lucene configuration # # #################### # diff --git a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java index ffc4e270e6..efdf342668 100644 --- a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java @@ -27,9 +27,11 @@ package org.alfresco.repo.admin.patch; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; +import java.util.Date; import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -46,8 +48,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Base implementation of the patch. This class ensures that the patch is - * thread- and transaction-safe. + * Base implementation of the patch. This class ensures that the patch is thread- and transaction-safe. * * @author Derek Hulley */ @@ -56,14 +57,20 @@ public abstract class AbstractPatch implements Patch /** * I18N message when properties not set. *
    - *
  • {0} = property name
  • - *
  • {1} = patch instance
  • + *
  • {0} = property name
  • + *
  • {1} = patch instance
  • *
*/ public static final String ERR_PROPERTY_NOT_SET = "patch.general.property_not_set"; - + private static final String MSG_PROGRESS = "patch.progress"; + + private static final long RANGE_10 = 1000 * 60 * 90; + private static final long RANGE_5 = 1000 * 60 * 60 * 4; + private static final long RANGE_2 = 1000 * 60 * 90 * 10; + private static Log logger = LogFactory.getLog(AbstractPatch.class); - + private static Log progress_logger = LogFactory.getLog(PatchExecuter.class); + private String id; private int fixesFromSchema; private int fixesToSchema; @@ -73,7 +80,8 @@ public abstract class AbstractPatch implements Patch private List dependsOn; /** flag indicating if the patch was successfully applied */ private boolean applied; - private boolean applyToTenants = true; // by default, apply to each tenant, if tenant service is enabled + private boolean applyToTenants; + /** the service to register ourselves with */ private PatchService patchService; /** used to ensure a unique transaction per execution */ @@ -90,15 +98,22 @@ public abstract class AbstractPatch implements Patch protected TenantDeployerService tenantDeployerService; + /** track completion * */ + int percentComplete = 0; + + /** start time * */ + long startTime; + public AbstractPatch() { this.fixesFromSchema = -1; this.fixesToSchema = -1; this.targetSchema = -1; this.applied = false; + this.applyToTenants = true; // by default, apply to each tenant, if tenant service is enabled this.dependsOn = Collections.emptyList(); } - + @Override public String toString() { @@ -136,7 +151,7 @@ public abstract class AbstractPatch implements Patch { this.namespaceService = namespaceService; } - + /** * Set a generally-used service */ @@ -167,7 +182,7 @@ public abstract class AbstractPatch implements Patch } /** - * This ensures that this bean gets registered with the appropriate {@link PatchService service}. + * This ensures that this bean gets registered with the appropriate {@link PatchService service}. */ public void init() { @@ -184,8 +199,8 @@ public abstract class AbstractPatch implements Patch } /** - * - * @param id the unique ID of the patch. This dictates the order in which patches are applied. + * @param id + * the unique ID of the patch. This dictates the order in which patches are applied. */ public void setId(String id) { @@ -200,7 +215,8 @@ public abstract class AbstractPatch implements Patch /** * Set the smallest schema number that this patch may be applied to. * - * @param version a schema number not smaller than 0 + * @param version + * a schema number not smaller than 0 */ public void setFixesFromSchema(int version) { @@ -224,8 +240,8 @@ public abstract class AbstractPatch implements Patch /** * Set the largest schema version number that this patch may be applied to. * - * @param version a schema version number not smaller than the - * {@link #setFixesFromSchema(int) from version} number. + * @param version + * a schema version number not smaller than the {@link #setFixesFromSchema(int) from version} number. */ public void setFixesToSchema(int version) { @@ -242,12 +258,11 @@ public abstract class AbstractPatch implements Patch } /** - * Set the schema version that this patch attempts to take the existing schema to. - * This is for informational purposes only, acting as an indicator of intention rather - * than having any specific effect. + * Set the schema version that this patch attempts to take the existing schema to. This is for informational + * purposes only, acting as an indicator of intention rather than having any specific effect. * - * @param version a schema version number that must be greater than the - * {@link #fixesToSchema max fix schema number} + * @param version + * a schema version number that must be greater than the {@link #fixesToSchema max fix schema number} */ public void setTargetSchema(int version) { @@ -264,7 +279,8 @@ public abstract class AbstractPatch implements Patch } /** - * @param description a thorough description of the patch + * @param description + * a thorough description of the patch */ public void setDescription(String description) { @@ -275,12 +291,12 @@ public abstract class AbstractPatch implements Patch { return this.dependsOn; } - + /** - * Set all the dependencies for this patch. It should not be executed - * before all the dependencies have been applied. + * Set all the dependencies for this patch. It should not be executed before all the dependencies have been applied. * - * @param dependsOn a list of dependencies + * @param dependsOn + * a list of dependencies */ public void setDependsOn(List dependsOn) { @@ -291,12 +307,14 @@ public abstract class AbstractPatch implements Patch { return ((this.fixesFromSchema <= version) && (version <= fixesToSchema)); } - + /** * Performs a null check on the supplied value. * - * @param value value to check - * @param name name of the property to report + * @param value + * value to check + * @param name + * name of the property to report */ protected final void checkPropertyNotNull(Object value, String name) { @@ -312,9 +330,8 @@ public abstract class AbstractPatch implements Patch } /** - * Check that the schema version properties have been set appropriately. - * Derived classes can override this method to perform their own validation provided - * that this method is called by the derived class. + * Check that the schema version properties have been set appropriately. Derived classes can override this method to + * perform their own validation provided that this method is called by the derived class. */ protected void checkProperties() { @@ -328,12 +345,11 @@ public abstract class AbstractPatch implements Patch checkPropertyNotNull(authenticationComponent, "authenticationComponent"); if (fixesFromSchema == -1 || fixesToSchema == -1 || targetSchema == -1) { - throw new AlfrescoRuntimeException( - "Patch properties 'fixesFromSchema', 'fixesToSchema' and 'targetSchema' have not all been set on this patch: \n" + - " patch: " + this); + throw new AlfrescoRuntimeException("Patch properties 'fixesFromSchema', 'fixesToSchema' and 'targetSchema' have not all been set on this patch: \n" + + " patch: " + this); } } - + /** * Sets up the transaction and ensures thread-safety. * @@ -344,8 +360,7 @@ public abstract class AbstractPatch implements Patch // ensure that this has not been executed already if (applied) { - throw new AlfrescoRuntimeException("The patch has already been executed: \n" + - " patch: " + this); + throw new AlfrescoRuntimeException("The patch has already been executed: \n" + " patch: " + this); } // check properties checkProperties(); @@ -354,9 +369,7 @@ public abstract class AbstractPatch implements Patch { if (logger.isDebugEnabled()) { - logger.debug("\n" + - "Patch will be applied: \n" + - " patch: " + this); + logger.debug("\n" + "Patch will be applied: \n" + " patch: " + this); } AuthenticationUtil.RunAsWork authorisedPathWork = new AuthenticationUtil.RunAsWork() { @@ -399,16 +412,14 @@ public abstract class AbstractPatch implements Patch return transactionService.getRetryingTransactionHelper().doInTransaction(patchWork); } }; + startTime = System.currentTimeMillis(); String report = AuthenticationUtil.runAs(authorisedPathWork, AuthenticationUtil.getSystemUserName()); // the patch was successfully applied applied = true; // done if (logger.isDebugEnabled()) { - logger.debug("\n" + - "Patch successfully applied: \n" + - " patch: " + this + "\n" + - " report: " + report); + logger.debug("\n" + "Patch successfully applied: \n" + " patch: " + this + "\n" + " report: " + report); } return report; } @@ -431,11 +442,12 @@ public abstract class AbstractPatch implements Patch throw new PatchException(report); } } - + /** * Dumps the error's full message and trace to the String * - * @param e the throwable + * @param e + * the throwable * @return Returns a String representative of the printStackTrace method */ private String makeReport(Throwable e) @@ -454,13 +466,91 @@ public abstract class AbstractPatch implements Patch } /** - * This method does the work. All transactions and thread-safety will be taken care of by this class. - * Any exception will result in the transaction being rolled back. Integrity checks are downgraded - * for the duration of the transaction. + * This method does the work. All transactions and thread-safety will be taken care of by this class. Any exception + * will result in the transaction being rolled back. Integrity checks are downgraded for the duration of the + * transaction. * * @return Returns the report (only success messages). * @see #apply() - * @throws Exception anything can be thrown. This must be used for all failures. + * @throws Exception + * anything can be thrown. This must be used for all failures. */ protected abstract String applyInternal() throws Exception; + + /** + * Support to report patch completion and estimated completion time. + * + * @param estimatedTotal + * @param currentInteration + */ + protected void reportProgress(long estimatedTotal, long currentInteration) + { + if (progress_logger.isDebugEnabled()) + { + progress_logger.debug(currentInteration + "/" + estimatedTotal); + } + if (currentInteration == 0) + { + // No point reporting the start - we have already done that elsewhere .... + percentComplete = 0; + } + else if (currentInteration * 100l / estimatedTotal > percentComplete) + { + int previous = percentComplete; + percentComplete = (int) (currentInteration * 100l / estimatedTotal); + + if (percentComplete < 100) + { + // conditional report + + long currentTime = System.currentTimeMillis(); + long timeSoFar = currentTime - startTime; + long timeRemaining = timeSoFar * (100 - percentComplete) / percentComplete; + + int report = -1; + + if (timeRemaining > 60000) + { + int reportInterval = getreportingInterval(timeSoFar, timeRemaining); + + for (int i = previous + 1; i <= percentComplete; i++) + { + if (i % reportInterval == 0) + { + report = i; + } + } + if (report > 0) + { + Date end = new Date(currentTime + timeRemaining); + + String msg = I18NUtil.getMessage(MSG_PROGRESS, report, end); + progress_logger.info(msg); + } + } + } + } + } + + private int getreportingInterval(long soFar, long toGo) + { + long total = soFar + toGo; + if (total < RANGE_10) + { + return 10; + } + else if (total < RANGE_5) + { + return 5; + } + else if (total < RANGE_2) + { + return 2; + } + else + { + return 1; + } + + } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java index 5356ba7ec3..c73607b694 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java @@ -29,7 +29,10 @@ import java.util.Map; import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl; import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; /** * Migrate permissions from the OLD format to defining, shared and layered @@ -40,12 +43,23 @@ public class AVMPermissionsPatch extends AbstractPatch private static final String MSG_SUCCESS = "patch.updateAvmPermissions.result"; private AccessControlListDAO accessControlListDao; + + private AclDaoComponentImpl aclDaoComponent; @Override protected String applyInternal() throws Exception { + Long toDo = aclDaoComponent.getAVMHeadNodeCount(); + Long maxId = aclDaoComponent.getMaxAclId(); + + Thread progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher"); + progressThread.start(); + Map summary = accessControlListDao.patchAcls(); + progressThread.interrupt(); + progressThread.join(); + // build the result message String msg = I18NUtil.getMessage(MSG_SUCCESS, summary.get(ACLType.DEFINING), summary.get(ACLType.LAYERED)); // done @@ -57,4 +71,57 @@ public class AVMPermissionsPatch extends AbstractPatch this.accessControlListDao = accessControlListDao; } + public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + + + private class ProgressWatcher implements Runnable + { + private boolean running = true; + + Long toDo; + + Long max; + + ProgressWatcher(Long toDo, Long max) + { + this.toDo = toDo; + this.max = max; + } + + public void run() + { + while (running) + { + try + { + Thread.sleep(60000); + } + catch (InterruptedException e) + { + running = false; + } + + if (running) + { + RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper(); + txHelper.setMaxRetries(1); + Long done = txHelper.doInTransaction(new RetryingTransactionCallback() + { + + public Long execute() throws Throwable + { + return aclDaoComponent.getAVMNodeCountWithNewACLS(max); + } + }, true, true); + + reportProgress(toDo, done); + } + } + } + + } + } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java index 03e8f08b10..1867892d05 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java @@ -32,7 +32,10 @@ import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.AVMRepository; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; @@ -43,6 +46,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.service.transaction.TransactionService; /** * Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set @@ -60,6 +64,8 @@ public class WCMPermissionPatch extends AbstractPatch PermissionService permissionService; + AclDaoComponentImpl aclDaoComponent; + public void setAvmService(AVMService avmService) { this.avmService = avmService; @@ -75,9 +81,20 @@ public class WCMPermissionPatch extends AbstractPatch this.permissionService = permissionService; } + public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + @Override protected String applyInternal() throws Exception { + Long toDo = aclDaoComponent.getAVMHeadNodeCount(); + Long maxId = aclDaoComponent.getMaxAclId(); + + Thread progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher"); + progressThread.start(); + List stores = avmService.getStores(); for (AVMStoreDescriptor store : stores) { @@ -113,6 +130,9 @@ public class WCMPermissionPatch extends AbstractPatch } } + progressThread.interrupt(); + progressThread.join(); + // build the result message String msg = I18NUtil.getMessage(MSG_SUCCESS); // done @@ -178,7 +198,7 @@ public class WCMPermissionPatch extends AbstractPatch PropertyValue pValue = avmService.getStoreProperty(stagingAreaName, propQName); permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); - + if (pValue != null) { NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF); @@ -213,7 +233,7 @@ public class WCMPermissionPatch extends AbstractPatch int end = name.indexOf("--", start + 1); if (end == -1) { - return name.substring(start+2); + return name.substring(start + 2); } return name.substring(start + 2, end); } @@ -228,4 +248,50 @@ public class WCMPermissionPatch extends AbstractPatch return name.substring(0, index); } + private class ProgressWatcher implements Runnable + { + private boolean running = true; + + Long toDo; + + Long max; + + ProgressWatcher(Long toDo, Long max) + { + this.toDo = toDo; + this.max = max; + } + + public void run() + { + while (running) + { + try + { + Thread.sleep(60000); + } + catch (InterruptedException e) + { + running = false; + } + + if (running) + { + RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper(); + txHelper.setMaxRetries(1); + Long done = txHelper.doInTransaction(new RetryingTransactionCallback() + { + + public Long execute() throws Throwable + { + return aclDaoComponent.getAVMNodeCountWithNewACLS(max); + } + }, true, true); + + reportProgress(toDo, done); + } + } + } + + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java index b41bd9fa3d..d2fe13f908 100644 --- a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java @@ -404,7 +404,7 @@ public class AVMServicePermissionsTest extends TestCase runAs(curentUser); } } - + public void testStoreAcls() throws Exception { runAs("admin"); @@ -416,74 +416,73 @@ public class AVMServicePermissionsTest extends TestCase AVMNodeDescriptor nodeDesc = avmService.lookup(-1, storeName + ":/base"); NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, nodeDesc.getPath()); permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - - permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS, true); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - - permissionService.deletePermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - - permissionService.deletePermissions(nodeRef.getStoreRef()); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS, true); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.deletePermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.deletePermissions(nodeRef.getStoreRef()); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS, true); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.READ, true); permissionService.setPermission(nodeRef.getStoreRef(), "lemur", PermissionService.ALL_PERMISSIONS, true); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); assertEquals(permissionService.getAllSetPermissions(nodeRef.getStoreRef()).size(), 3); - + permissionService.clearPermission(nodeRef.getStoreRef(), "andy"); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); assertEquals(permissionService.getAllSetPermissions(nodeRef.getStoreRef()).size(), 1); - + permissionService.clearPermission(nodeRef.getStoreRef(), "lemur"); - - assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); - assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); - assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); - + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + } finally { @@ -495,11 +494,13 @@ public class AVMServicePermissionsTest extends TestCase avmService.purgeStore(storeName + "-layer-d"); avmService.purgeStore(storeName + "-layer-layer-base"); avmService.purgeStore(storeName + "-layer-layer-layer-base"); + + System.out.println(avmService.getStores()); } } - public void testSimpleUpdate() throws Exception + public void testSimpleUpdate() throws Throwable { runAs("admin"); String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); @@ -556,6 +557,11 @@ public class AVMServicePermissionsTest extends TestCase fileAcl = node.getAcl(); assertNull(fileAcl); } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } finally { avmService.purgeStore(storeName); diff --git a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java index d89dad4d1f..b3cf84fc35 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java @@ -34,6 +34,8 @@ import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.AVMRepository; import org.alfresco.repo.domain.AccessControlListDAO; import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl.Indirection; +import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.ACLType; @@ -69,6 +71,10 @@ public class AVMAccessControlListDAO implements AccessControlListDAO private AclDaoComponent aclDaoComponent; + private AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor; + + private HibernateSessionHelper hibernateSessionHelper; + /** * Default constructory. */ @@ -91,6 +97,16 @@ public class AVMAccessControlListDAO implements AccessControlListDAO this.aclDaoComponent = aclDaoComponent; } + public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor) + { + this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor; + } + + public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper) + { + this.hibernateSessionHelper = hibernateSessionHelper; + } + public Long getIndirectAcl(NodeRef nodeRef) { Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); @@ -233,37 +249,46 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { inherited = aclDaoComponent.getInheritedAccessControlList(after); } - updateChangedAclsImpl(startingPoint, changes, SetMode.ALL, inherited, after); + Map> indirections = buildIndirections(); + updateChangedAclsImpl(startingPoint, changes, SetMode.ALL, inherited, after, indirections); } - private void updateChangedAclsImpl(NodeRef startingPoint, List changes, SetMode mode, Long inherited, Long setAcl) + private void updateChangedAclsImpl(NodeRef startingPoint, List changes, SetMode mode, Long inherited, Long setAcl, Map> indirections) { - HashMap changeMap = new HashMap(); - HashSet unchangedSet = new HashSet(); - for (AclChange change : changes) + hibernateSessionHelper.mark(); + try { - if (change.getBefore() == null) + HashMap changeMap = new HashMap(); + HashSet unchangedSet = new HashSet(); + for (AclChange change : changes) { - // null is treated using the inherited acl + if (change.getBefore() == null) + { + // null is treated using the inherited acl + } + else if (!change.getBefore().equals(change.getAfter())) + { + changeMap.put(change.getBefore(), change.getAfter()); + } + else + { + unchangedSet.add(change.getBefore()); + } } - else if (!change.getBefore().equals(change.getAfter())) - { - changeMap.put(change.getBefore(), change.getAfter()); - } - else - { - unchangedSet.add(change.getBefore()); - } - } - unchangedSet.add(inherited); - unchangedSet.add(setAcl); + unchangedSet.add(inherited); + unchangedSet.add(setAcl); - if (inherited != null) - { - updateReferencingLayeredAcls(startingPoint, inherited); + if (inherited != null) + { + updateReferencingLayeredAcls(startingPoint, inherited, indirections); + } + updateInheritedChangedAcls(startingPoint, changeMap, unchangedSet, inherited, mode, indirections); + updateLayeredAclsChangedByInheritance(changes, changeMap, unchangedSet, indirections); + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); } - updateInheritedChangedAcls(startingPoint, changeMap, unchangedSet, inherited, mode); - updateLayeredAclsChangedByInheritance(changes, changeMap, unchangedSet); } public void forceCopy(NodeRef nodeRef) @@ -283,10 +308,33 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { throw new InvalidNodeRefException(nodeRef); } - } - private void updateReferencingLayeredAcls(NodeRef node, Long inherited) + private Map> buildIndirections() + { + Map> answer = new HashMap>(); + + List indirections = aclDaoComponent.getAvmIndirections(); + for (Indirection indirection : indirections) + { + AVMNodeDescriptor toDesc = fAVMService.lookup(indirection.getToVersion(), indirection.getTo(), true); + if (toDesc != null) + { + Long toId = Long.valueOf(toDesc.getId()); + Set referees = answer.get(toId); + if (referees == null) + { + referees = new HashSet(); + answer.put(toId, referees); + } + referees.add(indirection.getFrom()); + } + } + + return answer; + } + + private void updateReferencingLayeredAcls(NodeRef node, Long inherited, Map> indirections) { Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(node); int version = avmVersionPath.getFirst(); @@ -304,42 +352,39 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } else { - List> paths = fAVMService.getHeadPaths(descriptor); - for (Pair current : paths) + Set avmNodeIds = indirections.get(Long.valueOf(descriptor.getId())); + if (avmNodeIds != null) { - List avmNodeIds = aclDaoComponent.getAvmNodesByIndirection(current.getSecond()); for (Long id : avmNodeIds) { // need to fix up inheritance as is has changed AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, 0, null, 0, false, 0, false, 0, 0); + List> layerPaths = fAVMRepository.getHeadPaths(layerDesc); // Update all locations with the updated ACL + for (Pair layerPath : layerPaths) { - AVMNodeDescriptor test = fAVMService.lookup(-1, layerPath.getSecond()); - if (test.isPrimary()) + DbAccessControlList target = getAclAsSystem(-1, layerPath.getSecond()); + if (target != null) { - DbAccessControlList target = getAclAsSystem(-1, layerPath.getSecond()); - if (target != null) + if (target.getAclType() == ACLType.LAYERED) { - if (target.getAclType() == ACLType.LAYERED) - { - fAVMService.forceCopy(layerPath.getSecond()); + fAVMService.forceCopy(layerPath.getSecond()); - List layeredChanges = aclDaoComponent.mergeInheritedAccessControlList(inherited, target.getId()); - NodeRef layeredNode = AVMNodeConverter.ToNodeRef(-1, layerPath.getSecond()); - for (AclChange change : layeredChanges) + List layeredChanges = aclDaoComponent.mergeInheritedAccessControlList(inherited, target.getId()); + NodeRef layeredNode = AVMNodeConverter.ToNodeRef(-1, layerPath.getSecond()); + for (AclChange change : layeredChanges) + { + if (change.getBefore().equals(target.getId())) { - if (change.getBefore().equals(target.getId())) + Long newInherited = null; + if (change.getAfter() != null) { - Long newInherited = null; - if (change.getAfter() != null) - { - newInherited = aclDaoComponent.getInheritedAccessControlList(change.getAfter()); - } - updateChangedAclsImpl(layeredNode, layeredChanges, SetMode.DIRECT_ONLY, newInherited, change.getAfter()); - break; + newInherited = aclDaoComponent.getInheritedAccessControlList(change.getAfter()); } + updateChangedAclsImpl(layeredNode, layeredChanges, SetMode.DIRECT_ONLY, newInherited, change.getAfter(), indirections); + break; } } } @@ -355,7 +400,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } - private void updateLayeredAclsChangedByInheritance(List changes, HashMap changeMap, Set unchanged) + private void updateLayeredAclsChangedByInheritance(List changes, HashMap changeMap, Set unchanged, Map> indirections) { for (AclChange change : changes) { @@ -375,14 +420,16 @@ public class AVMAccessControlListDAO implements AccessControlListDAO // No need to force COW - any inherited ACL will have COWED if the top ACL required it setAclAsSystem(path.getSecond(), aclDaoComponent.getDbAccessControlList(change.getAfter())); NodeRef layeredNode = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); - updateInheritedChangedAcls(layeredNode, changeMap, unchanged, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), SetMode.DIRECT_ONLY); + updateInheritedChangedAcls(layeredNode, changeMap, unchanged, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), SetMode.DIRECT_ONLY, + indirections); } } } } } - private void updateInheritedChangedAcls(NodeRef startingPoint, HashMap changeMap, Set unchanged, Long unsetAcl, SetMode mode) + private void updateInheritedChangedAcls(NodeRef startingPoint, HashMap changeMap, Set unchanged, Long unsetAcl, SetMode mode, + Map> indirections) { // Walk children and fix up any that reference the given list .. Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(startingPoint); @@ -404,9 +451,10 @@ public class AVMAccessControlListDAO implements AccessControlListDAO if (descriptor.isLayeredDirectory()) { - setInheritanceForDirectChildren(descriptor, changeMap, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, descriptor.getPath()).getId())); + setInheritanceForDirectChildren(descriptor, changeMap, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, descriptor.getPath()).getId()), + indirections); } - fixUpAcls(descriptor, changeMap, unchanged, unsetAcl, mode); + fixUpAcls(descriptor, changeMap, unchanged, unsetAcl, mode, indirections); } } catch (AVMException e) @@ -415,9 +463,9 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } - private void fixUpAcls(AVMNodeDescriptor descriptor, Map changes, Set unchanged, Long unsetAcl, SetMode mode) + private void fixUpAcls(AVMNodeDescriptor descriptor, Map changes, Set unchanged, Long unsetAcl, SetMode mode, Map> indirections) { - DbAccessControlList acl = getAclAsSystem(-1, descriptor.getPath()); + DbAccessControlList acl = getAclAsSystem(-1, descriptor.getPath()); Long id = null; if (acl != null) { @@ -429,7 +477,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO // No need to force COW - ACL should have COWed if required setAclAsSystem(descriptor.getPath(), aclDaoComponent.getDbAccessControlList(unsetAcl)); NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()); - updateReferencingLayeredAcls(nodeRef, unsetAcl); + updateReferencingLayeredAcls(nodeRef, unsetAcl, indirections); } else if (changes.containsKey(id)) { @@ -466,16 +514,24 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } for (AVMNodeDescriptor child : children.values()) { - fixUpAcls(child, changes, unchanged, unsetAcl, mode); + hibernateSessionHelper.mark(); + try + { + fixUpAcls(child, changes, unchanged, unsetAcl, mode, indirections); + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); + } } } } - private void setInheritanceForDirectChildren(AVMNodeDescriptor descriptor, Map changeMap, Long mergeFrom) + private void setInheritanceForDirectChildren(AVMNodeDescriptor descriptor, Map changeMap, Long mergeFrom, Map> indirections) { List changes = new ArrayList(); - setFixedAcls(descriptor, mergeFrom, changes, SetMode.DIRECT_ONLY, false); + setFixedAcls(descriptor, mergeFrom, changes, SetMode.DIRECT_ONLY, false, indirections); for (AclChange change : changes) { if (!change.getBefore().equals(change.getAfter())) @@ -498,9 +554,10 @@ public class AVMAccessControlListDAO implements AccessControlListDAO String path = avmVersionPath.getSecond(); try { + Map> indirections = buildIndirections(); List changes = new ArrayList(); AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); - setFixedAcls(descriptor, mergeFrom, changes, SetMode.ALL, false); + setFixedAcls(descriptor, mergeFrom, changes, SetMode.ALL, false, indirections); return changes; } @@ -510,7 +567,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } - public void setFixedAcls(AVMNodeDescriptor descriptor, Long mergeFrom, List changes, SetMode mode, boolean set) + public void setFixedAcls(AVMNodeDescriptor descriptor, Long mergeFrom, List changes, SetMode mode, boolean set, Map> indirections) { if (descriptor == null) { @@ -527,7 +584,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO if (previous == null) { NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()); - updateReferencingLayeredAcls(nodeRef, mergeFrom); + updateReferencingLayeredAcls(nodeRef, mergeFrom, indirections); } } @@ -554,8 +611,15 @@ public class AVMAccessControlListDAO implements AccessControlListDAO if (acl == null) { - setFixedAcls(child, mergeFrom, changes, mode, true); - + hibernateSessionHelper.mark(); + try + { + setFixedAcls(child, mergeFrom, changes, mode, true, indirections); + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); + } } else if (acl.getAclType() == ACLType.LAYERED) { @@ -573,16 +637,32 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { if (change.getBefore().equals(acl.getId())) { - setAclAsSystem(child.getPath(), aclDaoComponent.getDbAccessControlList(change.getAfter())); - setFixedAcls(child, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), newChanges, SetMode.DIRECT_ONLY, false); - changes.addAll(newChanges); - break; + hibernateSessionHelper.mark(); + try + { + setAclAsSystem(child.getPath(), aclDaoComponent.getDbAccessControlList(change.getAfter())); + setFixedAcls(child, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), newChanges, SetMode.DIRECT_ONLY, false, indirections); + changes.addAll(newChanges); + break; + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); + } } } } else { - setFixedAcls(child, mergeFrom, changes, mode, true); + hibernateSessionHelper.mark(); + try + { + setFixedAcls(child, mergeFrom, changes, mode, true, indirections); + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); + } } } @@ -599,11 +679,31 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { CounterSet result = new CounterSet(); List stores = fAVMService.getStores(); + Map> indirections = buildIndirections(); for (AVMStoreDescriptor store : stores) { AVMNodeDescriptor root = fAVMService.getStoreRoot(-1, store.getName()); - CounterSet update = fixOldAvmAcls(root); - result.add(update); + CounterSet update; + switch (avmSnapShotTriggeredIndexingMethodInterceptor.getStoreType(store.getName())) + { + case AUTHOR: + case AUTHOR_PREVIEW: + case AUTHOR_WORKFLOW: + case AUTHOR_WORKFLOW_PREVIEW: + case STAGING: + case STAGING_PREVIEW: + case WORKFLOW: + case WORKFLOW_PREVIEW: + AVMNodeDescriptor www = fAVMService.lookup(-1, store.getName() + ":/www"); + update = fixOldAvmAcls(www, false, indirections); + result.add(update); + break; + case UNKNOWN: + default: + update = fixOldAvmAcls(root, true, indirections); + result.add(update); + } + } HashMap toReturn = new HashMap(); @@ -614,20 +714,32 @@ public class AVMAccessControlListDAO implements AccessControlListDAO toReturn.put(ACLType.OLD, Integer.valueOf(result.get(ACLType.OLD).getCounter())); toReturn.put(ACLType.SHARED, Integer.valueOf(result.get(ACLType.SHARED).getCounter())); return toReturn; - } - private CounterSet fixOldAvmAcls(AVMNodeDescriptor node) + private CounterSet fixOldAvmAcls(AVMNodeDescriptor node, boolean searchDirectories, Map> indirections) + { + hibernateSessionHelper.mark(); + try + { + return fixOldAvmAclsImpl(node, searchDirectories, indirections); + } + finally + { + hibernateSessionHelper.resetAndRemoveMark(); + } + } + + private CounterSet fixOldAvmAclsImpl(AVMNodeDescriptor node, boolean searchDirectories, Map> indirections) { CounterSet result = new CounterSet(); // Do the children first - if (node.isDirectory()) + if (searchDirectories && node.isDirectory()) { Map children = fAVMRepository.getListingDirect(node, true); for (AVMNodeDescriptor child : children.values()) { - CounterSet update = fixOldAvmAcls(child); + CounterSet update = fixOldAvmAcls(child, searchDirectories, indirections); result.add(update); } } @@ -660,7 +772,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO List changes = new ArrayList(); - setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(id), changes, SetMode.DIRECT_ONLY, false); + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(id), changes, SetMode.DIRECT_ONLY, false, indirections); for (AclChange change : changes) { @@ -706,7 +818,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } List changes = new ArrayList(); - setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false); + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false, indirections); for (AclChange change : changes) { @@ -746,7 +858,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } List changes = new ArrayList(); - setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false); + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false, indirections); for (AclChange change : changes) { @@ -815,47 +927,55 @@ public class AVMAccessControlListDAO implements AccessControlListDAO counter += i; } } - + private DbAccessControlList getStoreAclAsSystem(final String storeName) { - return AuthenticationUtil.runAs(new RunAsWork(){ + return AuthenticationUtil.runAs(new RunAsWork() + { public DbAccessControlList doWork() throws Exception { return fAVMRepository.getStoreAcl(storeName); - }}, AuthenticationUtil.getSystemUserName()); + } + }, AuthenticationUtil.getSystemUserName()); } - + private void setStoreAclAsSystem(final String storeName, final DbAccessControlList acl) { - AuthenticationUtil.runAs(new RunAsWork(){ + AuthenticationUtil.runAs(new RunAsWork() + { public Object doWork() throws Exception { fAVMRepository.setStoreAcl(storeName, acl); return null; - }}, AuthenticationUtil.getSystemUserName()); + } + }, AuthenticationUtil.getSystemUserName()); } - + private DbAccessControlList getAclAsSystem(final int version, final String path) { - return AuthenticationUtil.runAs(new RunAsWork(){ + return AuthenticationUtil.runAs(new RunAsWork() + { public DbAccessControlList doWork() throws Exception { return fAVMRepository.getACL(version, path); - }}, AuthenticationUtil.getSystemUserName()); + } + }, AuthenticationUtil.getSystemUserName()); } - + private void setAclAsSystem(final String path, final DbAccessControlList acl) { - AuthenticationUtil.runAs(new RunAsWork(){ + AuthenticationUtil.runAs(new RunAsWork() + { public Object doWork() throws Exception { fAVMRepository.setACL(path, acl); return null; - }}, AuthenticationUtil.getSystemUserName()); + } + }, AuthenticationUtil.getSystemUserName()); } public DbAccessControlList getAccessControlList(StoreRef storeRef) @@ -869,7 +989,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO throw new InvalidStoreRefException(storeRef); } } - + public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) { try @@ -881,6 +1001,5 @@ public class AVMAccessControlListDAO implements AccessControlListDAO throw new InvalidStoreRefException(storeRef); } } - - + } diff --git a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java index 828b4f9cb8..88f4bcae29 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java @@ -25,6 +25,7 @@ package org.alfresco.repo.domain.hibernate; import java.io.Serializable; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -32,6 +33,7 @@ import java.util.List; import java.util.Set; import java.util.zip.CRC32; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.domain.DbAccessControlEntry; import org.alfresco.repo.domain.DbAccessControlList; @@ -60,8 +62,10 @@ import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; +import org.jgroups.tests.DeadlockTest.InRpc; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -92,12 +96,15 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo static String QUERY_GET_AVM_NODES_BY_ACL = "permission.FindAvmNodesByACL"; - static String QUERY_GET_AVM_NODES_BY_INDIRECTION = "permission.FindAvmNodesIndirection"; - static String QUERY_GET_LATEST_ACL_BY_ACLID = "permission.FindLatestAclByGuid"; + static String QUERY_GET_LAYERED_DIRECTORIES = "permission.GetLayeredDirectories"; + + static String QUERY_GET_LAYERED_FILES = "permission.GetLayeredFiles"; + /** Access to QName entities */ private QNameDAO qnameDAO; + /** a transactionally-safe cache to be injected */ private SimpleCache aclCache; @@ -1217,9 +1224,9 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo }; DbAuthority authority = null; List authorities = (List) getHibernateTemplate().execute(callback); - for(DbAuthority found : authorities) + for (DbAuthority found : authorities) { - if(found.getAuthority().equals(ace.getAuthority())) + if (found.getAuthority().equals(ace.getAuthority())) { authority = found; break; @@ -1239,7 +1246,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo final QName permissionQName = ace.getPermission().getQName(); final String permissionName = ace.getPermission().getName(); final QNameEntity permissionQNameEntity = qnameDAO.getOrCreateQNameEntity(permissionQName); - + callback = new HibernateCallback() { public Object doInHibernate(Session session) @@ -1312,14 +1319,13 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo return changes; } - private long getCrc(String str) { CRC32 crc = new CRC32(); crc.update(str.getBytes()); return crc.getValue(); } - + public List enableInheritance(Long id, Long parent) { List changes = new ArrayList(); @@ -1538,22 +1544,6 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo return avmNodeIds; } - @SuppressWarnings("unchecked") - public List getAvmNodesByIndirection(final String indirection) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_AVM_NODES_BY_INDIRECTION); - query.setParameter("indirection", indirection); - return query.list(); - } - }; - List avmNodeIds = (List) getHibernateTemplate().execute(callback); - return avmNodeIds; - } - @SuppressWarnings("unchecked") private List disableInheritanceImpl(Long id, boolean setInheritedOnAcl, DbAccessControlList acl) { @@ -1748,14 +1738,6 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo return ((Boolean) getHibernateTemplate().execute(callback)).booleanValue(); } - /** - * Just flushes the session - */ - public void flush() - { - getSession().flush(); - } - /** * NO-OP */ @@ -1832,4 +1814,155 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo } } + + /** + * Get the total number of head nodes in the repository + * + * @return + */ + public Long getAVMHeadNodeCount() + { + try + { + Session session = getSession(); + session.connection().setTransactionIsolation(1); + Query query = getSession().getNamedQuery("permission.GetAVMHeadNodeCount"); + Long answer = (Long) query.uniqueResult(); + return answer; + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level"); + } + + } + + public Long getMaxAclId() + { + try + { + Session session = getSession(); + session.connection().setTransactionIsolation(1); + Query query = getSession().getNamedQuery("permission.GetMaxAclId"); + Long answer = (Long) query.uniqueResult(); + return answer; + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level"); + } + } + + public Long getAVMNodeCountWithNewACLS(Long above) + { + try + { + Session session = getSession(); + session.connection().setTransactionIsolation(1); + Query query = getSession().getNamedQuery("permission.GetAVMHeadNodeCountWherePermissionsHaveChanged"); + query.setParameter("above", above); + Long answer = (Long) query.uniqueResult(); + return answer; + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level"); + } + } + + @SuppressWarnings("unchecked") + public List getLayeredDirectories() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_LAYERED_DIRECTORIES); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + ArrayList indirections = new ArrayList(results.size()); + for(Object[] row : results) + { + Long from = (Long)row[0]; + String to = (String) row[1]; + Integer version = (Integer) row[2]; + indirections.add(new Indirection(from, to, version)); + } + return indirections; + } + + @SuppressWarnings("unchecked") + public List getLayeredFiles() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_LAYERED_FILES); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + ArrayList indirections = new ArrayList(results.size()); + for(Object[] row : results) + { + Long from = (Long)row[0]; + String to = (String) row[1]; + Integer version = (Integer) row[2]; + indirections.add(new Indirection(from, to, version)); + } + return indirections; + } + + public List getAvmIndirections() + { + List dirList = getLayeredDirectories(); + List fileList = getLayeredFiles(); + ArrayList answer = new ArrayList(dirList.size() + fileList.size()); + answer.addAll(dirList); + answer.addAll(fileList); + return answer; + } + + public void flush() + { + getSession().flush(); + } + + public static class Indirection + { + Long from; + + String to; + + Integer toVersion; + + Indirection(Long from, String to, Integer toVersion) + { + this.from = from; + this.to = to; + this.toVersion = toVersion; + } + + public Long getFrom() + { + return from; + } + + public String getTo() + { + return to; + } + + public Integer getToVersion() + { + return toVersion; + } + + + + } + } diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateLoadListener.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateLoadListener.java new file mode 100644 index 0000000000..e1a445042e --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateLoadListener.java @@ -0,0 +1,22 @@ +package org.alfresco.repo.domain.hibernate; + +import org.hibernate.HibernateException; +import org.hibernate.event.LoadEvent; +import org.hibernate.event.LoadEventListener; +import org.hibernate.proxy.HibernateProxy; +import net.sf.cglib.proxy.Enhancer; + +public class HibernateLoadListener implements LoadEventListener +{ + + public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException + { + Object obj = event.getResult(); + if (obj instanceof HibernateProxy) { + Enhancer.registerCallbacks(obj.getClass(),null); + } + + + } + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelper.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelper.java new file mode 100644 index 0000000000..50ed21a590 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelper.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.util.List; + +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Utililty support against hibernate sessions. Supported by a super event listener which is registered on the even + * listener of the hibernate session. + * + * @author andyh + */ +public class HibernateSessionHelper extends HibernateDaoSupport implements HibernateSessionSupport +{ + /** + * + */ + private static final long serialVersionUID = -2532286150392812816L; + private static final String HIBERNATE_SESSION_EVENT_LISTENER = "HibernateSessionEventListener"; + + public void mark() + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.mark(getSession()); + } + + public void mark(String label) + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.mark(getSession(), label); + } + + public void reset() + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.reset(getSession()); + } + + public void reset(String label) + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.reset(getSession(), label); + } + + public void removeMark() + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.removeMark(getSession()); + } + + public void removeMark(String label) + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.removeMark(getSession(), label); + } + + public void resetAndRemoveMark() + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.resetAndRemoveMark(getSession()); + } + + public void resetAndRemoveMark(String label) + { + HibernateSessionHelperResourceProvider resource = getResource(); + resource.resetAndRemoveMark(getSession(), label); + } + + public List getMarks() + { + HibernateSessionHelperResourceProvider resource = getResource(); + return resource.getMarks(getSession()); + } + + public String getCurrentMark() + { + HibernateSessionHelperResourceProvider resource = getResource(); + return resource.getCurrentMark(); + } + + public static HibernateSessionHelperResourceProvider getResource() + { + HibernateSessionHelperResourceProvider listener = (HibernateSessionHelperResourceProvider) AlfrescoTransactionSupport.getResource(HIBERNATE_SESSION_EVENT_LISTENER); + if (listener == null) + { + listener = new HibernateSessionHelperResource(); + AlfrescoTransactionSupport.bindResource(HIBERNATE_SESSION_EVENT_LISTENER, listener); + } + return listener; + } + + + + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java new file mode 100644 index 0000000000..17817fdf05 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; + +import org.alfresco.util.GUID; +import org.hibernate.CacheMode; +import org.hibernate.Session; +import org.hibernate.engine.EntityKey; + +import com.sun.corba.se.spi.legacy.connection.GetEndPointInfoAgainException; + +/** + * Support to (optionally) listen to hibernate events generated by a hibernate session. The tracking is bound to a + * transaction resource + * + * @author andyh + */ +public class HibernateSessionHelperResource implements HibernateSessionHelperResourceProvider +{ + LinkedHashMap> marks = new LinkedHashMap>(); + + String currentMark = null; + + HibernateSessionHelperResource() + { + + } + + public String getCurrentMark() + { + return currentMark; + } + + public List getMarks(Session session) + { + ArrayList answer = new ArrayList(marks.size()); + for (String key : marks.keySet()) + { + answer.add(key); + } + return answer; + } + + public void mark(Session session) + { + Thread thread = Thread.currentThread(); + + String guid = GUID.generate(); + mark(session, guid); + + + } + + @SuppressWarnings("unchecked") + public void mark(Session session, String label) + { + session.flush(); + if (label == null) + { + throw new HibernateSessionHelperResourceException("Null key is not supported"); + + } + if (marks.containsKey(label)) + { + throw new HibernateSessionHelperResourceException("Key already exists - " + label); + } + + if (marks.size() == 0) + { + SessionSizeResourceManager.setDisableInTransaction(); + } + + HashSet mark = new HashSet((Set) session.getStatistics().getEntityKeys()); + marks.put(label, mark); + currentMark = label; + + //System.out.println("Mark "+marks.size()+" "+currentMark); + } + + public void removeMark(Session session) + { + if (currentMark != null) + { + removeMark(session, currentMark); + } + else + { + throw new HibernateSessionHelperResourceException("No current mark"); + } + + } + + public void removeMark(Session session, String label) + { + if (label == null) + { + throw new HibernateSessionHelperResourceException("Null key is not supported"); + + } + if (!marks.containsKey(label)) + { + throw new HibernateSessionHelperResourceException("Key does not exist - " + label); + } + + if (marks.size() > 0) + { + marks.remove(label); + + if (label.equals(currentMark)) + { + currentMark = getLastMarkOrNull(); + } + } + + if (marks.size() == 0) + { + SessionSizeResourceManager.setEnableInTransaction(); + } + } + + public void reset(Session session) + { + if (currentMark != null) + { + doResetAndRemove(session, currentMark, false); + } + else + { + throw new HibernateSessionHelperResourceException("No current mark"); + } + } + + public void reset(Session session, String label) + { + doResetAndRemove(session, label, false); + } + + public void resetAndRemoveMark(Session session) + { + if (currentMark != null) + { + doResetAndRemove(session, currentMark, true); + } + else + { + throw new HibernateSessionHelperResourceException("No current mark"); + } + } + + public void resetAndRemoveMark(Session session, String label) + { + doResetAndRemove(session, label, true); + } + + @SuppressWarnings("unchecked") + private void doResetAndRemove(Session session, String label, boolean remove) + { + if (label == null) + { + throw new HibernateSessionHelperResourceException("Null key is not supported"); + + } + if (!marks.containsKey(label)) + { + throw new HibernateSessionHelperResourceException("Key does not exist - " + label); + } + if (marks.size() > 0) + { + session.flush(); + + Set check = marks.get(label); + Set current = new HashSet((Set) session.getStatistics().getEntityKeys()); + + Set toEvict = new HashSet(Math.max((int) (current.size() / .75f) + 1, 16)); + + for (EntityKey key : current) + { + if (!check.contains(key)) + { + if (!key.getEntityName().startsWith("org.alfresco")) + { + System.out.println("Oops: " + key.getEntityName()); + } + + if(key.getEntityName().equals(QNameEntityImpl.class.getName())) + { + //System.out.println("Skipping: " + key.getEntityName()); + continue; + } + Object val = session.get(key.getEntityName(), key.getIdentifier()); + if (val != null) + { + toEvict.add(val); + } + } + } + + for (Object evitee : toEvict) + { + session.evict(evitee); + } + + String last; + while ((last = getLastMarkOrNull()) != null) + { + if (!label.equals(last)) + { + marks.remove(last); + } + else + { + if (remove) + { + marks.remove(last); + } + break; + } + } + + currentMark = getLastMarkOrNull(); + + if (marks.size() == 0) + { + SessionSizeResourceManager.setEnableInTransaction(); + } + + //System.out.println("Removed "+marks.size()+" "+label); + } + } + + private String getLastMarkOrNull() + { + String mark = null; + for (String key : marks.keySet()) + { + mark = key; + } + return mark; + } + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceException.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceException.java new file mode 100644 index 0000000000..0e2138f2e0 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceException.java @@ -0,0 +1,37 @@ +package org.alfresco.repo.domain.hibernate; + +import org.alfresco.error.AlfrescoRuntimeException; + +public class HibernateSessionHelperResourceException extends AlfrescoRuntimeException +{ + + /** + * + */ + private static final long serialVersionUID = 2935681199033295625L; + + public HibernateSessionHelperResourceException(String msgId, Object[] msgParams, Throwable cause) + { + super(msgId, msgParams, cause); + // TODO Auto-generated constructor stub + } + + public HibernateSessionHelperResourceException(String msgId, Object[] msgParams) + { + super(msgId, msgParams); + // TODO Auto-generated constructor stub + } + + public HibernateSessionHelperResourceException(String msgId, Throwable cause) + { + super(msgId, cause); + // TODO Auto-generated constructor stub + } + + public HibernateSessionHelperResourceException(String msgId) + { + super(msgId); + // TODO Auto-generated constructor stub + } + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceProvider.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceProvider.java new file mode 100644 index 0000000000..bbcdcf9f46 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResourceProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.util.List; + +import org.hibernate.Session; + +public interface HibernateSessionHelperResourceProvider +{ + public void mark(Session session); + + public void mark(Session session, String label); + + public void reset(Session session); + + public void reset(Session session, String label); + + public void removeMark(Session session); + + public void removeMark(Session session, String label); + + public void resetAndRemoveMark(Session session); + + public void resetAndRemoveMark(Session session, String label); + + public List getMarks(Session session); + + public String getCurrentMark(); +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java new file mode 100644 index 0000000000..46b37d39cd --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java @@ -0,0 +1,570 @@ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import org.alfresco.repo.domain.NodeKey; +import org.alfresco.repo.domain.NodeStatus; +import org.alfresco.repo.domain.Server; +import org.alfresco.repo.domain.StoreKey; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.BaseSpringTest; +import org.hibernate.engine.EntityKey; +import org.springframework.orm.toplink.SessionReadCallback; + +public class HibernateSessionHelperTest extends BaseSpringTest +{ + + + protected void onTearDownInTransaction() + { + // force a flush to ensure that the database updates succeed + getSession().flush(); + getSession().clear(); + } + + public void testSimpleMark() + { + assertEquals(0, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + StoreImpl store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + getName() + " - " + System.currentTimeMillis()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + assertEquals(1, getSession().getStatistics().getEntityCount()); + + Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + + assertEquals(2, getSession().getStatistics().getEntityCount()); + + HibernateSessionHelper helper = (HibernateSessionHelper)getApplicationContext().getBean("hibernateSessionHelper"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + + TransactionImpl transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + Serializable txID = getSession().save(transaction); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + helper.reset(); + + assertEquals(2, getSession().getStatistics().getEntityCount()); + + getSession().get(TransactionImpl.class, txID); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + helper.resetAndRemoveMark(); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + assertEquals(0, helper.getMarks().size()); + assertEquals(2, getSession().getStatistics().getEntityCount()); + + } + + public void testNestedMarks() + { + assertEquals(0, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + StoreImpl store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + getName() + " - " + System.currentTimeMillis()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + assertEquals(1, getSession().getStatistics().getEntityCount()); + + Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + + TransactionImpl transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + Serializable txID = getSession().save(transaction); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + HibernateSessionHelper helper = (HibernateSessionHelper)getApplicationContext().getBean("hibernateSessionHelper"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + + NodeKey key1 = new NodeKey(store.getKey(), "1"); + createNodeStatus(transaction, key1); + + assertEquals(4, getSession().getStatistics().getEntityCount()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(2, helper.getMarks().size()); + + NodeKey key2 = new NodeKey(store.getKey(), "2"); + createNodeStatus(transaction, key2); + + assertEquals(5, getSession().getStatistics().getEntityCount()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(3, helper.getMarks().size()); + + NodeKey key3 = new NodeKey(store.getKey(), "3"); + createNodeStatus(transaction, key3); + + assertEquals(6, getSession().getStatistics().getEntityCount()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(4, helper.getMarks().size()); + + NodeKey key4 = new NodeKey(store.getKey(), "4"); + createNodeStatus(transaction, key4); + + assertEquals(7, getSession().getStatistics().getEntityCount()); + helper.mark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + + NodeKey key5 = new NodeKey(store.getKey(), "5"); + createNodeStatus(transaction, key5); + + assertEquals(8, getSession().getStatistics().getEntityCount()); + + helper.reset(); + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + getSession().get(NodeStatusImpl.class, key5); + assertEquals(8, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertTrue(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.reset(); + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + getSession().get(NodeStatusImpl.class, key5); + assertEquals(8, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertTrue(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark(); + + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(4, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark(); + + assertEquals(6, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(3, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + + helper.resetAndRemoveMark(); + + assertEquals(5, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(2, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertFalse(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark(); + + assertEquals(4, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertFalse(sessionContainsNodeStatus(key3)); + assertFalse(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark(); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(0, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertFalse(sessionContainsNodeStatus(key3)); + assertFalse(sessionContainsNodeStatus(key2)); + assertFalse(sessionContainsNodeStatus(key1)); + + try + { + helper.reset(); + fail("can not reset"); + } + catch(HibernateSessionHelperResourceException hshre) + { + + } + } + + public void testNamedMarks() + { + assertEquals(0, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + StoreImpl store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + getName() + " - " + System.currentTimeMillis()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + assertEquals(1, getSession().getStatistics().getEntityCount()); + + Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + + assertEquals(2, getSession().getStatistics().getEntityCount()); + + HibernateSessionHelper helper = (HibernateSessionHelper)getApplicationContext().getBean("hibernateSessionHelper"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + helper.mark("One"); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + + TransactionImpl transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + Serializable txID = getSession().save(transaction); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + helper.reset("One"); + + assertEquals(2, getSession().getStatistics().getEntityCount()); + + getSession().get(TransactionImpl.class, txID); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + helper.resetAndRemoveMark("One"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + assertEquals(0, helper.getMarks().size()); + assertEquals(2, getSession().getStatistics().getEntityCount()); + + } + + + public void testNestedNamedMarks() + { + assertEquals(0, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + StoreImpl store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + getName() + " - " + System.currentTimeMillis()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + assertEquals(1, getSession().getStatistics().getEntityCount()); + + Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + + TransactionImpl transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + Serializable txID = getSession().save(transaction); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + HibernateSessionHelper helper = (HibernateSessionHelper)getApplicationContext().getBean("hibernateSessionHelper"); + assertNull(helper.getCurrentMark()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + helper.mark("One"); + assertEquals("One", helper.getCurrentMark()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + + NodeKey key1 = new NodeKey(store.getKey(), "1"); + createNodeStatus(transaction, key1); + + assertEquals(4, getSession().getStatistics().getEntityCount()); + helper.mark("Two"); + assertEquals("Two", helper.getCurrentMark()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(2, helper.getMarks().size()); + + NodeKey key2 = new NodeKey(store.getKey(), "2"); + createNodeStatus(transaction, key2); + + assertEquals(5, getSession().getStatistics().getEntityCount()); + helper.mark("Three"); + assertEquals("Three", helper.getCurrentMark()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(3, helper.getMarks().size()); + + NodeKey key3 = new NodeKey(store.getKey(), "3"); + createNodeStatus(transaction, key3); + + assertEquals(6, getSession().getStatistics().getEntityCount()); + helper.mark("Four"); + assertEquals("Four", helper.getCurrentMark()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(4, helper.getMarks().size()); + + NodeKey key4 = new NodeKey(store.getKey(), "4"); + createNodeStatus(transaction, key4); + + assertEquals(7, getSession().getStatistics().getEntityCount()); + helper.mark("Five"); + assertEquals("Five", helper.getCurrentMark()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + + NodeKey key5 = new NodeKey(store.getKey(), "5"); + createNodeStatus(transaction, key5); + + assertEquals(8, getSession().getStatistics().getEntityCount()); + + helper.reset("Five"); + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + getSession().get(NodeStatusImpl.class, key5); + assertEquals(8, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertTrue(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.reset("Five"); + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + getSession().get(NodeStatusImpl.class, key5); + assertEquals(8, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertTrue(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + assertEquals("Five", helper.getCurrentMark()); + helper.resetAndRemoveMark("Five"); + assertEquals("Four", helper.getCurrentMark()); + + assertEquals(7, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(4, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertTrue(sessionContainsNodeStatus(key4)); + assertTrue(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark("Three"); + assertEquals("Two", helper.getCurrentMark()); + + assertEquals(5, getSession().getStatistics().getEntityCount()); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(2, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertFalse(sessionContainsNodeStatus(key3)); + assertTrue(sessionContainsNodeStatus(key2)); + assertTrue(sessionContainsNodeStatus(key1)); + + helper.resetAndRemoveMark("One"); + assertNull(helper.getCurrentMark()); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(0, helper.getMarks().size()); + assertFalse(sessionContainsNodeStatus(key5)); + assertFalse(sessionContainsNodeStatus(key4)); + assertFalse(sessionContainsNodeStatus(key3)); + assertFalse(sessionContainsNodeStatus(key2)); + assertFalse(sessionContainsNodeStatus(key1)); + + try + { + helper.reset("One"); + fail("can not reset"); + } + catch(HibernateSessionHelperResourceException hshre) + { + + } + } + + public void voidTestRemove() + { + assertEquals(0, getSession().getStatistics().getEntityCount()); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + + StoreImpl store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + getName() + " - " + System.currentTimeMillis()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + assertEquals(1, getSession().getStatistics().getEntityCount()); + + Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + + TransactionImpl transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + Serializable txID = getSession().save(transaction); + + assertEquals(3, getSession().getStatistics().getEntityCount()); + + HibernateSessionHelper helper = (HibernateSessionHelper)getApplicationContext().getBean("hibernateSessionHelper"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + helper.mark("One"); + helper.mark("Two"); + helper.mark("Three"); + helper.mark("Four"); + helper.mark("Five"); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(5, helper.getMarks().size()); + assertEquals("Five", helper.getCurrentMark()); + + helper.removeMark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(4, helper.getMarks().size()); + assertEquals("Four", helper.getCurrentMark()); + + helper.removeMark("One"); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(3, helper.getMarks().size()); + assertEquals("Four", helper.getCurrentMark()); + + helper.removeMark(); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(2, helper.getMarks().size()); + assertEquals("Three", helper.getCurrentMark()); + + helper.removeMark("Two"); + assertTrue(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(1, helper.getMarks().size()); + assertEquals("Three", helper.getCurrentMark()); + + helper.removeMark("Three"); + assertFalse(SessionSizeResourceManager.isDisableInTransaction()); + assertEquals(0, helper.getMarks().size()); + assertNull(helper.getCurrentMark()); + } + + private NodeStatus createNodeStatus(TransactionImpl transaction, NodeKey key) + { + NodeStatus nodeStatus = new NodeStatusImpl(); + nodeStatus.setKey(key); + nodeStatus.setTransaction(transaction); + getSession().save(nodeStatus); + return nodeStatus; + } + + @SuppressWarnings("unchecked") + private boolean sessionContainsNodeStatus(NodeKey nodeKey) + { + Set keys = (Set)getSession().getStatistics().getEntityKeys(); + for(EntityKey key : keys) + { + if(key.getEntityName().equals(NodeStatusImpl.class.getName())) + { + if(key.getIdentifier().equals(nodeKey)) + { + return true; + } + } + } + return false; + } + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionSupport.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionSupport.java new file mode 100644 index 0000000000..40762b96b9 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionSupport.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.util.List; + +public interface HibernateSessionSupport +{ + public void mark(); + + public void mark(String label); + + public void reset(); + + public void reset(String label); + + public void removeMark(); + + public void removeMark(String label); + + public void resetAndRemoveMark(); + + public void resetAndRemoveMark(String label); + + public List getMarks(); + + public String getCurrentMark(); +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml index 78b9c7eb81..9f27b774f7 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml @@ -378,6 +378,53 @@ where acl.aclId = :aclId and latest = true + + + + + + + + :above + ]]> + + + + + + + + + + + + + + + +