From f1307fba20370c328ec9abecf9dfece5c373d6e8 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Wed, 11 Mar 2009 03:22:35 +0000 Subject: [PATCH] Merged V3.1 to HEAD 12999: Fixed read-only bootstrap of SiteAVMBootstrap and removed incorrect use of 'assert' 13000: Added log4j to Eclipse classpath (unexported) 13001: Merged V2.1-A to V3.1 9127: Performance improvement to folder copy 9151: *RECORD-ONLY* Fix index back up failing with missing files 13002: Merged V2.1-A to V3.1 9174: Further fixes for ACT-2588 (Lucene backup read-write locks) 9279: Fix ADB-84. PHP module is not restricted by the upper version 10191: Fix for ADB-77: Need to have as the sender's email address the email address of the user triggering the rule 13006: Merged V2.1-A to V3.1 10893: Fixes for ADB-78 & ADB-98 - Fixed service getter/setter pattern as well 10903: Fix for ADB-115 ACT-4355 13010: Made AVMLockingBootstrap resilient to read-only mode 13011: Better message for InvalidStoreRefException 13013: Merged V2.1-A to V3.1 9189: Composite Conditions Support Part 1 of 2 (repo) 9190: Composite Conditions Support Part 1a of 2 ( missed file from repo) 13015: Port of Adobe CIFS/FTP configuration changes 13017: Convert avoids folders given by '--svn-status' option 13018: Merge V2.1A to V3.1 7746: (record-only) Added ability to specify a custom CIFS authenticator class 8533: (record-only) Added the configuration tag, disable use of JNI code on Windows 8700: (record-only) Update to prevent any native calls via configuration code 8705: (record-only) Filer out the '0.0.0.0' bind address 8864: (record-only) Added the getBean() method for custom authenticators to get access to beans 9054: (record-only) Added the 'AIX' platform type for use in the platforms="..." attribute 8863: (record-only) Fix passthru socket connection timeout, added 'protocolOrder' and 'offlineCheckInterval' config values 12144: (record-only) CIFS virtual circuit fixes 13020: Merged V2.1-A to V3.1 (Composite Actions) 9191: Composite Conditions Support Part 2 of 2 (client) 9243: Composite Conditions Support Part 1 of 2 (client) 9245: Composite Conditions Support Part 2 of 2 (repo) 13021: Merged V3.0 to V3.1 13008: Merged V2.2 to V3.0 12824: (record only) Change admin access to the web project staging store to be read-only in the virtualization view - ETWOTWO-933 13024: Ported CIFS configuration changes from Adobe V2.1A, missed checkin. ___________________________________________________________________ Modified: svn:mergeinfo Merged /alfresco/BRANCHES/V2.1-A:r9127,9151,9174,9189-9191,9243,9245,9279,10191,10893,10903 Merged /alfresco/BRANCHES/V3.1:r12999-13002,13006,13010-13011,13013,13015,13017-13018,13020-13021,13024 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13550 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/action-services-context.xml | 210 +- config/alfresco/bootstrap-context.xml | 10 +- .../messages/action-config.properties | 14 +- config/alfresco/network-protocol-context.xml | 3 + .../filesys/AlfrescoConfigSection.java | 13 + .../filesys/ServerConfigurationBean.java | 117 +- .../auth/cifs/AlfrescoCifsAuthenticator.java | 17 + .../auth/cifs/CifsAuthenticatorBase.java | 51 + .../cifs/EnterpriseCifsAuthenticator.java | 4 + .../auth/cifs/PassthruCifsAuthenticator.java | 4 + .../auth/ftp/AlfrescoFtpAuthenticator.java | 85 +- .../auth/ftp/FTPAuthenticatorBase.java | 177 ++ .../auth/ftp/PassthruFtpAuthenticator.java | 57 +- .../org/alfresco/filesys/avm/AVMContext.java | 22 + .../alfresco/filesys/avm/AVMDiskDriver.java | 68 +- .../repo/action/ActionConditionImpl.java | 4 +- .../org/alfresco/repo/action/ActionModel.java | 10 +- .../repo/action/ActionServiceImpl.java | 2199 +++++++++-------- .../repo/action/ActionServiceImplTest.java | 1545 ++++++------ .../repo/action/ActionServiceRemote.java | 6 + .../alfresco/repo/action/ActionTestSuite.java | 1 + .../action/CompositeActionConditionImpl.java | 113 + .../CompositeActionConditionImplTest.java | 100 + .../org/alfresco/repo/action/actionModel.xml | 104 +- .../ComparePropertyValueEvaluator.java | 115 +- .../CompositeConditionEvaluator.java | 58 + .../action/evaluator/IsSubTypeEvaluator.java | 20 +- .../evaluator/NoConditionEvaluator.java | 20 +- .../compare/PropertyValueComparator.java | 2 +- .../action/executer/MailActionExecuter.java | 19 +- .../repo/avm/locking/AVMLockingBootstrap.java | 23 +- .../alfresco/repo/copy/CopyServiceImpl.java | 22 +- .../repo/node/db/DbNodeServiceImpl.java | 2 +- ...stractLuceneIndexerAndSearcherFactory.java | 61 +- .../alfresco/repo/site/SiteAVMBootstrap.java | 35 +- .../service/cmr/action/ActionService.java | 371 +-- .../cmr/action/CompositeActionCondition.java | 108 + 37 files changed, 3498 insertions(+), 2292 deletions(-) create mode 100644 source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java create mode 100644 source/java/org/alfresco/repo/action/CompositeActionConditionImpl.java create mode 100644 source/java/org/alfresco/repo/action/CompositeActionConditionImplTest.java create mode 100644 source/java/org/alfresco/repo/action/evaluator/CompositeConditionEvaluator.java create mode 100644 source/java/org/alfresco/service/cmr/action/CompositeActionCondition.java diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index 9320d07264..6753db6a70 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -38,64 +38,64 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - + - + - + - + - + - + @@ -103,25 +103,25 @@ - - - - - - - - + + + + + + + + - - - alfresco.messages.action-service - alfresco.messages.action-config - - + + + alfresco.messages.action-service + alfresco.messages.action-config + + @@ -147,12 +147,17 @@ - - - + + + - + + + + + + @@ -174,7 +179,7 @@ - + @@ -192,6 +197,9 @@ + + + @@ -204,21 +212,21 @@ false - + - + false - + - - + + - + @@ -274,9 +282,9 @@ - - {http://www.alfresco.org/model/content/1.0}content - + + {http://www.alfresco.org/model/content/1.0}content + @@ -319,9 +327,9 @@ - - {http://www.alfresco.org/model/content/1.0}content - + + {http://www.alfresco.org/model/content/1.0}content + @@ -333,9 +341,9 @@ - - {http://www.alfresco.org/model/content/1.0}content - + + {http://www.alfresco.org/model/content/1.0}content + @@ -392,9 +400,9 @@ - - {http://www.alfresco.org/model/content/1.0}content - + + {http://www.alfresco.org/model/content/1.0}content + true @@ -490,17 +498,17 @@ - - - - - - - - - - false - + + + + + + + + + + false + @@ -516,12 +524,12 @@ - - - - - false - + + + + + false + @@ -552,25 +560,25 @@ - - - - - - - - false - + + + + + + + + false + - deployment - + deployment + - + @@ -579,7 +587,7 @@ - false + false admin @@ -605,9 +613,9 @@ - - false - + + false + diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 4ec4ac66e1..7cf67059b0 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -129,9 +129,8 @@ - - - + + @@ -140,12 +139,12 @@ - + - + @@ -341,6 +340,7 @@ + sitestore diff --git a/config/alfresco/messages/action-config.properties b/config/alfresco/messages/action-config.properties index ebafee8c25..a5147e41b8 100644 --- a/config/alfresco/messages/action-config.properties +++ b/config/alfresco/messages/action-config.properties @@ -18,6 +18,18 @@ has-aspect.description=The rule is applied to all items that have the specified compare-mime-type.title=Items with the specified mime type compare-mime-type.description=The rule is applied to all items that have content of the specified mime type. +composite-condition.title=Composite Condition +composite-condition.description=Combine several conditions to create a more complicate condition. + +compare-date-property.title=Items with specific date value in property +compare-date-property.description=Compare a date property of the metadata, aspect or type + +compare-integer-property.title=Items with specific integer value in property +compare-integer-property.description=Compare an integer property of the metadata, aspect or type + +compare-text-property.title=Items with specific text value in property +compare-text-property.description=Compare a text property of the metadata, aspect or type + # Actions add-features.title=Add aspect to item @@ -28,7 +40,7 @@ remove-features.description=This will remove an aspect from the matched item. simple-workflow.title=Add simple workflow to item simple-workflow.description=This will add a simple workflow to the matched item. This will allow the item to be moved to a different space for its next step in a workflow. You can also give a space for it to be moved to if you want a reject step. - + link-category.title=Link item to category link-category.description=This will apply a category to the matched item. diff --git a/config/alfresco/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml index 7a821f7222..8cfcfb0e67 100644 --- a/config/alfresco/network-protocol-context.xml +++ b/config/alfresco/network-protocol-context.xml @@ -57,6 +57,9 @@ + + + diff --git a/source/java/org/alfresco/filesys/AlfrescoConfigSection.java b/source/java/org/alfresco/filesys/AlfrescoConfigSection.java index 3ba8c9a2c9..7c5472d8af 100644 --- a/source/java/org/alfresco/filesys/AlfrescoConfigSection.java +++ b/source/java/org/alfresco/filesys/AlfrescoConfigSection.java @@ -31,6 +31,7 @@ import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; @@ -70,6 +71,7 @@ public class AlfrescoConfigSection extends ConfigSection { private TenantService m_tenantService; private SearchService m_searchService; private NamespaceService m_namespaceService; + private AuthorityService m_authorityService; /** * Class constructor @@ -93,6 +95,7 @@ public class AlfrescoConfigSection extends ConfigSection { m_tenantService = config.getTenantService(); m_searchService = config.getSearchService(); m_namespaceService = config.getNamespaceService(); + m_authorityService = config.getAuthorityService(); } /** @@ -194,4 +197,14 @@ public class AlfrescoConfigSection extends ConfigSection { { return m_namespaceService; } + + /** + * Return the authority service + * + * @return AuthorityService + */ + public final AuthorityService getAuthorityService() + { + return m_authorityService; + } } diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java index c4847f8ae0..a39608ffb9 100644 --- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.java @@ -97,6 +97,7 @@ import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; @@ -231,12 +232,17 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl private TenantService m_tenantService; private SearchService m_searchService; private NamespaceService m_namespaceService; + private AuthorityService m_authorityService; // Local server name and domain/workgroup name private String m_localName; private String m_localDomain; + // Disable use of native code on Windows, do not use any JNI calls + + private boolean m_disableNativeCode = false; + /** * Default constructor */ @@ -374,6 +380,16 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl m_namespaceService = namespaceService; } + /** + * Set the authority service + * + * @param authService AuthorityService + */ + public void setAuthorityService(AuthorityService authService) + { + m_authorityService = authService; + } + /** * Check if the configuration has been initialized * @@ -473,6 +489,10 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl { throw new AlfrescoRuntimeException("Property 'configService' not set"); } + else if (m_authorityService == null) + { + throw new AlfrescoRuntimeException("Property 'authorityService' not set"); + } // Create the configuration context @@ -675,6 +695,21 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl try { + // Check if native code calls should be disabled on Windows + + elem = config.getConfigElement( "disableNativeCode"); + if ( elem != null) + { + // Disable native code calls so that the JNI DLL is not required + + cifsConfig.setNativeCodeDisabled( true); + m_disableNativeCode = true; + + // Warning + + logger.warn("CIFS server native calls disabled, JNI code will not be used"); + } + // Get the network broadcast address // // Note: We need to set this first as the call to getLocalDomainName() may use a NetBIOS @@ -767,7 +802,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl String localDomain = getLocalDomainName(); - if ( localDomain == null && getPlatformType() != Platform.Type.WINDOWS) + if ( localDomain == null && ( getPlatformType() != Platform.Type.WINDOWS || isNativeCodeDisabled())) { // Use a default domain/workgroup name @@ -874,6 +909,13 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl authClass = "org.alfresco.filesys.auth.cifs.EnterpriseCifsAuthenticator"; } + else if ( authType.equalsIgnoreCase( "custom")) + { + // Get the authenticator class + + ConfigElement authClassElem = authElem.getChild("class"); + authClass = authClassElem.getValue(); + } else throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType); @@ -1348,7 +1390,8 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl String osName = System.getProperty("os.name"); if (osName.startsWith("Windows") - && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false)) + && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false) + && isNativeCodeDisabled() == false) { // Call the Win32NetBIOS native code to make sure it is initialized @@ -1478,7 +1521,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl // Check if WINS is configured, if we are running on Windows and socket based NetBIOS is enabled - else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS) + else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS && isNativeCodeDisabled()) { // Get the WINS server list @@ -1834,8 +1877,15 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl { // Standard authenticator requires MD4 or passthru based authentication - if ( ntlmMode == NTLMMode.NONE) - throw new AlfrescoRuntimeException("Wrong authentication setup for alfresco authenticator"); +// if ( ntlmMode == NTLMMode.NONE) +// throw new AlfrescoRuntimeException("Wrong authentication setup for alfresco authenticator"); + } + else if ( authType.equalsIgnoreCase( "custom")) + { + // Get the authenticator class + + ConfigElement authClassElem = authElem.getChild("class"); + authClass = authClassElem.getValue(); } else throw new AlfrescoRuntimeException("Invalid authenticator type, " + authType); @@ -2056,9 +2106,19 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl { try { + // Default RPC authenticator class + + String authClass = "org.alfresco.filesys.auth.nfs.AlfrescoRpcAuthenticator"; + + // Check if a custom NFS authentictor class has been specified + + ConfigElement authClassElem = elem.getChild("class"); + if ( authClassElem != null) + authClass = authClassElem.getValue(); + // Create the RPC authenticator - nfsConfig.setRpcAuthenticator( "org.alfresco.filesys.auth.nfs.AlfrescoRpcAuthenticator", elem); + nfsConfig.setRpcAuthenticator( authClass, elem); } catch ( InvalidConfigurationException ex) { @@ -2934,7 +2994,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl String srvName = null; - if (getPlatformType() == Platform.Type.WINDOWS) + if (getPlatformType() == Platform.Type.WINDOWS && isNativeCodeDisabled() == false) { // Get the local name via JNI @@ -2987,7 +3047,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl String domainName = null; - if (getPlatformType() == Platform.Type.WINDOWS) + if (getPlatformType() == Platform.Type.WINDOWS && isNativeCodeDisabled()) { // Get the local domain/workgroup name via JNI @@ -3193,4 +3253,45 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl { return m_namespaceService; } + + /** + * Check if native code calls are disabled + * + * @return boolean + */ + public final boolean isNativeCodeDisabled() + { + return m_disableNativeCode; + } + + /** + * Return the named bean + * + * @param beanName String + * @return Object + */ + public final Object getBean( String beanName) + { + return applicationContext.getBean( beanName); + } + + /** + * Return the applicatin context + * + * @return ApplicationContext + */ + public final ApplicationContext getApplicationsContext() + { + return applicationContext; + } + + /** + * Return the authority service + * + * @return AuthorityService + */ + public final AuthorityService getAuthorityService() + { + return m_authorityService; + } } diff --git a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java index a2a87006f6..c04f9c45a5 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java @@ -239,6 +239,11 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase } } + // Check for an administrator logon + + if ( authSts == AUTH_ALLOW && client.getLogonType() == ClientInfo.LogonNormal) + checkForAdminUserName( client); + // DEBUG if ( logger.isDebugEnabled()) @@ -404,6 +409,10 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase getHomeFolderForUser( client); + // Indicate this is a normal user logon + + client.setLogonType( ClientInfo.LogonNormal); + // Passwords match, grant access return CifsAuthenticator.AUTH_ALLOW; @@ -497,6 +506,10 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Allow the user access as a guest authSts = CifsAuthenticator.AUTH_GUEST; + + // Indicate that this is a guest logon + + client.setLogonType( ClientInfo.LogonGuest); } } else @@ -505,6 +518,10 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase // Allow the user full access to the server authSts = CifsAuthenticator.AUTH_ALLOW; + + // Indicate that this is a normal user logon + + client.setLogonType( ClientInfo.LogonNormal); } // Set the current user to be authenticated, save the authentication token diff --git a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java index 9f61a0b792..2beead17e2 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java +++ b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java @@ -49,6 +49,7 @@ import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; @@ -349,4 +350,54 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator { return m_alfrescoConfig.getTransactionService(); } + + /** + * Return the authority service + * + * @return AuthorityService + */ + protected final AuthorityService getAuthorityService() { + return m_alfrescoConfig.getAuthorityService(); + } + + /** + * Check if the user is an administrator user name + * + * @param cInfo ClientInfo + */ + protected final void checkForAdminUserName(ClientInfo cInfo) { + + // Check if the user name is an administrator + + UserTransaction tx = getTransactionService().getUserTransaction(); + + try { + tx.begin(); + + if ( cInfo.getLogonType() == ClientInfo.LogonNormal && getAuthorityService().isAdminAuthority(cInfo.getUserName())) { + + // Indicate that this is an administrator logon + + cInfo.setLogonType(ClientInfo.LogonAdmin); + } + tx.commit(); + } + catch (Throwable ex) { + try { + tx.rollback(); + } + catch (Throwable ex2) { + logger.error("Failed to rollback transaction", ex2); + } + + // Re-throw the exception + + if ( ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + else { + throw new RuntimeException("Error during execution of transaction.", ex); + } + } + } } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java index 271434abf0..72c6623956 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java @@ -901,6 +901,10 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement sess.removeSetupObject( client.getProcessId()); + // Check if the user is an administrator + + checkForAdminUserName( client); + // Create a virtual circuit for the new logon VirtualCircuit vc = new VirtualCircuit( vcNum, client); diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java index 55f47587a6..7000fc9151 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java @@ -739,6 +739,10 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements sess.removeSetupObject( client.getProcessId()); + // Check if the user is an administrator + + checkForAdminUserName( client); + // Create a virtual circuit for the new logon VirtualCircuit vc = new VirtualCircuit( vcNum, client); diff --git a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java index b4c506255f..1921ba5083 100644 --- a/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/ftp/AlfrescoFtpAuthenticator.java @@ -44,6 +44,7 @@ import org.alfresco.repo.security.authentication.MD4PasswordEncoder; import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl; import org.alfresco.repo.security.authentication.NTLMMode; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -53,11 +54,7 @@ import org.apache.commons.logging.LogFactory; * * @author gkspencer */ -public class AlfrescoFtpAuthenticator implements FTPAuthenticator { - - // Logging - - protected static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol.auth"); +public class AlfrescoFtpAuthenticator extends FTPAuthenticatorBase { // MD4 hash decoder @@ -67,30 +64,6 @@ public class AlfrescoFtpAuthenticator implements FTPAuthenticator { protected PasswordEncryptor m_encryptor = new PasswordEncryptor(); - // Alfresco configuration section - - private AlfrescoConfigSection m_alfrescoConfig; - - /** - * Initialize the authenticator - * - * @param config ServerConfiguration - * @param params ConfigElement - * @exception InvalidConfigurationException - */ - public void initialize(ServerConfiguration config, ConfigElement params) - throws InvalidConfigurationException - { - // Get the alfresco configuration section, required to get hold of various services/components - - m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName); - - // Check that the required authentication classes are available - - if ( m_alfrescoConfig == null || getAuthenticationComponent() == null) - throw new InvalidConfigurationException("Authentication component not available"); - } - /** * Authenticate the user * @@ -121,6 +94,7 @@ public class AlfrescoFtpAuthenticator implements FTPAuthenticator { // Indicate logged on as guest authSts = true; + client.setLogonType( ClientInfo.LogonGuest); // DEBUG @@ -136,10 +110,24 @@ public class AlfrescoFtpAuthenticator implements FTPAuthenticator { tx = getTransactionService().getUserTransaction( false); tx.begin(); - + // Perform local MD4 password check authSts = doMD4UserAuthentication(client, sess); + + // Check if the user has been logged on successfully + + if ( authSts == true) + client.setLogonType( ClientInfo.LogonNormal); + + // Check if the logged on user is an administrator + + if ( client.getLogonType() == ClientInfo.LogonNormal) + { + // Check for an administrator logon, update the logon type + + checkForAdminUserName( client); + } } catch ( Exception ex) { @@ -263,41 +251,4 @@ public class AlfrescoFtpAuthenticator implements FTPAuthenticator { return false; } - - /** - * Return the authentication componenet - * - * @return AuthenticationComponent - */ - protected final AuthenticationComponent getAuthenticationComponent() - { - return m_alfrescoConfig.getAuthenticationComponent(); - } - - /** - * Return the authentication service - * - * @return AuthenticationService - */ - protected final AuthenticationService getAuthenticationService() - { - return m_alfrescoConfig.getAuthenticationService(); - } - - /** - * Return the transaction service - * - * @return TransactionService - */ - protected final TransactionService getTransactionService() - { - return m_alfrescoConfig.getTransactionService(); - } - - /** - * Close the authenticator, perform any cleanup - */ - public void closeAuthenticator() - { - } } diff --git a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java new file mode 100644 index 0000000000..2fcfef9e04 --- /dev/null +++ b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006-2008 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.filesys.auth.ftp; + +import javax.transaction.UserTransaction; + +import org.alfresco.config.ConfigElement; +import org.alfresco.filesys.AlfrescoConfigSection; +import org.alfresco.jlan.ftp.FTPAuthenticator; +import org.alfresco.jlan.ftp.FTPSrvSession; +import org.alfresco.jlan.server.auth.ClientInfo; +import org.alfresco.jlan.server.config.InvalidConfigurationException; +import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author gkspencer + */ +public abstract class FTPAuthenticatorBase implements FTPAuthenticator { + + // Logging + + protected static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol.auth"); + + // Alfresco configuration section + + private AlfrescoConfigSection m_alfrescoConfig; + + /** + * Default constructor + */ + public FTPAuthenticatorBase() { + } + + /** + * Initialize the authenticator + * + * @param config ServerConfiguration + * @param params ConfigElement + * @exception InvalidConfigurationException + */ + public void initialize(ServerConfiguration config, ConfigElement params) + throws InvalidConfigurationException { + + // Get the alfresco configuration section, required to get hold of various + // services/components + + m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection(AlfrescoConfigSection.SectionName); + + // Check that the required authentication classes are available + + if ( m_alfrescoConfig == null || getAuthenticationComponent() == null) + throw new InvalidConfigurationException("Authentication component not available"); + } + + /** + * Authenticate the user + * + * @param client ClientInfo + * @param sess FTPSrvSession + * @return boolean + */ + public abstract boolean authenticateUser(ClientInfo info, FTPSrvSession sess); + + /** + * Close the authenticator, perform any cleanup + */ + public void closeAuthenticator() + { + } + + /** + * Return the authentication componenet + * + * @return AuthenticationComponent + */ + protected final AuthenticationComponent getAuthenticationComponent() { + return m_alfrescoConfig.getAuthenticationComponent(); + } + + /** + * Return the authentication service + * + * @return AuthenticationService + */ + protected final AuthenticationService getAuthenticationService() { + return m_alfrescoConfig.getAuthenticationService(); + } + + /** + * Return the transaction service + * + * @return TransactionService + */ + protected final TransactionService getTransactionService() { + return m_alfrescoConfig.getTransactionService(); + } + + /** + * Return the authority service + * + * @return AuthorityService + */ + protected final AuthorityService getAuthorityService() { + return m_alfrescoConfig.getAuthorityService(); + } + + /** + * Check if the user is an administrator user name + * + * @param cInfo ClientInfo + */ + protected final void checkForAdminUserName(ClientInfo cInfo) { + + // Check if the user name is an administrator + + UserTransaction tx = getTransactionService().getUserTransaction(); + + try { + tx.begin(); + + if ( cInfo.getLogonType() == ClientInfo.LogonNormal && getAuthorityService().isAdminAuthority(cInfo.getUserName())) { + + // Indicate that this is an administrator logon + + cInfo.setLogonType(ClientInfo.LogonAdmin); + } + tx.commit(); + } + catch (Throwable ex) { + try { + tx.rollback(); + } + catch (Throwable ex2) { + logger.error("Failed to rollback transaction", ex2); + } + + // Re-throw the exception + + if ( ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + else { + throw new RuntimeException("Error during execution of transaction.", ex); + } + } + } +} diff --git a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java index 878cdd09c3..223e00e45d 100644 --- a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java @@ -64,11 +64,7 @@ import org.apache.commons.logging.LogFactory; * * @author gkspencer */ -public class PassthruFtpAuthenticator implements FTPAuthenticator { - - // Logging - - protected static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol.auth"); +public class PassthruFtpAuthenticator extends FTPAuthenticatorBase { // Constants @@ -88,10 +84,6 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { private PasswordEncryptor m_passwordEncryptor; - // Alfresco configuration section - - private AlfrescoConfigSection m_alfrescoConfig; - // Security configuration private SecurityConfigSection m_securityConfig; @@ -105,21 +97,13 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { */ public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException { + + super.initialize(config, params); - // Get the alfresco configuration section, required to get hold of various - // services/components - - m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection(AlfrescoConfigSection.SectionName); - // Get the security configuration, for domain mapping m_securityConfig = (SecurityConfigSection) config.getConfigSection(SecurityConfigSection.SectionName); - // Check that the required authentication classes are available - - if ( m_alfrescoConfig == null || getAuthenticationComponent() == null) - throw new InvalidConfigurationException("Authentication component not available"); - // Create the password encryptor m_passwordEncryptor = new PasswordEncryptor(); @@ -354,6 +338,11 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { // Perform passthru authentication check authSts = doPassthruUserAuthentication(client, sess); + + // Check if the user is an administrator + + if ( authSts == true && client.getLogonType() == ClientInfo.LogonNormal) + checkForAdminUserName( client); } catch (Exception ex) { if ( logger.isDebugEnabled()) @@ -475,6 +464,7 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { // Passwords match, grant access authSts = true; + client.setLogonType( ClientInfo.LogonNormal); // Logging @@ -510,33 +500,6 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { return authSts; } - /** - * Return the authentication componenet - * - * @return AuthenticationComponent - */ - protected final AuthenticationComponent getAuthenticationComponent() { - return m_alfrescoConfig.getAuthenticationComponent(); - } - - /** - * Return the authentication service - * - * @return AuthenticationService - */ - protected final AuthenticationService getAuthenticationService() { - return m_alfrescoConfig.getAuthenticationService(); - } - - /** - * Return the transaction service - * - * @return TransactionService - */ - protected final TransactionService getTransactionService() { - return m_alfrescoConfig.getTransactionService(); - } - /** * Map a client IP address to a domain * @@ -582,6 +545,8 @@ public class PassthruFtpAuthenticator implements FTPAuthenticator { */ public void closeAuthenticator() { + super.closeAuthenticator(); + // Close the passthru authentication server list if ( m_passthruServers != null) diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java index 5a10cff2cf..faa8eadadb 100644 --- a/source/java/org/alfresco/filesys/avm/AVMContext.java +++ b/source/java/org/alfresco/filesys/avm/AVMContext.java @@ -92,6 +92,10 @@ public class AVMContext extends AlfrescoContext private StringList m_newStores; private Object m_newStoresLock; + // Allow admin user to write to web project staging stores + + private boolean m_allowAdminStagingWrites; + /** * Class constructor * @@ -182,6 +186,24 @@ public class AVMContext extends AlfrescoContext return m_virtualView; } + /** + * Check if the admin user is allowed to write to web project staging stores + * + * @return boolean + */ + public final boolean allowAdminStagingWrites() { + return m_allowAdminStagingWrites; + } + + /** + * Set the admin web project staging store writeable status + * + * @param writeable boolean + */ + public final void setAllowAdminStaginWrites(boolean writeable) { + m_allowAdminStagingWrites = writeable; + } + /** * Check if there are any new stores queued for adding to the virtualization view * diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java index ed140e1fdd..518bfa86ea 100644 --- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java +++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java @@ -362,6 +362,11 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface context.enableStateTable(true, getStateReaper()); + // Check if the admin user should be allowed to write to the web project staging stores + + if ( cfg.getChild("adminWriteable") != null) + context.setAllowAdminStaginWrites( true); + // Plug the virtualization view context into the various store/version call back listeners // so that store/version pseudo folders can be kept in sync with AVM @@ -834,9 +839,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the filesystem is the virtualization view - if (ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) + if (ctx.isVirtualizationView()) { - throw new AccessDeniedException("Cannot create folder in store/version layer, " + params.getPath()); + if (storePath.isReadOnlyPseudoPath()) + throw new AccessDeniedException("Cannot create folder in store/version layer, " + params.getPath()); + else if ( storePath.isReadOnlyAccess()) + throw new AccessDeniedException("Cannot create folder " + params.getPath() + ", read-only path"); } // Create a new file @@ -910,9 +918,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the filesystem is the virtualization view - if (ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) + if (ctx.isVirtualizationView()) { - throw new AccessDeniedException("Cannot create file in store/version layer, " + params.getPath()); + if (storePath.isReadOnlyPseudoPath()) + throw new AccessDeniedException("Cannot create file in store/version layer, " + params.getPath()); + else if ( storePath.isReadOnlyAccess()) + throw new AccessDeniedException("Cannot create file " + params.getPath() + ", read-only path"); } else if (storePath.getVersion() != AVMContext.VERSION_HEAD) { @@ -1008,9 +1019,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the filesystem is the virtualization view - if (ctx.isVirtualizationView() && storePath.isPseudoPath()) + if (ctx.isVirtualizationView()) { - throw new AccessDeniedException("Cannot delete pseudo folder, " + dir); + if (storePath.isPseudoPath()) + throw new AccessDeniedException("Cannot delete folder in store/version layer, " + dir); + else if ( storePath.isReadOnlyAccess()) + throw new AccessDeniedException("Cannot delete folder " + dir + ", read-only path"); } // Make sure the path is to a folder before deleting it @@ -1080,9 +1094,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the filesystem is the virtualization view - if (ctx.isVirtualizationView() && storePath.isPseudoPath()) + if (ctx.isVirtualizationView()) { - throw new AccessDeniedException("Cannot delete pseudo file, " + name); + if (storePath.isPseudoPath()) + throw new AccessDeniedException("Cannot delete file in store/version layer, " + name); + else if ( storePath.isReadOnlyAccess()) + throw new AccessDeniedException("Cannot delete file " + name + ", read-only path"); } // Make sure the path is to a file before deleting it @@ -1609,9 +1626,14 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Check if the filesystem is the virtualization view - if (ctx.isVirtualizationView() && oldAVMPath.isReadOnlyPseudoPath()) + if (ctx.isVirtualizationView()) { - throw new AccessDeniedException("Cannot rename folder in store/version layer, " + oldName); + if ( oldAVMPath.isReadOnlyPseudoPath()) + throw new AccessDeniedException("Cannot rename folder in store/version layer, " + oldName); + else if ( newAVMPath.isReadOnlyPseudoPath()) + throw new AccessDeniedException("Cannot rename folder to store/version layer, " + newName); + else if ( newAVMPath.isReadOnlyAccess()) + throw new AccessDeniedException("Cannot rename folder to read-only folder, " + newName); } // Start a transaction for the rename @@ -1701,7 +1723,12 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // If this is not the head version then it's not writable AVMContext avmCtx = (AVMContext) tree.getContext(); - if (avmCtx.isVersion() != AVMContext.VERSION_HEAD) + + // Parse the path + + AVMPath storePath = buildStorePath(avmCtx, name, sess); + + if (avmCtx.isVersion() != AVMContext.VERSION_HEAD || storePath.isReadOnlyAccess()) throw new AccessDeniedException("Store not writable, cannot set delete on close"); } } @@ -2757,13 +2784,14 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Allow access to the root folder - if ( avmPath.isLevel() == AVMPath.LevelId.Root) + if ( avmPath.isLevel() == AVMPath.LevelId.Root) { + + // Allow read only access to the root + + avmPath.setReadOnlyAccess( true); return; + } - // Admin user has full access - - if ( cInfo.getUserName().equalsIgnoreCase( m_authComponent.getSystemUserName())) - return; // Get root file state, get the store pseudo folder details @@ -2798,7 +2826,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface throw new AccessDeniedException("User " + cInfo.getUserName() + " has no access to web project, " + webFolder.getFileName()); } - else if ( role == WebProjectStorePseudoFile.RolePublisher) + else if ( avmCtx.allowAdminStagingWrites() && cInfo.isAdministrator()) + { + // Allow admin write access + + avmPath.setReadOnlyAccess( false); + } + else { // Only allow read-only access to the staging area diff --git a/source/java/org/alfresco/repo/action/ActionConditionImpl.java b/source/java/org/alfresco/repo/action/ActionConditionImpl.java index 591f5d2593..920a6fe703 100644 --- a/source/java/org/alfresco/repo/action/ActionConditionImpl.java +++ b/source/java/org/alfresco/repo/action/ActionConditionImpl.java @@ -41,7 +41,7 @@ public class ActionConditionImpl extends ParameterizedItemImpl implements Serial private static final long serialVersionUID = 3257288015402644020L; /** - * Rule condition defintion + * Rule condition definition */ private String actionConditionDefinitionName; @@ -63,7 +63,7 @@ public class ActionConditionImpl extends ParameterizedItemImpl implements Serial * @param parameterValues */ public ActionConditionImpl( - String id, + String id, String actionConditionDefinitionName, Map parameterValues) { diff --git a/source/java/org/alfresco/repo/action/ActionModel.java b/source/java/org/alfresco/repo/action/ActionModel.java index 37b3aa0bbc..036e380e52 100644 --- a/source/java/org/alfresco/repo/action/ActionModel.java +++ b/source/java/org/alfresco/repo/action/ActionModel.java @@ -12,14 +12,18 @@ public interface ActionModel static final QName PROP_ACTION_DESCRIPTION = QName.createQName(ACTION_MODEL_URI, "actionDescription"); static final QName PROP_EXECUTE_ASYNCHRONOUSLY = QName.createQName(ACTION_MODEL_URI, "executeAsynchronously"); static final QName ASSOC_CONDITIONS = QName.createQName(ACTION_MODEL_URI, "conditions"); + static final QName ASSOC_COMPENSATING_ACTION = QName.createQName(ACTION_MODEL_URI, "compensatingAction"); static final QName ASSOC_PARAMETERS = QName.createQName(ACTION_MODEL_URI, "parameters"); static final QName TYPE_ACTION_CONDITION = QName.createQName(ACTION_MODEL_URI, "actioncondition"); + static final QName TYPE_COMPOSITE_ACTION_CONDITION = QName.createQName(ACTION_MODEL_URI, "compositeactioncondition"); + static final QName TYPE_ACTION_PARAMETER = QName.createQName(ACTION_MODEL_URI, "actionparameter"); static final QName PROP_PARAMETER_NAME = QName.createQName(ACTION_MODEL_URI, "parameterName"); static final QName PROP_PARAMETER_VALUE = QName.createQName(ACTION_MODEL_URI, "parameterValue"); static final QName TYPE_COMPOSITE_ACTION = QName.createQName(ACTION_MODEL_URI, "compositeaction"); static final QName ASSOC_ACTIONS = QName.createQName(ACTION_MODEL_URI, "actions"); + static final QName ASSOC_COMPOSITE_ACTION_CONDITION = QName.createQName(ACTION_MODEL_URI, "compositeconditions"); static final QName ASPECT_ACTIONS = QName.createQName(ACTION_MODEL_URI, "actions"); static final QName ASSOC_ACTION_FOLDER = QName.createQName(ACTION_MODEL_URI, "actionFolder"); @@ -30,5 +34,9 @@ public interface ActionModel //static final QName ASSOC_SAVED_ACTIONS = QName.createQName(ACTION_MODEL_URI, "savedActions"); static final QName PROP_CONDITION_INVERT = QName.createQName(ACTION_MODEL_URI, "invert"); + static final QName PROP_CONDITION_ANDOR = QName.createQName(ACTION_MODEL_URI, "or"); -} \ No newline at end of file + /** Action assoc name */ + public static final QName ASSOC_NAME_ACTIONS = QName.createQName(ACTION_MODEL_URI, "actions"); + +} diff --git a/source/java/org/alfresco/repo/action/ActionServiceImpl.java b/source/java/org/alfresco/repo/action/ActionServiceImpl.java index 1a1a48b71c..c292fd3a3f 100644 --- a/source/java/org/alfresco/repo/action/ActionServiceImpl.java +++ b/source/java/org/alfresco/repo/action/ActionServiceImpl.java @@ -37,7 +37,6 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.action.evaluator.ActionConditionEvaluator; import org.alfresco.repo.action.executer.ActionExecuter; import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionCondition; @@ -46,6 +45,7 @@ import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ActionServiceException; import org.alfresco.service.cmr.action.CompositeAction; +import org.alfresco.service.cmr.action.CompositeActionCondition; import org.alfresco.service.cmr.action.ParameterizedItem; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -71,99 +71,96 @@ import org.springframework.context.ApplicationContextAware; public class ActionServiceImpl implements ActionService, RuntimeActionService, ApplicationContextAware { /** - * Transaction resource name - */ - private static final String POST_TRANSACTION_PENDING_ACTIONS = "postTransactionPendingActions"; - - /** - * Error message - */ - private static final String ERR_FAIL = "The action failed to execute due to an error."; - - /** Action assoc name */ - private static final QName ASSOC_NAME_ACTIONS = QName.createQName(ActionModel.ACTION_MODEL_URI, "actions"); - - /** + * Transaction resource name + */ + private static final String POST_TRANSACTION_PENDING_ACTIONS = "postTransactionPendingActions"; + + /** + * Error message + */ + private static final String ERR_FAIL = "The action failed to execute due to an error."; + + /** * The logger */ - private static Log logger = LogFactory.getLog(ActionServiceImpl.class); + private static Log logger = LogFactory.getLog(ActionServiceImpl.class); /** * Thread local containing the current action chain */ ThreadLocal> currentActionChain = new ThreadLocal>(); - - /** - * The application context - */ - private ApplicationContext applicationContext; + + /** + * The application context + */ + private ApplicationContext applicationContext; /** - * The node service - */ - private NodeService nodeService; - - /** - * The search service - */ - private SearchService searchService; + * The node service + */ + private NodeService nodeService; + + /** + * The search service + */ + private SearchService searchService; /** The dictionary service */ private DictionaryService dictionaryService; /** The authentication component */ private AuthenticationComponent authenticationComponent; - - /** - * The asynchronous action execution queues - * map of name, queue - */ - private Map asynchronousActionExecutionQueues; - - /** - * Action transaction listener - */ - private ActionTransactionListener transactionListener = new ActionTransactionListener(this); - - /** - * All the condition definitions currently registered - */ - private Map conditionDefinitions = new HashMap(); - - /** - * All the action definitions currently registered - */ - private Map actionDefinitions = new HashMap(); - - /** - * Set the application context - * - * @param applicationContext the application context - */ - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - this.applicationContext = applicationContext; - } + + /** + * The asynchronous action execution queues + * map of name, queue + */ + private Map asynchronousActionExecutionQueues; + + /** + * Action transaction listener + */ + private ActionTransactionListener transactionListener = new ActionTransactionListener(this); + + /** + * All the condition definitions currently registered + */ + private Map conditionDefinitions = new HashMap(); + + /** + * All the action definitions currently registered + */ + private Map actionDefinitions = new HashMap(); + + /** + * Set the application context + * + * @param applicationContext the application context + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } /** - * Set the node service - * - * @param nodeService the node service - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * Set the search service - * - * @param searchService the search service - */ - public void setSearchService(SearchService searchService) - { - this.searchService = searchService; - } + * Set the node service + * + * @param nodeService the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Set the search service + * + * @param searchService the search service + */ + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } /** * Set the authentication component @@ -184,44 +181,54 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A { this.dictionaryService = dictionaryService; } - - /** - * Set the asynchronous action execution queues - * - * @param asynchronousActionExecutionQueue the asynchronous action execution queues - */ - public void setAsynchronousActionExecutionQueues( - Map asynchronousActionExecutionQueues) - { - this.asynchronousActionExecutionQueues = asynchronousActionExecutionQueues; - } - + /** - * Gets the saved action folder reference - * - * @param nodeRef the node reference - * @return the node reference - */ - private NodeRef getSavedActionFolderRef(NodeRef nodeRef) - { - List assocs = this.nodeService.getChildAssocs( + * Set the asynchronous action execution queues + * + * @param asynchronousActionExecutionQueue the asynchronous action execution queues + */ + public void setAsynchronousActionExecutionQueues( + Map asynchronousActionExecutionQueues) + { + this.asynchronousActionExecutionQueues = asynchronousActionExecutionQueues; + } + +// /** +// * Get the asynchronous action execution queue +// * +// * @return the asynchronous action execution queue +// */ +// public AsynchronousActionExecutionQueue getAsynchronousActionExecutionQueue() +// { +// return asynchronousActionExecutionQueue; +// } +// + /** + * Gets the saved action folder reference + * + * @param nodeRef the node reference + * @return the node reference + */ + private NodeRef getSavedActionFolderRef(NodeRef nodeRef) + { + List assocs = this.nodeService.getChildAssocs( nodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_ACTION_FOLDER); - if (assocs.size() != 1) - { - throw new ActionServiceException("Unable to retrieve the saved action folder reference."); - } - - return assocs.get(0).getChildRef(); - } - - /** - * @see org.alfresco.service.cmr.action.ActionService#getActionDefinition(java.lang.String) - */ - public ActionDefinition getActionDefinition(String name) - { - // get direct access to action definition (i.e. ignoring public flag of executer) + if (assocs.size() != 1) + { + throw new ActionServiceException("Unable to retrieve the saved action folder reference."); + } + + return assocs.get(0).getChildRef(); + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#getActionDefinition(java.lang.String) + */ + public ActionDefinition getActionDefinition(String name) + { + // get direct access to action definition (i.e. ignoring public flag of executer) ActionDefinition definition = null; Object bean = this.applicationContext.getBean(name); if (bean != null && bean instanceof ActionExecuter) @@ -230,15 +237,15 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A definition = executer.getActionDefinition(); } return definition; - } + } - /** - * @see org.alfresco.service.cmr.action.ActionService#getActionDefinitions() - */ - public List getActionDefinitions() - { - return new ArrayList(this.actionDefinitions.values()); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#getActionDefinitions() + */ + public List getActionDefinitions() + { + return new ArrayList(this.actionDefinitions.values()); + } /** * @see org.alfresco.service.cmr.action.ActionService#getActionDefinitions(org.alfresco.service.cmr.repository.NodeRef) @@ -278,203 +285,292 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A } } - /** - * @see org.alfresco.service.cmr.action.ActionService#getActionConditionDefinition(java.lang.String) - */ - public ActionConditionDefinition getActionConditionDefinition(String name) - { - return this.conditionDefinitions.get(name); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#getActionConditionDefinition(java.lang.String) + */ + public ActionConditionDefinition getActionConditionDefinition(String name) + { + return this.conditionDefinitions.get(name); + } - /** - * @see org.alfresco.service.cmr.action.ActionService#getActionConditionDefinitions() - */ - public List getActionConditionDefinitions() - { - return new ArrayList(this.conditionDefinitions.values()); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#getActionConditionDefinitions() + */ + public List getActionConditionDefinitions() + { + return new ArrayList(this.conditionDefinitions.values()); + } - /** - * @see org.alfresco.service.cmr.action.ActionService#createActionCondition(java.lang.String) - */ - public ActionCondition createActionCondition(String name) - { - return new ActionConditionImpl(GUID.generate(), name); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#createActionCondition(java.lang.String) + */ + public ActionCondition createActionCondition(String name) + { + if (logger.isDebugEnabled()) + logger.debug("Creating Action Condition - [" + name + "]"); - /** - * @see org.alfresco.service.cmr.action.ActionService#createActionCondition(java.lang.String, java.util.Map) - */ - public ActionCondition createActionCondition(String name, Map params) - { - ActionCondition condition = createActionCondition(name); - condition.setParameterValues(params); - return condition; - } + if (CompositeActionCondition.COMPOSITE_CONDITION.equals(name)) + { + return new CompositeActionConditionImpl(GUID.generate()); + } + + return new ActionConditionImpl(GUID.generate(), name); + } - /** - * @see org.alfresco.service.cmr.action.ActionService#createAction() - */ - public Action createAction(String name) - { - return new ActionImpl(null, GUID.generate(),name, null); - } - - /** - * @see org.alfresco.service.cmr.action.ActionService#createAction(java.lang.String, java.util.Map) - */ - public Action createAction(String name, Map params) - { - Action action = createAction(name); - action.setParameterValues(params); - return action; - } + /** + * @see org.alfresco.service.cmr.action.ActionService#createActionCondition(java.lang.String, java.util.Map) + */ + public ActionCondition createActionCondition(String name, Map params) + { + ActionCondition condition = createActionCondition(name); + condition.setParameterValues(params); + return condition; + } - /** - * @see org.alfresco.service.cmr.action.ActionService#createCompositeAction() - */ - public CompositeAction createCompositeAction() - { - return new CompositeActionImpl(null, GUID.generate()); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#createAction() + */ + public Action createAction(String name) + { + return new ActionImpl(null, GUID.generate(),name, null); + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#createAction(java.lang.String, java.util.Map) + */ + public Action createAction(String name, Map params) + { + Action action = createAction(name); + action.setParameterValues(params); + return action; + } - /** - * @see org.alfresco.service.cmr.action.ActionService#evaluateAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) - */ - public boolean evaluateAction(Action action, NodeRef actionedUponNodeRef) - { - boolean result = true; - - if (action.hasActionConditions() == true) - { - List actionConditions = action.getActionConditions(); - for (ActionCondition condition : actionConditions) - { - result = result && evaluateActionCondition(condition, actionedUponNodeRef); - } - } - - return result; - } - - /** - * @see org.alfresco.service.cmr.action.ActionService#evaluateActionCondition(org.alfresco.service.cmr.action.ActionCondition, org.alfresco.service.cmr.repository.NodeRef) - */ - public boolean evaluateActionCondition(ActionCondition condition, NodeRef actionedUponNodeRef) - { - boolean result = false; + /** + * @see org.alfresco.service.cmr.action.ActionService#createCompositeAction() + */ + public CompositeAction createCompositeAction() + { + return new CompositeActionImpl(null, GUID.generate()); + } - // Evaluate the condition - ActionConditionEvaluator evaluator = (ActionConditionEvaluator)this.applicationContext.getBean(condition.getActionConditionDefinitionName()); - result = evaluator.evaluate(condition, actionedUponNodeRef); - - return result; - } - - /** - * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean) - */ - public void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions) - { - executeAction(action, actionedUponNodeRef, checkConditions, action.getExecuteAsychronously()); - } - - /** - * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean) - */ - public void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsychronously) - { + /** + * @see org.alfresco.service.cmr.action.ActionService#createCompositeActionCondition() + */ + public CompositeActionCondition createCompositeActionCondition() + { + return new CompositeActionConditionImpl(GUID.generate()); + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#evaluateAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) + */ + public boolean evaluateAction(Action action, NodeRef actionedUponNodeRef) + { + boolean result = true; + + if (action.hasActionConditions() == true) + { + List actionConditions = action.getActionConditions(); + for (ActionCondition condition : actionConditions) + { + boolean tempresult = evaluateActionCondition(condition, actionedUponNodeRef); + + if (logger.isDebugEnabled()) + logger.debug("\tCondition " + condition.getActionConditionDefinitionName() + " Result - " + tempresult); + + result = result && tempresult; + } + } + + if (logger.isDebugEnabled()) + logger.debug("\tAll Condition Evaluation Result - " + result); + + return result; + } + + /** + * Evaluates the actions by finding corresponding actionEvaluators in applicationContext (registered through Spring). + * Composite conditions are evaluated here as well. It is also possible to have composite actions inside composite actions. + * + * @see org.alfresco.service.cmr.action.ActionService#evaluateActionCondition(org.alfresco.service.cmr.action.ActionCondition, org.alfresco.service.cmr.repository.NodeRef) + */ + public boolean evaluateActionCondition(ActionCondition condition, NodeRef actionedUponNodeRef) + { + if (condition instanceof CompositeActionCondition) + { + CompositeActionCondition compositeCondition = (CompositeActionCondition) condition; + if (logger.isDebugEnabled()) + { + logger.debug("Evaluating Composite Condition - BOOLEAN CONDITION IS " + (compositeCondition.isORCondition()?"OR":"AND")); + } + + if (!compositeCondition.hasActionConditions()) + { + throw new IllegalStateException("CompositeActionCondition has no subconditions."); + } + + boolean result ; + if (compositeCondition.isORCondition()) + { + result = false; + } + else + { + result = true; + } + + for (ActionCondition simplecondition : compositeCondition.getActionConditions()) + { + if (logger.isDebugEnabled()) + { + logger.debug("Evaluating composite condition " + simplecondition.getActionConditionDefinitionName()); + } + + if (compositeCondition.isORCondition()) + { + result = result || evaluateSimpleCondition(simplecondition, actionedUponNodeRef); + + //Short circuit for the OR condition + if (result) break; + } + else + { + result = result && evaluateSimpleCondition(simplecondition, actionedUponNodeRef); + //Short circuit for the AND condition + if (!result) break; + } + } + + if (compositeCondition.getInvertCondition()) + { + return !result; + } + else + { + return result; + } + } + else + { + return evaluateSimpleCondition(condition, actionedUponNodeRef); + } + } + + private boolean evaluateSimpleCondition(ActionCondition condition, NodeRef actionedUponNodeRef) + { + if (logger.isDebugEnabled()) + { + logger.debug("Evaluating simple condition " + condition.getActionConditionDefinitionName()); + } + // Evaluate the condition + ActionConditionEvaluator evaluator = (ActionConditionEvaluator)this.applicationContext.getBean(condition.getActionConditionDefinitionName()); + return evaluator.evaluate(condition, actionedUponNodeRef); + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + public void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions) + { + executeAction(action, actionedUponNodeRef, checkConditions, action.getExecuteAsychronously()); + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + public void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsychronously) + { Set actionChain = this.currentActionChain.get(); - if (executeAsychronously == false) - { - executeActionImpl(action, actionedUponNodeRef, checkConditions, false, actionChain); - } - else - { - // Add to the post transaction pending action list - addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain); - } - } - - /** - * called by transaction service. - */ - public void postCommit() - { - for (PendingAction pendingAction : getPostTransactionPendingActions()) - { - queueAction(pendingAction); - } - } - - /** - * - */ - private void queueAction(PendingAction action) - { - // Get the right queue - AsynchronousActionExecutionQueue queue = getQueue(action.action); + if (executeAsychronously == false) + { + executeActionImpl(action, actionedUponNodeRef, checkConditions, false, actionChain); + } + else + { + // Add to the post transaction pending action list + addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain); + } + } + + /** + * called by transaction service. + */ + public void postCommit() + { + for (PendingAction pendingAction : getPostTransactionPendingActions()) + { + queueAction(pendingAction); + } + } + + /** + * + */ + private void queueAction(PendingAction action) + { + // Get the right queue + AsynchronousActionExecutionQueue queue = getQueue(action.action); - // Queue the action for execution - queue.executeAction( - this, - action.getAction(), - action.getActionedUponNodeRef(), - action.getCheckConditions(), + // Queue the action for execution + queue.executeAction( + this, + action.getAction(), + action.getActionedUponNodeRef(), + action.getCheckConditions(), action.getActionChain()); - } - - /** - * - * @param compensatingAction - * @param actionedUponNodeRef - */ - private void queueAction(Action compensatingAction, NodeRef actionedUponNodeRef) - { - // Get the right queue - AsynchronousActionExecutionQueue queue = getQueue(compensatingAction); - - // Queue the action for execution - queue.executeAction(this, compensatingAction, actionedUponNodeRef, false, null); - } - - private AsynchronousActionExecutionQueue getQueue(Action action) - { - ActionExecuter executer = (ActionExecuter)this.applicationContext.getBean(action.getActionDefinitionName()); - AsynchronousActionExecutionQueue queue = null; - - String queueName = executer.getQueueName(); - if(queueName == null) - { - queue = asynchronousActionExecutionQueues.get(""); - } - else - { - queue = asynchronousActionExecutionQueues.get(queueName); - } - if(queue == null) - { - // can't get queue - throw new ActionServiceException("Unable to get AsynchronousActionExecutionQueue name: "+ queueName); - } - - return queue; - } + } + + /** + * + * @param compensatingAction + * @param actionedUponNodeRef + */ + private void queueAction(Action compensatingAction, NodeRef actionedUponNodeRef) + { + // Get the right queue + AsynchronousActionExecutionQueue queue = getQueue(compensatingAction); + + // Queue the action for execution + queue.executeAction(this, compensatingAction, actionedUponNodeRef, false, null); + } + + private AsynchronousActionExecutionQueue getQueue(Action action) + { + ActionExecuter executer = (ActionExecuter)this.applicationContext.getBean(action.getActionDefinitionName()); + AsynchronousActionExecutionQueue queue = null; + + String queueName = executer.getQueueName(); + if(queueName == null) + { + queue = asynchronousActionExecutionQueues.get(""); + } + else + { + queue = asynchronousActionExecutionQueues.get(queueName); + } + if(queue == null) + { + // can't get queue + throw new ActionServiceException("Unable to get AsynchronousActionExecutionQueue name: "+ queueName); + } + + return queue; + } - /** - * @see org.alfresco.repo.action.RuntimeActionService#executeActionImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean, org.alfresco.service.cmr.repository.NodeRef) - */ - public void executeActionImpl( - Action action, - NodeRef actionedUponNodeRef, - boolean checkConditions, - boolean executedAsynchronously, + /** + * @see org.alfresco.repo.action.RuntimeActionService#executeActionImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef, boolean, org.alfresco.service.cmr.repository.NodeRef) + */ + public void executeActionImpl( + Action action, + NodeRef actionedUponNodeRef, + boolean checkConditions, + boolean executedAsynchronously, Set actionChain) - { + { if (logger.isDebugEnabled() == true) { - StringBuilder builder = new StringBuilder("Exceute action impl action chain = "); + StringBuilder builder = new StringBuilder("Execute action impl action chain = "); if (actionChain == null) { builder.append("null"); @@ -500,8 +596,8 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A logger.debug("Doing executeActionImpl"); } - try - { + try + { Set origActionChain = null; if (actionChain == null) @@ -522,12 +618,12 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A try { - // Check and execute now - if (checkConditions == false || evaluateAction(action, actionedUponNodeRef) == true) - { - // Execute the action - directActionExecution(action, actionedUponNodeRef); - } + // Check and execute now + if (checkConditions == false || evaluateAction(action, actionedUponNodeRef) == true) + { + // Execute the action + directActionExecution(action, actionedUponNodeRef); + } } finally { @@ -545,134 +641,133 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A logger.debug("Resetting the action chain."); } } - } - catch (Throwable exception) - { + } + catch (Throwable exception) + { // DH: No logging of the exception. Leave the logging decision to the client code, // which can handle the rethrown exception. - if (executedAsynchronously == true) - { - // If one is specified, queue the compensating action ready for execution - Action compensatingAction = action.getCompensatingAction(); - if (compensatingAction != null) - { + if (executedAsynchronously == true) + { + // If one is specified, queue the compensating action ready for execution + Action compensatingAction = action.getCompensatingAction(); + if (compensatingAction != null) + { // Set the current user ((ActionImpl)compensatingAction).setRunAsUser(currentUserName); - queueAction(compensatingAction, actionedUponNodeRef); - } - } - - // Rethrow the exception - if (exception instanceof RuntimeException) - { - throw (RuntimeException)exception; - } - else - { - throw new ActionServiceException(ERR_FAIL, exception); - } - - } + queueAction(compensatingAction, actionedUponNodeRef); + } + } + + // Rethrow the exception + if (exception instanceof RuntimeException) + { + throw (RuntimeException)exception; + } + else + { + throw new ActionServiceException(ERR_FAIL, exception); + } + + } } - } + } - /** - * @see org.alfresco.repo.action.RuntimeActionService#directActionExecution(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) - */ - public void directActionExecution(Action action, NodeRef actionedUponNodeRef) - { + /** + * @see org.alfresco.repo.action.RuntimeActionService#directActionExecution(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) + */ + public void directActionExecution(Action action, NodeRef actionedUponNodeRef) + { // Debug output if (logger.isDebugEnabled() == true) { logger.debug("The action is being executed as the user: " + this.authenticationComponent.getCurrentUserName()); } - // Get the action executer and execute - ActionExecuter executer = (ActionExecuter)this.applicationContext.getBean(action.getActionDefinitionName()); - executer.execute(action, actionedUponNodeRef); - } + // Get the action executer and execute + ActionExecuter executer = (ActionExecuter)this.applicationContext.getBean(action.getActionDefinitionName()); + executer.execute(action, actionedUponNodeRef); + } - /** - * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, NodeRef) - */ - public void executeAction(Action action, NodeRef actionedUponNodeRef) - { - executeAction(action, actionedUponNodeRef, true); - } + /** + * @see org.alfresco.service.cmr.action.ActionService#executeAction(org.alfresco.service.cmr.action.Action, NodeRef) + */ + public void executeAction(Action action, NodeRef actionedUponNodeRef) + { + executeAction(action, actionedUponNodeRef, true); + } - /** - * @see org.alfresco.repo.action.RuntimeActionService#registerActionConditionEvaluator(org.alfresco.repo.action.evaluator.ActionConditionEvaluator) - */ - public void registerActionConditionEvaluator(ActionConditionEvaluator actionConditionEvaluator) - { - ActionConditionDefinition cond = actionConditionEvaluator.getActionConditionDefintion(); - this.conditionDefinitions.put(cond.getName(), cond); - } + /** + * @see org.alfresco.repo.action.RuntimeActionService#registerActionConditionEvaluator(org.alfresco.repo.action.evaluator.ActionConditionEvaluator) + */ + public void registerActionConditionEvaluator(ActionConditionEvaluator actionConditionEvaluator) + { + ActionConditionDefinition cond = actionConditionEvaluator.getActionConditionDefintion(); + this.conditionDefinitions.put(cond.getName(), cond); + } - /** - * @see org.alfresco.repo.action.RuntimeActionService#registerActionExecuter(org.alfresco.repo.action.executer.ActionExecuter) - */ - public void registerActionExecuter(ActionExecuter actionExecuter) - { - ActionDefinition action = actionExecuter.getActionDefinition(); - this.actionDefinitions.put(action.getName(), action); - } - - /** - * Gets the action node ref from the action id - * - * @param nodeRef the node reference - * @param actionId the acition id - * @return the action node reference - */ - private NodeRef getActionNodeRefFromId(NodeRef nodeRef, String actionId) - { - NodeRef result = null; - - if (this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) - { - DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver(); - namespacePrefixResolver.registerNamespace(NamespaceService.SYSTEM_MODEL_PREFIX, NamespaceService.SYSTEM_MODEL_1_0_URI); - - List nodeRefs = searchService.selectNodes( - getSavedActionFolderRef(nodeRef), - "*[@sys:" + ContentModel.PROP_NODE_UUID.getLocalName() + "='" + actionId + "']", - null, - namespacePrefixResolver, - false); - if (nodeRefs.size() != 0) - { - result = nodeRefs.get(0); - } - } - - return result; - } + /** + * @see org.alfresco.repo.action.RuntimeActionService#registerActionExecuter(org.alfresco.repo.action.executer.ActionExecuter) + */ + public void registerActionExecuter(ActionExecuter actionExecuter) + { + ActionDefinition action = actionExecuter.getActionDefinition(); + this.actionDefinitions.put(action.getName(), action); + } + + /** + * Gets the action node ref from the action id + * + * @param nodeRef the node reference + * @param actionId the action id + * @return the action node reference + */ + private NodeRef getActionNodeRefFromId(NodeRef nodeRef, String actionId) + { + NodeRef result = null; + + if (this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) + { + DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver(); + namespacePrefixResolver.registerNamespace(NamespaceService.SYSTEM_MODEL_PREFIX, NamespaceService.SYSTEM_MODEL_1_0_URI); + + List nodeRefs = searchService.selectNodes( + getSavedActionFolderRef(nodeRef), + "*[@sys:" + ContentModel.PROP_NODE_UUID.getLocalName() + "='" + actionId + "']", + null, + namespacePrefixResolver, + false); + if (nodeRefs.size() != 0) + { + result = nodeRefs.get(0); + } + } + + return result; + } - /** - * @see org.alfresco.service.cmr.action.ActionService#saveAction(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) - */ - public void saveAction(NodeRef nodeRef, Action action) - { - NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, action.getId()); - if (actionNodeRef == null) - { - if (this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == false) - { - // Apply the actionable aspect - this.nodeService.addAspect(nodeRef, ActionModel.ASPECT_ACTIONS, null); - } - - // Create the action nod reference + /** + * @see org.alfresco.service.cmr.action.ActionService#saveAction(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) + */ + public void saveAction(NodeRef nodeRef, Action action) + { + NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, action.getId()); + if (actionNodeRef == null) + { + if (this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == false) + { + // Apply the actionable aspect + this.nodeService.addAspect(nodeRef, ActionModel.ASPECT_ACTIONS, null); + } + + // Create the action and reference actionNodeRef = createActionNodeRef(action, getSavedActionFolderRef(nodeRef), ContentModel.ASSOC_CONTAINS, - ASSOC_NAME_ACTIONS); - } - - saveActionImpl(actionNodeRef, action); - } - + ActionModel.ASSOC_NAME_ACTIONS); + } + saveActionImpl(actionNodeRef, action); + } + public NodeRef createActionNodeRef(Action action, NodeRef parentNodeRef, QName assocTypeName, QName assocName) { Map props = new HashMap(2); @@ -701,202 +796,283 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A return actionNodeRef; } - /** - * @see org.alfresco.repo.action.RuntimeActionService#saveActionImpl(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) - */ - public void saveActionImpl(NodeRef actionNodeRef, Action action) - { + /** + * @see org.alfresco.repo.action.RuntimeActionService#saveActionImpl(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) + */ + public void saveActionImpl(NodeRef actionNodeRef, Action action) + { // Save action properties - saveActionProperties(actionNodeRef, action); - - // Update the parameters of the action - saveParameters(actionNodeRef, action); - - // Update the conditions of the action - saveConditions(actionNodeRef, action); - - if (action instanceof CompositeAction) - { - // Update composite action - saveActions(actionNodeRef, (CompositeAction)action); - } - - // Update the modified details - ((ActionImpl)action).setModifier((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_MODIFIER)); - ((ActionImpl)action).setModifiedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_MODIFIED)); - } + saveActionProperties(actionNodeRef, action); + + // Update the parameters of the action + saveParameters(actionNodeRef, action); + + // Update the conditions of the action + saveConditions(actionNodeRef, action); + + if (action instanceof CompositeAction) + { + // Update composite action + saveCompositeActions(actionNodeRef, (CompositeAction)action); + } + + // Update the modified details + ((ActionImpl)action).setModifier((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_MODIFIER)); + ((ActionImpl)action).setModifiedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_MODIFIED)); + } - /** - * Save the action property values - * - * @param actionNodeRef the action node reference - * @param action the action - */ - private void saveActionProperties(NodeRef actionNodeRef, Action action) - { - // Update the action property values - Map props = this.nodeService.getProperties(actionNodeRef); - props.put(ActionModel.PROP_ACTION_TITLE, action.getTitle()); - props.put(ActionModel.PROP_ACTION_DESCRIPTION, action.getDescription()); - props.put(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY, action.getExecuteAsychronously()); - this.nodeService.setProperties(actionNodeRef, props); - - // Update the compensating action (model should enforce the singularity of this association) - Action compensatingAction = action.getCompensatingAction(); - List assocs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPENSATING_ACTION); - if (assocs.size() == 0) - { - if (compensatingAction != null) - { - //Map props2 = new HashMap(2); - //props2.put(ActionModel.PROP_DEFINITION_NAME, compensatingAction.getActionDefinitionName()); - //props2.put(ContentModel.PROP_NODE_UUID, compensatingAction.getId()); - - //NodeRef compensatingActionNodeRef = this.nodeService.createNode( - /// actionNodeRef, - // ActionModel.ASSOC_COMPENSATING_ACTION, - // ActionModel.ASSOC_COMPENSATING_ACTION, - // ActionModel.TYPE_ACTION, - // props2).getChildRef(); + /** + * Save the action property values + * + * @param actionNodeRef the action node reference + * @param action the action + */ + private void saveActionProperties(NodeRef actionNodeRef, Action action) + { + // Update the action property values + Map props = this.nodeService.getProperties(actionNodeRef); + props.put(ActionModel.PROP_ACTION_TITLE, action.getTitle()); + props.put(ActionModel.PROP_ACTION_DESCRIPTION, action.getDescription()); + props.put(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY, action.getExecuteAsychronously()); + this.nodeService.setProperties(actionNodeRef, props); + + // Update the compensating action (model should enforce the singularity of this association) + Action compensatingAction = action.getCompensatingAction(); + List assocs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPENSATING_ACTION); + if (assocs.size() == 0) + { + if (compensatingAction != null) + { + //Map props2 = new HashMap(2); + //props2.put(ActionModel.PROP_DEFINITION_NAME, compensatingAction.getActionDefinitionName()); + //props2.put(ContentModel.PROP_NODE_UUID, compensatingAction.getId()); + + //NodeRef compensatingActionNodeRef = this.nodeService.createNode( + /// actionNodeRef, + // ActionModel.ASSOC_COMPENSATING_ACTION, + // ActionModel.ASSOC_COMPENSATING_ACTION, + // ActionModel.TYPE_ACTION, + // props2).getChildRef(); // Create the compensating node reference - NodeRef compensatingActionNodeRef = createActionNodeRef(compensatingAction, actionNodeRef, ActionModel.ASSOC_COMPENSATING_ACTION, ActionModel.ASSOC_COMPENSATING_ACTION); - saveActionImpl(compensatingActionNodeRef, compensatingAction); - } - } - else - { - ChildAssociationRef assoc = assocs.get(0); - if (compensatingAction == null) - { - this.nodeService.removeChild(actionNodeRef, assoc.getChildRef()); - } - else - { - saveActionImpl(assoc.getChildRef(), compensatingAction); - } - } - } + NodeRef compensatingActionNodeRef = createActionNodeRef(compensatingAction, actionNodeRef, ActionModel.ASSOC_COMPENSATING_ACTION, ActionModel.ASSOC_COMPENSATING_ACTION); + saveActionImpl(compensatingActionNodeRef, compensatingAction); + } + } + else + { + ChildAssociationRef assoc = assocs.get(0); + if (compensatingAction == null) + { + this.nodeService.removeChild(actionNodeRef, assoc.getChildRef()); + } + else + { + saveActionImpl(assoc.getChildRef(), compensatingAction); + } + } + } - /** - * Save the actions of a composite action - * - * @param compositeActionNodeRef the node reference of the coposite action - * @param compositeAction the composite action - */ - private void saveActions(NodeRef compositeActionNodeRef, CompositeAction compositeAction) - { - // TODO Need a way of sorting the order of the actions + /** + * Save the actions of a composite action + * + * @param compositeActionNodeRef the node reference of the composite action + * @param compositeAction the composite action + */ + private void saveCompositeActions(NodeRef compositeActionNodeRef, CompositeAction compositeAction) + { + // TODO Need a way of sorting the order of the actions - Map idToAction = new HashMap(); + Map idToAction = new HashMap(); List orderedIds = new ArrayList(); - for (Action action : compositeAction.getActions()) - { - idToAction.put(action.getId(), action); + for (Action action : compositeAction.getActions()) + { + idToAction.put(action.getId(), action); orderedIds.add(action.getId()); - } - - List actionRefs = this.nodeService.getChildAssocs(compositeActionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_ACTIONS); - for (ChildAssociationRef actionRef : actionRefs) - { - NodeRef actionNodeRef = actionRef.getChildRef(); - if (idToAction.containsKey(actionNodeRef.getId()) == false) - { - // Delete the action - this.nodeService.removeChild(compositeActionNodeRef, actionNodeRef); - } - else - { - // Update the action + } + + List actionRefs = this.nodeService.getChildAssocs(compositeActionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_ACTIONS); + for (ChildAssociationRef actionRef : actionRefs) + { + NodeRef actionNodeRef = actionRef.getChildRef(); + if (idToAction.containsKey(actionNodeRef.getId()) == false) + { + // Delete the action + this.nodeService.removeChild(compositeActionNodeRef, actionNodeRef); + } + else + { + // Update the action Action action = idToAction.get(actionNodeRef.getId()); - saveActionImpl(actionNodeRef, action); - orderedIds.remove(actionNodeRef.getId()); - } - - } - - // Create the actions remaining - for (String actionId : orderedIds) - { + saveActionImpl(actionNodeRef, action); + orderedIds.remove(actionNodeRef.getId()); + } + + } + + // Create the actions remaining + for (String actionId : orderedIds) + { Action action = idToAction.get(actionId); - Map props = new HashMap(2); - props.put(ActionModel.PROP_DEFINITION_NAME, action.getActionDefinitionName()); - props.put(ContentModel.PROP_NODE_UUID, action.getId()); - - NodeRef actionNodeRef = this.nodeService.createNode( - compositeActionNodeRef, + Map props = new HashMap(2); + props.put(ActionModel.PROP_DEFINITION_NAME, action.getActionDefinitionName()); + props.put(ContentModel.PROP_NODE_UUID, action.getId()); + + NodeRef actionNodeRef = this.nodeService.createNode( + compositeActionNodeRef, ActionModel.ASSOC_ACTIONS, ActionModel.ASSOC_ACTIONS, ActionModel.TYPE_ACTION, - props).getChildRef(); - - // Update the created details and the node reference - ((ActionImpl)action).setCreator((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATOR)); - ((ActionImpl)action).setCreatedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATED)); - ((ActionImpl)action).setNodeRef(actionNodeRef); - - saveActionImpl(actionNodeRef, action); - } - } - - /** - * Saves the conditions associated with an action - * - * @param actionNodeRef the action node reference - * @param action the action - */ - private void saveConditions(NodeRef actionNodeRef, Action action) - { - // TODO Need a way of sorting out the order of the conditions - - Map idToCondition = new HashMap(); - List orderedIds = new ArrayList(); - for (ActionCondition actionCondition : action.getActionConditions()) - { - idToCondition.put(actionCondition.getId(), actionCondition); - orderedIds.add(actionCondition.getId()); - } - - List conditionRefs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_CONDITIONS); - for (ChildAssociationRef conditionRef : conditionRefs) - { - NodeRef conditionNodeRef = conditionRef.getChildRef(); - if (idToCondition.containsKey(conditionNodeRef.getId()) == false) - { - // Delete the condition - this.nodeService.removeChild(actionNodeRef, conditionNodeRef); - } - else - { - saveConditionProperties(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); - - // Update the conditions parameters - saveParameters(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); - orderedIds.remove(conditionNodeRef.getId()); - } - - } - - // Create the conditions remaining - for (String nextId : orderedIds) - { - ActionCondition actionCondition = idToCondition.get(nextId); - Map props = new HashMap(2); - props.put(ActionModel.PROP_DEFINITION_NAME, actionCondition.getActionConditionDefinitionName()); - props.put(ContentModel.PROP_NODE_UUID, actionCondition.getId()); - - NodeRef conditionNodeRef = this.nodeService.createNode( - actionNodeRef, - ActionModel.ASSOC_CONDITIONS, - ActionModel.ASSOC_CONDITIONS, - ActionModel.TYPE_ACTION_CONDITION, - props).getChildRef(); + props).getChildRef(); - saveConditionProperties(conditionNodeRef, actionCondition); - saveParameters(conditionNodeRef, actionCondition); - } - } + // Update the created details and the node reference + ((ActionImpl)action).setCreator((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATOR)); + ((ActionImpl)action).setCreatedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATED)); + ((ActionImpl)action).setNodeRef(actionNodeRef); + + saveActionImpl(actionNodeRef, action); + } + } + + /** + * Saves the conditions associated with an action. + * + * @param actionNodeRef the action node reference + * @param action the action + */ + private void saveConditions(NodeRef actionNodeRef, Action action) + { + // TODO Need a way of sorting out the order of the conditions + List actionConditionsList = action.getActionConditions(); + saveActionConditionList(actionNodeRef, actionConditionsList, false); + } + + private void saveActionConditionList(NodeRef actionNodeRef, + List actionConditionsList, boolean isComposite) + { + if (logger.isDebugEnabled()) + logger.debug("SaveActionCondition list, "+ actionConditionsList.size() + + (isComposite?" Composite":"") + " conditions to be saved"); + + Map idToCondition = new HashMap(); + List orderedIds = new ArrayList(); + + for (ActionCondition actionCondition : actionConditionsList) + { + idToCondition.put(actionCondition.getId(), actionCondition); + orderedIds.add(actionCondition.getId()); + } + + List conditionRefs = this.nodeService.getChildAssocs( + actionNodeRef, RegexQNamePattern.MATCH_ALL, + !isComposite? ActionModel.ASSOC_CONDITIONS : ActionModel.ASSOC_COMPOSITE_ACTION_CONDITION); + + for (ChildAssociationRef conditionRef : conditionRefs) + { + NodeRef conditionNodeRef = conditionRef.getChildRef(); + if (idToCondition.containsKey(conditionNodeRef.getId()) == false) + { + // Delete the condition + this.nodeService.removeChild(actionNodeRef, conditionNodeRef); + } + else + { + saveConditionProperties(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); + // Update the conditions parameters + saveParameters(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); + orderedIds.remove(conditionNodeRef.getId()); + } + } + + // Create the conditions remaining + for (String nextId : orderedIds) + { + ActionCondition actionCondition = idToCondition.get(nextId); + + if (!isComposite && actionCondition instanceof CompositeActionCondition) + { + if (logger.isDebugEnabled()) + logger.debug("Saving Composite Condition"); + + NodeRef conditionNodeRef = saveActionCondition(actionNodeRef, actionCondition, + ActionModel.ASSOC_CONDITIONS, ActionModel.TYPE_COMPOSITE_ACTION_CONDITION); + saveActionConditionList(conditionNodeRef, ((CompositeActionCondition) actionCondition).getActionConditions(), true); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Saving Condition " + actionCondition.getActionConditionDefinitionName()); + + NodeRef conditionNodeRef = saveActionCondition(actionNodeRef, actionCondition, + !isComposite? ActionModel.ASSOC_CONDITIONS : ActionModel.ASSOC_COMPOSITE_ACTION_CONDITION, + ActionModel.TYPE_ACTION_CONDITION); + } + } + } + + /* + private void saveCompositeActionConditionList(NodeRef compositeConditionRef, + List actionConditionsList) + { + if (logger.isDebugEnabled()) + logger.debug("SaveActionCondition list Composite, "+ actionConditionsList.size() + " conditions to be saved"); + + Map idToCondition = new HashMap(); + List orderedIds = new ArrayList(); + + for (ActionCondition actionCondition : actionConditionsList) + { + idToCondition.put(actionCondition.getId(), actionCondition); + orderedIds.add(actionCondition.getId()); + } + + List conditionRefs = this.nodeService.getChildAssocs(compositeConditionRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_CONDITIONS); + for (ChildAssociationRef conditionRef : conditionRefs) + { + NodeRef conditionNodeRef = conditionRef.getChildRef(); + if (idToCondition.containsKey(conditionNodeRef.getId()) == false) + { + // Delete the condition + this.nodeService.removeChild(compositeConditionRef, conditionNodeRef); + } + else + { + saveConditionProperties(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); + // Update the conditions parameters + saveParameters(conditionNodeRef, idToCondition.get(conditionNodeRef.getId())); + orderedIds.remove(conditionNodeRef.getId()); + } + } + + // Create the conditions remaining + for (String nextId : orderedIds) + { + ActionCondition actionCondition = idToCondition.get(nextId); + NodeRef conditionNodeRef = saveActionCondition(compositeConditionRef, actionCondition, ActionModel.ASSOC_CONDITIONS, ActionModel.TYPE_ACTION_CONDITION); + + } + }*/ + + + private NodeRef saveActionCondition(NodeRef actionNodeRef, + ActionCondition actionCondition, QName AssociationQName, QName typeName) + { + Map props = new HashMap(2); + props.put(ActionModel.PROP_DEFINITION_NAME, actionCondition.getActionConditionDefinitionName()); + props.put(ContentModel.PROP_NODE_UUID, actionCondition.getId()); + + NodeRef conditionNodeRef = this.nodeService.createNode( + actionNodeRef, + AssociationQName, + AssociationQName, + typeName, + props).getChildRef(); + + saveConditionProperties(conditionNodeRef, actionCondition); + saveParameters(conditionNodeRef, actionCondition); + return conditionNodeRef; + } /** * Save the condition properties @@ -904,146 +1080,160 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A * @param conditionNodeRef * @param condition */ - private void saveConditionProperties(NodeRef conditionNodeRef, ActionCondition condition) + private void saveConditionProperties(NodeRef conditionNodeRef, ActionCondition condition) { this.nodeService.setProperty(conditionNodeRef, ActionModel.PROP_CONDITION_INVERT, condition.getInvertCondition()); + if (condition instanceof CompositeActionCondition) + { + if (logger.isDebugEnabled()) + { + logger.debug("SAVING OR = " + ((CompositeActionCondition)condition).isORCondition()); + } + this.nodeService.setProperty(conditionNodeRef, ActionModel.PROP_CONDITION_ANDOR, new Boolean(((CompositeActionCondition)condition).isORCondition())); + } } /** - * Saves the parameters associated with an action or condition - * - * @param parameterizedNodeRef the parameterized item node reference - * @param item the parameterized item - */ - private void saveParameters(NodeRef parameterizedNodeRef, ParameterizedItem item) - { - Map parameterMap = new HashMap(); - parameterMap.putAll(item.getParameterValues()); - - List parameters = this.nodeService.getChildAssocs(parameterizedNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_PARAMETERS); - for (ChildAssociationRef ref : parameters) - { - NodeRef paramNodeRef = ref.getChildRef(); - Map nodeRefParameterMap = this.nodeService.getProperties(paramNodeRef); - String paramName = (String)nodeRefParameterMap.get(ActionModel.PROP_PARAMETER_NAME); - if (parameterMap.containsKey(paramName) == false) - { - // Delete parameter from node ref - this.nodeService.removeChild(parameterizedNodeRef, paramNodeRef); - } - else - { - // Update the parameter value - nodeRefParameterMap.put(ActionModel.PROP_PARAMETER_VALUE, parameterMap.get(paramName)); - this.nodeService.setProperties(paramNodeRef, nodeRefParameterMap); - parameterMap.remove(paramName); - } - } - - // Add any remaing parameters - for (Map.Entry entry : parameterMap.entrySet()) - { - Map nodeRefProperties = new HashMap(2); - nodeRefProperties.put(ActionModel.PROP_PARAMETER_NAME, entry.getKey()); - nodeRefProperties.put(ActionModel.PROP_PARAMETER_VALUE, entry.getValue()); - - this.nodeService.createNode( - parameterizedNodeRef, + * Saves the parameters associated with an action or condition + * + * @param parameterizedNodeRef the parameterized item node reference + * @param item the parameterized item + */ + private void saveParameters(NodeRef parameterizedNodeRef, ParameterizedItem item) + { + Map parameterMap = new HashMap(); + parameterMap.putAll(item.getParameterValues()); + + List parameters = this.nodeService.getChildAssocs(parameterizedNodeRef, + RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_PARAMETERS); + for (ChildAssociationRef ref : parameters) + { + NodeRef paramNodeRef = ref.getChildRef(); + Map nodeRefParameterMap = this.nodeService.getProperties(paramNodeRef); + String paramName = (String)nodeRefParameterMap.get(ActionModel.PROP_PARAMETER_NAME); + if (parameterMap.containsKey(paramName) == false) + { + // Delete parameter from node ref + this.nodeService.removeChild(parameterizedNodeRef, paramNodeRef); + } + else + { + // Update the parameter value + nodeRefParameterMap.put(ActionModel.PROP_PARAMETER_VALUE, parameterMap.get(paramName)); + this.nodeService.setProperties(paramNodeRef, nodeRefParameterMap); + parameterMap.remove(paramName); + } + } + + // Add any remaining parameters + for (Map.Entry entry : parameterMap.entrySet()) + { + Map nodeRefProperties = new HashMap(2); + nodeRefProperties.put(ActionModel.PROP_PARAMETER_NAME, entry.getKey()); + nodeRefProperties.put(ActionModel.PROP_PARAMETER_VALUE, entry.getValue()); + + this.nodeService.createNode( + parameterizedNodeRef, ActionModel.ASSOC_PARAMETERS, ActionModel.ASSOC_PARAMETERS, ActionModel.TYPE_ACTION_PARAMETER, - nodeRefProperties); - } - } + nodeRefProperties); + } + } - /** - * @see org.alfresco.service.cmr.action.ActionService#getActions(org.alfresco.service.cmr.repository.NodeRef) - */ - public List getActions(NodeRef nodeRef) - { - List result = new ArrayList(); - - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) - { - List actions = this.nodeService.getChildAssocs( + /** + * @see org.alfresco.service.cmr.action.ActionService#getActions(org.alfresco.service.cmr.repository.NodeRef) + */ + public List getActions(NodeRef nodeRef) + { + List result = new ArrayList(); + + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) + { + List actions = this.nodeService.getChildAssocs( getSavedActionFolderRef(nodeRef), - RegexQNamePattern.MATCH_ALL, ASSOC_NAME_ACTIONS); - for (ChildAssociationRef action : actions) - { - NodeRef actionNodeRef = action.getChildRef(); - result.add(createAction(actionNodeRef)); - } - } - - return result; - } + RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_NAME_ACTIONS); + for (ChildAssociationRef action : actions) + { + NodeRef actionNodeRef = action.getChildRef(); + result.add(createAction(actionNodeRef)); + } + } + + return result; + } - /** - * Create an action from the action node reference - * - * @param actionNodeRef the action node reference - * @return the action - */ - public Action createAction(NodeRef actionNodeRef) - { - Action result = null; - - Map properties = this.nodeService.getProperties(actionNodeRef); - - QName actionType = this.nodeService.getType(actionNodeRef); - if (ActionModel.TYPE_COMPOSITE_ACTION.equals(actionType) == true) - { - // Create a composite action - result = new CompositeActionImpl(actionNodeRef, actionNodeRef.getId()); - populateCompositeAction(actionNodeRef, (CompositeAction)result); - } - else - { - // Create an action - result = new ActionImpl(actionNodeRef, actionNodeRef.getId(), (String)properties.get(ActionModel.PROP_DEFINITION_NAME)); - populateAction(actionNodeRef, result); - } - - return result; - } + /** + * Create an action from the action node reference + * + * @param actionNodeRef the action node reference + * @return the action + */ + public Action createAction(NodeRef actionNodeRef) + { + Action result = null; + + Map properties = this.nodeService.getProperties(actionNodeRef); + + QName actionType = this.nodeService.getType(actionNodeRef); + if (ActionModel.TYPE_COMPOSITE_ACTION.equals(actionType) == true) + { + // Create a composite action + result = new CompositeActionImpl(actionNodeRef, actionNodeRef.getId()); + populateCompositeAction(actionNodeRef, (CompositeAction)result); + } + else + { + // Create an action + result = new ActionImpl(actionNodeRef, actionNodeRef.getId(), (String)properties.get(ActionModel.PROP_DEFINITION_NAME)); + populateAction(actionNodeRef, result); + } + + return result; + } - /** - * Populate the details of the action from the node reference - * - * @param actionNodeRef the action node reference - * @param action the action - */ - private void populateAction(NodeRef actionNodeRef, Action action) - { - // Populate the action properties - populateActionProperties(actionNodeRef, action); - - // Set the parameters - populateParameters(actionNodeRef, action); - - // Set the conditions - List conditions = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_CONDITIONS); - for (ChildAssociationRef condition : conditions) - { - NodeRef conditionNodeRef = condition.getChildRef(); - action.addActionCondition(createActionCondition(conditionNodeRef)); - } - } + /** + * Populate the details of the action from the node reference + * + * @param actionNodeRef the action node reference + * @param action the action + */ + private void populateAction(NodeRef actionNodeRef, Action action) + { + // Populate the action properties + populateActionProperties(actionNodeRef, action); + + // Set the parameters + populateParameters(actionNodeRef, action); + + // Set the conditions + List conditions = this.nodeService.getChildAssocs(actionNodeRef, + RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_CONDITIONS); + + if (logger.isDebugEnabled()) + logger.debug("Retrieving " + (conditions==null ? " null" : conditions.size()) + " conditions"); - /** - * Populates the action properties from the node reference - * - * @param actionNodeRef the action node reference - * @param action the action - */ - private void populateActionProperties(NodeRef actionNodeRef, Action action) - { - Map props = this.nodeService.getProperties(actionNodeRef); - - action.setTitle((String)props.get(ActionModel.PROP_ACTION_TITLE)); - action.setDescription((String)props.get(ActionModel.PROP_ACTION_DESCRIPTION)); + for (ChildAssociationRef condition : conditions) + { + NodeRef conditionNodeRef = condition.getChildRef(); + action.addActionCondition(createActionCondition(conditionNodeRef)); + } + } + + /** + * Populates the action properties from the node reference + * + * @param actionNodeRef the action node reference + * @param action the action + */ + private void populateActionProperties(NodeRef actionNodeRef, Action action) + { + Map props = this.nodeService.getProperties(actionNodeRef); + + action.setTitle((String)props.get(ActionModel.PROP_ACTION_TITLE)); + action.setDescription((String)props.get(ActionModel.PROP_ACTION_DESCRIPTION)); boolean value = false; Boolean executeAsynchronously = (Boolean)props.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); @@ -1051,148 +1241,193 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A { value = executeAsynchronously.booleanValue(); } - action.setExecuteAsynchronously(value); - - ((ActionImpl)action).setCreator((String)props.get(ContentModel.PROP_CREATOR)); - ((ActionImpl)action).setCreatedDate((Date)props.get(ContentModel.PROP_CREATED)); - ((ActionImpl)action).setModifier((String)props.get(ContentModel.PROP_MODIFIER)); - ((ActionImpl)action).setModifiedDate((Date)props.get(ContentModel.PROP_MODIFIED)); - - // Get the compensating action - List assocs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPENSATING_ACTION); - if (assocs.size() != 0) - { - Action compensatingAction = createAction(assocs.get(0).getChildRef()); - action.setCompensatingAction(compensatingAction); - } - } - - /** - * Populate the parameteres of a parameterized item from the parameterized item node reference - * - * @param parameterizedItemNodeRef the parameterized item node reference - * @param parameterizedItem the parameterized item - */ - private void populateParameters(NodeRef parameterizedItemNodeRef, ParameterizedItem parameterizedItem) - { - List parameters = this.nodeService.getChildAssocs(parameterizedItemNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_PARAMETERS); - for (ChildAssociationRef parameter : parameters) - { - NodeRef parameterNodeRef = parameter.getChildRef(); - Map properties = this.nodeService.getProperties(parameterNodeRef); - parameterizedItem.setParameterValue( - (String)properties.get(ActionModel.PROP_PARAMETER_NAME), - properties.get(ActionModel.PROP_PARAMETER_VALUE)); - } - } - - /** - * Creates an action condition from an action condition node reference - * - * @param conditionNodeRef the condition node reference - * @return the action condition - */ - private ActionCondition createActionCondition(NodeRef conditionNodeRef) - { - Map properties = this.nodeService.getProperties(conditionNodeRef); - ActionCondition condition = new ActionConditionImpl(conditionNodeRef.getId(), (String)properties.get(ActionModel.PROP_DEFINITION_NAME)); + action.setExecuteAsynchronously(value); - boolean value = false; - Boolean invert = (Boolean)this.nodeService.getProperty(conditionNodeRef, ActionModel.PROP_CONDITION_INVERT); - if (invert != null) + ((ActionImpl)action).setCreator((String)props.get(ContentModel.PROP_CREATOR)); + ((ActionImpl)action).setCreatedDate((Date)props.get(ContentModel.PROP_CREATED)); + ((ActionImpl)action).setModifier((String)props.get(ContentModel.PROP_MODIFIER)); + ((ActionImpl)action).setModifiedDate((Date)props.get(ContentModel.PROP_MODIFIED)); + + // Get the compensating action + List assocs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPENSATING_ACTION); + if (assocs.size() != 0) { - value = invert.booleanValue(); + Action compensatingAction = createAction(assocs.get(0).getChildRef()); + action.setCompensatingAction(compensatingAction); } - condition.setInvertCondition(value); + } + + /** + * Populate the parameters of a parameterized item from the parameterized item node reference + * + * @param parameterizedItemNodeRef the parameterized item node reference + * @param parameterizedItem the parameterized item + */ + private void populateParameters(NodeRef parameterizedItemNodeRef, ParameterizedItem parameterizedItem) + { + List parameters = this.nodeService.getChildAssocs(parameterizedItemNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_PARAMETERS); + for (ChildAssociationRef parameter : parameters) + { + NodeRef parameterNodeRef = parameter.getChildRef(); + Map properties = this.nodeService.getProperties(parameterNodeRef); + parameterizedItem.setParameterValue( + (String)properties.get(ActionModel.PROP_PARAMETER_NAME), + properties.get(ActionModel.PROP_PARAMETER_VALUE)); + } + } + + /** + * Creates an action condition from an action condition node reference + * + * @param conditionNodeRef the condition node reference + * @return the action condition + */ + private ActionCondition createActionCondition(NodeRef conditionNodeRef) + { + if (logger.isDebugEnabled()) + logger.debug("\tCreateActionCondition: Retrieving Conditions from repository"); + + Map properties = this.nodeService.getProperties(conditionNodeRef); + QName conditionType = this.nodeService.getType(conditionNodeRef); - populateParameters(conditionNodeRef, condition); - return condition; - } + ActionCondition condition = null; + if (ActionModel.TYPE_COMPOSITE_ACTION_CONDITION.equals(conditionType) == false) + { + condition = new ActionConditionImpl(conditionNodeRef.getId(), + (String)properties.get(ActionModel.PROP_DEFINITION_NAME)); + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("\tRetrieving Composite Condition from repository"); + } + + // Create a composite condition + CompositeActionCondition compositeCondition = new CompositeActionConditionImpl(GUID.generate()); + populateCompositeActionCondition(conditionNodeRef, compositeCondition); + + condition = compositeCondition; + } - /** - * Populates a composite action from a composite action node reference - * - * @param compositeNodeRef the composite action node reference - * @param compositeAction the composite action - */ - public void populateCompositeAction(NodeRef compositeNodeRef, CompositeAction compositeAction) - { - populateAction(compositeNodeRef, compositeAction); - - List actions = this.nodeService.getChildAssocs(compositeNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_ACTIONS); - for (ChildAssociationRef action : actions) - { - NodeRef actionNodeRef = action.getChildRef(); - compositeAction.addAction(createAction(actionNodeRef)); - } - } + Boolean invert = (Boolean)this.nodeService.getProperty(conditionNodeRef, ActionModel.PROP_CONDITION_INVERT); + condition.setInvertCondition(invert == null? false: invert.booleanValue()); - /** - * @see org.alfresco.service.cmr.action.ActionService#getAction(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) - */ - public Action getAction(NodeRef nodeRef, String actionId) - { - Action result = null; - - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) - { - NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, actionId); - if (actionNodeRef != null) - { - result = createAction(actionNodeRef); - } - } - - return result; - } + populateParameters(conditionNodeRef, condition); + return condition; + } + + private void populateCompositeActionCondition(NodeRef compositeNodeRef, CompositeActionCondition compositeActionCondition) + { + List conditions = this.nodeService.getChildAssocs(compositeNodeRef, + RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPOSITE_ACTION_CONDITION); + + Boolean OR = (Boolean) this.nodeService.getProperty(compositeNodeRef, ActionModel.PROP_CONDITION_ANDOR); - /** - * @see org.alfresco.service.cmr.action.ActionService#removeAction(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) - */ - public void removeAction(NodeRef nodeRef, Action action) - { - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) - { - NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, action.getId()); - if (actionNodeRef != null) - { - this.nodeService.removeChild(getSavedActionFolderRef(nodeRef), actionNodeRef); - } - } - } + if (logger.isDebugEnabled()) + { + logger.debug("\tPopulating Composite Condition with subconditions, Condition OR = " + OR); + } - /** - * @see org.alfresco.service.cmr.action.ActionService#removeAllActions(org.alfresco.service.cmr.repository.NodeRef) - */ - public void removeAllActions(NodeRef nodeRef) - { - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) - { - List actions = new ArrayList(this.nodeService.getChildAssocs(getSavedActionFolderRef(nodeRef), RegexQNamePattern.MATCH_ALL, ASSOC_NAME_ACTIONS)); - for (ChildAssociationRef action : actions) - { - this.nodeService.removeChild(getSavedActionFolderRef(nodeRef), action.getChildRef()); - } - } - } - - /** - * Add a pending action to the list to be queued for execution once the transaction is completed. - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - * @param checkConditions indicates whether to check the conditions before execution - */ - @SuppressWarnings("unchecked") - private void addPostTransactionPendingAction( - Action action, - NodeRef actionedUponNodeRef, - boolean checkConditions, + compositeActionCondition.setORCondition(OR == null? false: OR.booleanValue()); + + for (ChildAssociationRef conditionNodeRef : conditions) + { + NodeRef actionNodeRef = conditionNodeRef.getChildRef(); + ActionCondition currentCondition = createActionCondition(actionNodeRef); + + if (logger.isDebugEnabled()) + logger.debug("\t\tAdding subcondition " + currentCondition.getActionConditionDefinitionName()); + + compositeActionCondition.addActionCondition(currentCondition); + } + } + + + /** + * Populates a composite action from a composite action node reference + * + * @param compositeNodeRef the composite action node reference + * @param compositeAction the composite action + */ + public void populateCompositeAction(NodeRef compositeNodeRef, CompositeAction compositeAction) + { + populateAction(compositeNodeRef, compositeAction); + + List actions = this.nodeService.getChildAssocs(compositeNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_ACTIONS); + for (ChildAssociationRef action : actions) + { + NodeRef actionNodeRef = action.getChildRef(); + compositeAction.addAction(createAction(actionNodeRef)); + } + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#getAction(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) + */ + public Action getAction(NodeRef nodeRef, String actionId) + { + Action result = null; + + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) + { + NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, actionId); + if (actionNodeRef != null) + { + result = createAction(actionNodeRef); + } + } + + return result; + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#removeAction(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) + */ + public void removeAction(NodeRef nodeRef, Action action) + { + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) + { + NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, action.getId()); + if (actionNodeRef != null) + { + this.nodeService.removeChild(getSavedActionFolderRef(nodeRef), actionNodeRef); + } + } + } + + /** + * @see org.alfresco.service.cmr.action.ActionService#removeAllActions(org.alfresco.service.cmr.repository.NodeRef) + */ + public void removeAllActions(NodeRef nodeRef) + { + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, ActionModel.ASPECT_ACTIONS) == true) + { + List actions = new ArrayList(this.nodeService.getChildAssocs(getSavedActionFolderRef(nodeRef), RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_NAME_ACTIONS)); + for (ChildAssociationRef action : actions) + { + this.nodeService.removeChild(getSavedActionFolderRef(nodeRef), action.getChildRef()); + } + } + } + + /** + * Add a pending action to the list to be queued for execution once the transaction is completed. + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + * @param checkConditions indicates whether to check the conditions before execution + */ + @SuppressWarnings("unchecked") + private void addPostTransactionPendingAction( + Action action, + NodeRef actionedUponNodeRef, + boolean checkConditions, Set actionChain) - { + { if (logger.isDebugEnabled() == true) { StringBuilder builder = new StringBuilder("addPostTransactionPendingAction action chain = "); @@ -1226,137 +1461,137 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A } ((ActionImpl)action).setRunAsUser(this.authenticationComponent.getCurrentUserName()); - // Ensure that the transaction listener is bound to the transaction - AlfrescoTransactionSupport.bindListener(this.transactionListener); - - // Add the pending action to the transaction resource - List pendingActions = (List)AlfrescoTransactionSupport.getResource(POST_TRANSACTION_PENDING_ACTIONS); - if (pendingActions == null) - { - pendingActions = new ArrayList(); - AlfrescoTransactionSupport.bindResource(POST_TRANSACTION_PENDING_ACTIONS, pendingActions); - } - - // Check that action has only been added to the list once - PendingAction pendingAction = new PendingAction(action, actionedUponNodeRef, checkConditions, actionChain); - if (pendingActions.contains(pendingAction) == false) - { - pendingActions.add(pendingAction); - } + // Ensure that the transaction listener is bound to the transaction + AlfrescoTransactionSupport.bindListener(this.transactionListener); + + // Add the pending action to the transaction resource + List pendingActions = (List)AlfrescoTransactionSupport.getResource(POST_TRANSACTION_PENDING_ACTIONS); + if (pendingActions == null) + { + pendingActions = new ArrayList(); + AlfrescoTransactionSupport.bindResource(POST_TRANSACTION_PENDING_ACTIONS, pendingActions); + } + + // Check that action has only been added to the list once + PendingAction pendingAction = new PendingAction(action, actionedUponNodeRef, checkConditions, actionChain); + if (pendingActions.contains(pendingAction) == false) + { + pendingActions.add(pendingAction); + } } - } - - /** - * @see org.alfresco.repo.action.RuntimeActionService#getPostTransactionPendingActions() - */ - @SuppressWarnings("unchecked") - private List getPostTransactionPendingActions() - { - return (List)AlfrescoTransactionSupport.getResource(POST_TRANSACTION_PENDING_ACTIONS); - } - - /** - * Pending action details class - */ - private class PendingAction - { - /** - * The action - */ - private Action action; - - /** - * The actioned upon node reference - */ - private NodeRef actionedUponNodeRef; - - /** - * Indicates whether the conditions should be checked before the action is executed - */ - private boolean checkConditions; + } + + /** + * @see org.alfresco.repo.action.RuntimeActionService#getPostTransactionPendingActions() + */ + @SuppressWarnings("unchecked") + private List getPostTransactionPendingActions() + { + return (List)AlfrescoTransactionSupport.getResource(POST_TRANSACTION_PENDING_ACTIONS); + } + + /** + * Pending action details class + */ + private class PendingAction + { + /** + * The action + */ + private Action action; + + /** + * The actioned upon node reference + */ + private NodeRef actionedUponNodeRef; + + /** + * Indicates whether the conditions should be checked before the action is executed + */ + private boolean checkConditions; private Set actionChain; - - /** - * Constructor - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - * @param checkConditions indicated whether the conditions need to be checked - */ - public PendingAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, Set actionChain) - { - this.action = action; - this.actionedUponNodeRef = actionedUponNodeRef; - this.checkConditions = checkConditions; + + /** + * Constructor + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + * @param checkConditions indicated whether the conditions need to be checked + */ + public PendingAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, Set actionChain) + { + this.action = action; + this.actionedUponNodeRef = actionedUponNodeRef; + this.checkConditions = checkConditions; this.actionChain = actionChain; - } - - /** - * Get the action - * - * @return the action - */ - public Action getAction() - { - return action; - } - - /** - * Get the actioned upon node reference - * - * @return the actioned upon node reference - */ - public NodeRef getActionedUponNodeRef() - { - return actionedUponNodeRef; - } - - /** - * Get the check conditions value - * - * @return indicates whether the condition should be checked - */ - public boolean getCheckConditions() - { - return this.checkConditions; - } + } + + /** + * Get the action + * + * @return the action + */ + public Action getAction() + { + return action; + } + + /** + * Get the actioned upon node reference + * + * @return the actioned upon node reference + */ + public NodeRef getActionedUponNodeRef() + { + return actionedUponNodeRef; + } + + /** + * Get the check conditions value + * + * @return indicates whether the condition should be checked + */ + public boolean getCheckConditions() + { + return this.checkConditions; + } public Set getActionChain() { return this.actionChain; } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - int hashCode = 37 * this.actionedUponNodeRef.hashCode(); - hashCode += 37 * this.action.hashCode(); - return hashCode; - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj instanceof PendingAction) - { - PendingAction that = (PendingAction) obj; - return (this.action.equals(that.action) && this.actionedUponNodeRef.equals(that.actionedUponNodeRef)); - } - else - { - return false; - } - } - } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + int hashCode = 37 * this.actionedUponNodeRef.hashCode(); + hashCode += 37 * this.action.hashCode(); + return hashCode; + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj instanceof PendingAction) + { + PendingAction that = (PendingAction) obj; + return (this.action.equals(that.action) && this.actionedUponNodeRef.equals(that.actionedUponNodeRef)); + } + else + { + return false; + } + } + } } diff --git a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java index 87c18c962a..8b60b01dfa 100644 --- a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java +++ b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java @@ -48,6 +48,7 @@ import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionConditionDefinition; import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.CompositeAction; +import org.alfresco.service.cmr.action.CompositeActionCondition; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; @@ -64,19 +65,19 @@ import org.alfresco.util.BaseAlfrescoSpringTest; */ public class ActionServiceImplTest extends BaseAlfrescoSpringTest { - private static final String BAD_NAME = "badName"; + private static final String BAD_NAME = "badName"; - private NodeRef nodeRef; + private NodeRef nodeRef; private NodeRef folder; - @Override - protected void onSetUpInTransaction() throws Exception - { - super.onSetUpInTransaction(); + @Override + protected void onSetUpInTransaction() throws Exception + { + super.onSetUpInTransaction(); // Create the node used for tests this.nodeRef = this.nodeService.createNode( - this.rootNodeRef, + this.rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}testnode"), ContentModel.TYPE_CONTENT).getChildRef(); @@ -90,29 +91,29 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest QName.createQName("{test}testFolder"), ContentModel.TYPE_FOLDER).getChildRef(); - } - - /** - * Test getActionDefinition - */ - public void testGetActionDefinition() - { - ActionDefinition action = actionService.getActionDefinition(AddFeaturesActionExecuter.NAME); - assertNotNull(action); - assertEquals(AddFeaturesActionExecuter.NAME, action.getName()); - - ActionConditionDefinition nullCondition = this.actionService.getActionConditionDefinition(BAD_NAME); - assertNull(nullCondition); - } + } - /** - * Test getActionDefintions - */ - public void testGetActionDefinitions() - { - List defintions = this.actionService.getActionDefinitions(); - assertNotNull(defintions); - assertFalse(defintions.isEmpty()); + /** + * Test getActionDefinition + */ + public void testGetActionDefinition() + { + ActionDefinition action = actionService.getActionDefinition(AddFeaturesActionExecuter.NAME); + assertNotNull(action); + assertEquals(AddFeaturesActionExecuter.NAME, action.getName()); + + ActionConditionDefinition nullCondition = this.actionService.getActionConditionDefinition(BAD_NAME); + assertNull(nullCondition); + } + + /** + * Test getActionDefintions + */ + public void testGetActionDefinitions() + { + List defintions = this.actionService.getActionDefinitions(); + assertNotNull(defintions); + assertFalse(defintions.isEmpty()); int totalCount = defintions.size(); for (ActionDefinition definition : defintions) @@ -124,261 +125,333 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest List definitions = this.actionService.getActionDefinitions(this.folder); assertNotNull(definitions); assertTrue(totalCount > definitions.size()); - } + } - /** - * Test getActionConditionDefinition - */ - public void testGetActionConditionDefinition() - { - ActionConditionDefinition condition = this.actionService.getActionConditionDefinition(NoConditionEvaluator.NAME); - assertNotNull(condition); - assertEquals(NoConditionEvaluator.NAME, condition.getName()); - - ActionConditionDefinition nullCondition = this.actionService.getActionConditionDefinition(BAD_NAME); - assertNull(nullCondition); - } + /** + * Test getActionConditionDefinition + */ + public void testGetActionConditionDefinition() + { + ActionConditionDefinition condition = this.actionService.getActionConditionDefinition(NoConditionEvaluator.NAME); + assertNotNull(condition); + assertEquals(NoConditionEvaluator.NAME, condition.getName()); + + ActionConditionDefinition nullCondition = this.actionService.getActionConditionDefinition(BAD_NAME); + assertNull(nullCondition); + } - /** - * Test getActionConditionDefinitions - * - */ - public void testGetActionConditionDefinitions() - { - List defintions = this.actionService.getActionConditionDefinitions(); - assertNotNull(defintions); - assertFalse(defintions.isEmpty()); + /** + * Test getActionConditionDefinitions + * + */ + public void testGetActionConditionDefinitions() + { + List defintions = this.actionService.getActionConditionDefinitions(); + assertNotNull(defintions); + assertFalse(defintions.isEmpty()); for (ActionConditionDefinition definition : defintions) { System.out.println(definition.getTitle()); } - } + } - /** - * Test create action condition - */ - public void testCreateActionCondition() - { - ActionCondition condition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); - assertNotNull(condition); - assertEquals(NoConditionEvaluator.NAME, condition.getActionConditionDefinitionName()); - } + /** + * Test create action condition + */ + public void testCreateActionCondition() + { + ActionCondition condition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); + assertNotNull(condition); + assertEquals(NoConditionEvaluator.NAME, condition.getActionConditionDefinitionName()); + } - /** - * Test createAction - */ - public void testCreateAction() - { - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - assertNotNull(action); - assertEquals(AddFeaturesActionExecuter.NAME, action.getActionDefinitionName()); - } + /** + * Test createCompositeAction + */ + public void testCreateCompositeActionCondition() + { + CompositeActionCondition action = this.actionService.createCompositeActionCondition(); + assertNotNull(action); + assertEquals(CompositeActionCondition.COMPOSITE_CONDITION, action.getActionConditionDefinitionName()); + } + + /** + * Test createAction + */ + public void testCreateAction() + { + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + assertNotNull(action); + assertEquals(AddFeaturesActionExecuter.NAME, action.getActionDefinitionName()); + } - /** - * Test createCompositeAction - */ - public void testCreateCompositeAction() - { - CompositeAction action = this.actionService.createCompositeAction(); - assertNotNull(action); - assertEquals(CompositeActionExecuter.NAME, action.getActionDefinitionName()); - } + /** + * Test createCompositeAction + */ + public void testCreateCompositeAction() + { + CompositeAction action = this.actionService.createCompositeAction(); + assertNotNull(action); + assertEquals(CompositeActionExecuter.NAME, action.getActionDefinitionName()); + } - /** - * Evaluate action - */ - public void testEvaluateAction() - { - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); - - ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); - action.addActionCondition(condition); - - assertFalse(this.actionService.evaluateAction(action, this.nodeRef)); - this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); - assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); - - ActionCondition condition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - condition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "my"); - action.addActionCondition(condition2); - assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); - - this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "document.doc"); - assertFalse(this.actionService.evaluateAction(action, this.nodeRef)); - } - - /** - * Test evaluate action condition - */ - public void testEvaluateActionCondition() - { - ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); - - assertFalse(this.actionService.evaluateActionCondition(condition, this.nodeRef)); - this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); - assertTrue(this.actionService.evaluateActionCondition(condition, this.nodeRef)); + /** + * Evaluate action + */ + public void testEvaluateAction() + { + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); + + ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + action.addActionCondition(condition); + + assertFalse(this.actionService.evaluateAction(action, this.nodeRef)); + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); + assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); + + ActionCondition condition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "my"); + action.addActionCondition(condition2); + assertTrue(this.actionService.evaluateAction(action, this.nodeRef)); + + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "document.doc"); + assertFalse(this.actionService.evaluateAction(action, this.nodeRef)); + } + + /** + * Test evaluate action condition + */ + public void testEvaluateActionCondition() + { + ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + + assertFalse(this.actionService.evaluateActionCondition(condition, this.nodeRef)); + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); + assertTrue(this.actionService.evaluateActionCondition(condition, this.nodeRef)); // Check that inverting the condition has the correct effect condition.setInvertCondition(true); assertFalse(this.actionService.evaluateActionCondition(condition, this.nodeRef)); - } - - /** - * Test execute action - */ - public void testExecuteAction() - { - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - - this.actionService.executeAction(action, this.nodeRef); - assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); - action.addActionCondition(condition); - - this.actionService.executeAction(action, this.nodeRef); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.actionService.executeAction(action, this.nodeRef, true); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.actionService.executeAction(action, this.nodeRef, false); - assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); - this.actionService.executeAction(action, this.nodeRef); - assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - // Create the composite action - Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); - Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - CompositeAction compAction = this.actionService.createCompositeAction(); - compAction.setTitle("title"); - compAction.setDescription("description"); - compAction.addAction(action1); - compAction.addAction(action2); - - // Execute the composite action - this.actionService.executeAction(compAction, this.nodeRef); - - assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_LOCKABLE)); - assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - } - - public void testGetAndGetAllWithNoActions() - { - assertNull(this.actionService.getAction(this.nodeRef, AddFeaturesActionExecuter.NAME)); - List actions = this.actionService.getActions(this.nodeRef); - assertNotNull(actions); - assertEquals(0, actions.size()); - } - - /** - * Test saving an action with no conditions. Includes testing storage and retrieval - * of compensating actions. - */ - public void testSaveActionNoCondition() - { - // Create the action - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - String actionId = action.getId(); - - // Set the parameters of the action - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - - // Set the title and description of the action - action.setTitle("title"); - action.setDescription("description"); - action.setExecuteAsynchronously(true); - - // Save the action - this.actionService.saveAction(this.nodeRef, action); - - // Get the action - Action savedAction = this.actionService.getAction(this.nodeRef, actionId); - - // Check the action - assertEquals(action.getId(), savedAction.getId()); - assertEquals(action.getActionDefinitionName(), savedAction.getActionDefinitionName()); - - // Check the properties - assertEquals("title", savedAction.getTitle()); - assertEquals("description", savedAction.getDescription()); - assertTrue(savedAction.getExecuteAsychronously()); - - // Check that the compensating action has not been set - assertNull(savedAction.getCompensatingAction()); - - // Check the properties - assertEquals(1, savedAction.getParameterValues().size()); - assertEquals(ContentModel.ASPECT_VERSIONABLE, savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); - - // Check the conditions - assertNotNull(savedAction.getActionConditions()); - assertEquals(0, savedAction.getActionConditions().size()); - - // Edit the properties of the action - Map properties = new HashMap(1); - properties.put(ContentModel.PROP_NAME, "testName"); - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_AUDITABLE); - - // Set the compensating action - Action compensatingAction = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - action.setCompensatingAction(compensatingAction); - - this.actionService.saveAction(this.nodeRef, action); - Action savedAction2 = this.actionService.getAction(this.nodeRef, actionId); - - // Check the updated properties - assertEquals(1, savedAction2.getParameterValues().size()); - assertEquals(ContentModel.ASPECT_AUDITABLE, savedAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); - - // Check the compensating action - Action savedCompensatingAction = savedAction2.getCompensatingAction(); - assertNotNull(savedCompensatingAction); - assertEquals(compensatingAction, savedCompensatingAction); - assertEquals(AddFeaturesActionExecuter.NAME, savedCompensatingAction.getActionDefinitionName()); - assertEquals(ContentModel.ASPECT_VERSIONABLE, savedCompensatingAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); - - // Change the details of the compensating action (edit and remove) - compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); - this.actionService.saveAction(this.nodeRef, action); - Action savedAction3 = this.actionService.getAction(this.nodeRef, actionId); - Action savedCompensatingAction2 = savedAction3.getCompensatingAction(); - assertNotNull(savedCompensatingAction2); - assertEquals(compensatingAction, savedCompensatingAction2); - assertEquals(AddFeaturesActionExecuter.NAME, savedCompensatingAction2.getActionDefinitionName()); - assertEquals(ContentModel.ASPECT_CLASSIFIABLE, savedCompensatingAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); - action.setCompensatingAction(null); - this.actionService.saveAction(this.nodeRef, action); - Action savedAction4 = this.actionService.getAction(this.nodeRef, actionId); - assertNull(savedAction4.getCompensatingAction()); - - //System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef)); - } + } + + /** + * Test evaluate action condition + */ + public void testEvaluateCompositeActionConditionWith1SubCondition() + { + CompositeActionCondition compositeCondition = this.actionService.createCompositeActionCondition(); + + ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + + compositeCondition.addActionCondition(condition); + + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); + assertTrue(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + + // Check that inverting the condition has the correct effect + compositeCondition.setInvertCondition(true); + assertFalse(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + } + + /** + * Test evaluate action condition + */ + public void testEvaluateCompositeActionConditionWith2SubConditions() + { + CompositeActionCondition compositeCondition = this.actionService.createCompositeActionCondition(); + + ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + + compositeCondition.addActionCondition(condition); + + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); + assertTrue(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + + ActionCondition conditionTwo = this.actionService.createActionCondition("compare-text-property"); + conditionTwo.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "Doc"); + conditionTwo.setParameterValue(ComparePropertyValueEvaluator.PARAM_PROPERTY, QName.createQName(null, "name")); + conditionTwo.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.CONTAINS.toString()); + + compositeCondition.addActionCondition(conditionTwo); + assertFalse(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + + compositeCondition.removeAllActionConditions(); + assertFalse(compositeCondition.hasActionConditions()); + + compositeCondition.addActionCondition(condition); + conditionTwo.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "NotFound"); + assertFalse(this.actionService.evaluateActionCondition(conditionTwo, this.nodeRef)); + + compositeCondition.addActionCondition(conditionTwo); + compositeCondition.setORCondition(true); + assertTrue(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + + compositeCondition.setORCondition(false); + assertFalse(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + + // Check that inverting the condition has the correct effect + compositeCondition.setInvertCondition(true); + assertTrue(this.actionService.evaluateActionCondition(compositeCondition, this.nodeRef)); + } + + /** + * Test execute action + */ + public void testExecuteAction() + { + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + + this.actionService.executeAction(action, this.nodeRef); + assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + ActionCondition condition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + action.addActionCondition(condition); + + this.actionService.executeAction(action, this.nodeRef); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.actionService.executeAction(action, this.nodeRef, true); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.actionService.executeAction(action, this.nodeRef, false); + assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.nodeService.setProperty(this.nodeRef, ContentModel.PROP_NAME, "myDocument.doc"); + this.actionService.executeAction(action, this.nodeRef); + assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + // Create the composite action + Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); + Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + CompositeAction compAction = this.actionService.createCompositeAction(); + compAction.setTitle("title"); + compAction.setDescription("description"); + compAction.addAction(action1); + compAction.addAction(action2); + + // Execute the composite action + this.actionService.executeAction(compAction, this.nodeRef); + + assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_LOCKABLE)); + assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + } + + public void testGetAndGetAllWithNoActions() + { + assertNull(this.actionService.getAction(this.nodeRef, AddFeaturesActionExecuter.NAME)); + List actions = this.actionService.getActions(this.nodeRef); + assertNotNull(actions); + assertEquals(0, actions.size()); + } + + /** + * Test saving an action with no conditions. Includes testing storage and retrieval + * of compensating actions. + */ + public void testSaveActionNoCondition() + { + // Create the action + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + String actionId = action.getId(); + + // Set the parameters of the action + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + + // Set the title and description of the action + action.setTitle("title"); + action.setDescription("description"); + action.setExecuteAsynchronously(true); + + // Save the action + this.actionService.saveAction(this.nodeRef, action); + + // Get the action + Action savedAction = this.actionService.getAction(this.nodeRef, actionId); + + // Check the action + assertEquals(action.getId(), savedAction.getId()); + assertEquals(action.getActionDefinitionName(), savedAction.getActionDefinitionName()); + + // Check the properties + assertEquals("title", savedAction.getTitle()); + assertEquals("description", savedAction.getDescription()); + assertTrue(savedAction.getExecuteAsychronously()); + + // Check that the compensating action has not been set + assertNull(savedAction.getCompensatingAction()); + + // Check the properties + assertEquals(1, savedAction.getParameterValues().size()); + assertEquals(ContentModel.ASPECT_VERSIONABLE, savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); + + // Check the conditions + assertNotNull(savedAction.getActionConditions()); + assertEquals(0, savedAction.getActionConditions().size()); + + // Edit the properties of the action + Map properties = new HashMap(1); + properties.put(ContentModel.PROP_NAME, "testName"); + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_AUDITABLE); + + // Set the compensating action + Action compensatingAction = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + action.setCompensatingAction(compensatingAction); + + this.actionService.saveAction(this.nodeRef, action); + Action savedAction2 = this.actionService.getAction(this.nodeRef, actionId); + + // Check the updated properties + assertEquals(1, savedAction2.getParameterValues().size()); + assertEquals(ContentModel.ASPECT_AUDITABLE, savedAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); + + // Check the compensating action + Action savedCompensatingAction = savedAction2.getCompensatingAction(); + assertNotNull(savedCompensatingAction); + assertEquals(compensatingAction, savedCompensatingAction); + assertEquals(AddFeaturesActionExecuter.NAME, savedCompensatingAction.getActionDefinitionName()); + assertEquals(ContentModel.ASPECT_VERSIONABLE, savedCompensatingAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); + + // Change the details of the compensating action (edit and remove) + compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); + this.actionService.saveAction(this.nodeRef, action); + Action savedAction3 = this.actionService.getAction(this.nodeRef, actionId); + Action savedCompensatingAction2 = savedAction3.getCompensatingAction(); + assertNotNull(savedCompensatingAction2); + assertEquals(compensatingAction, savedCompensatingAction2); + assertEquals(AddFeaturesActionExecuter.NAME, savedCompensatingAction2.getActionDefinitionName()); + assertEquals(ContentModel.ASPECT_CLASSIFIABLE, savedCompensatingAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); + action.setCompensatingAction(null); + this.actionService.saveAction(this.nodeRef, action); + Action savedAction4 = this.actionService.getAction(this.nodeRef, actionId); + assertNull(savedAction4.getCompensatingAction()); + + //System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef)); + } public void testOwningNodeRef() { @@ -404,181 +477,181 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest this.actionService.getAction(this.nodeRef, actionId); } - /** - * Test saving an action with conditions - */ - public void testSaveActionWithConditions() - { - // Create the action - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - String actionId = action.getId(); - - // Set the parameters of the action - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - - // Set the conditions of the action - ActionCondition actionCondition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); + /** + * Test saving an action with conditions + */ + public void testSaveActionWithConditions() + { + // Create the action + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + String actionId = action.getId(); + + // Set the parameters of the action + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + + // Set the conditions of the action + ActionCondition actionCondition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); actionCondition.setInvertCondition(true); - ActionCondition actionCondition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); - action.addActionCondition(actionCondition); - action.addActionCondition(actionCondition2); - - // Save the action - this.actionService.saveAction(this.nodeRef, action); - - // Get the action - Action savedAction = this.actionService.getAction(this.nodeRef, actionId); - - // Check the action - assertEquals(action.getId(), savedAction.getId()); - assertEquals(action.getActionDefinitionName(), savedAction.getActionDefinitionName()); - - // Check the properties - assertEquals(action.getParameterValues().size(), savedAction.getParameterValues().size()); - assertEquals(ContentModel.ASPECT_VERSIONABLE, savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); - - // Check the conditions - assertNotNull(savedAction.getActionConditions()); - assertEquals(2, savedAction.getActionConditions().size()); - for (ActionCondition savedCondition : savedAction.getActionConditions()) - { - if (savedCondition.getActionConditionDefinitionName().equals(NoConditionEvaluator.NAME) == true) - { - assertEquals(0, savedCondition.getParameterValues().size()); + ActionCondition actionCondition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.doc"); + action.addActionCondition(actionCondition); + action.addActionCondition(actionCondition2); + + // Save the action + this.actionService.saveAction(this.nodeRef, action); + + // Get the action + Action savedAction = this.actionService.getAction(this.nodeRef, actionId); + + // Check the action + assertEquals(action.getId(), savedAction.getId()); + assertEquals(action.getActionDefinitionName(), savedAction.getActionDefinitionName()); + + // Check the properties + assertEquals(action.getParameterValues().size(), savedAction.getParameterValues().size()); + assertEquals(ContentModel.ASPECT_VERSIONABLE, savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME)); + + // Check the conditions + assertNotNull(savedAction.getActionConditions()); + assertEquals(2, savedAction.getActionConditions().size()); + for (ActionCondition savedCondition : savedAction.getActionConditions()) + { + if (savedCondition.getActionConditionDefinitionName().equals(NoConditionEvaluator.NAME) == true) + { + assertEquals(0, savedCondition.getParameterValues().size()); assertTrue(savedCondition.getInvertCondition()); - } - else if (savedCondition.getActionConditionDefinitionName().equals(ComparePropertyValueEvaluator.NAME) == true) - { - assertEquals(1, savedCondition.getParameterValues().size()); - assertEquals("*.doc", savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE)); + } + else if (savedCondition.getActionConditionDefinitionName().equals(ComparePropertyValueEvaluator.NAME) == true) + { + assertEquals(1, savedCondition.getParameterValues().size()); + assertEquals("*.doc", savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE)); assertFalse(savedCondition.getInvertCondition()); - } - else - { - fail("There is a condition here that we are not expecting."); - } - } - - // Modify the conditions of the action - ActionCondition actionCondition3 = this.actionService.createActionCondition(InCategoryEvaluator.NAME); - actionCondition3.setParameterValue(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_OWNABLE); - action.addActionCondition(actionCondition3); - action.removeActionCondition(actionCondition); - actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.exe"); - actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS); - - this.actionService.saveAction(this.nodeRef, action); - Action savedAction2 = this.actionService.getAction(this.nodeRef, actionId); - - // Check that the conditions have been updated correctly - assertNotNull(savedAction2.getActionConditions()); - assertEquals(2, savedAction2.getActionConditions().size()); - for (ActionCondition savedCondition : savedAction2.getActionConditions()) - { - if (savedCondition.getActionConditionDefinitionName().equals(InCategoryEvaluator.NAME) == true) - { - assertEquals(1, savedCondition.getParameterValues().size()); - assertEquals(ContentModel.ASPECT_OWNABLE, savedCondition.getParameterValue(InCategoryEvaluator.PARAM_CATEGORY_ASPECT)); - } - else if (savedCondition.getActionConditionDefinitionName().equals(ComparePropertyValueEvaluator.NAME) == true) - { - assertEquals(2, savedCondition.getParameterValues().size()); - assertEquals("*.exe", savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE)); - assertEquals(ComparePropertyValueOperation.EQUALS, savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION)); - } - else - { - fail("There is a condition here that we are not expecting."); - } - } - - //System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef)); - } - - /** - * Test saving a composite action - */ - public void testSaveCompositeAction() - { - Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - Action action2 = this.actionService.createAction(CheckInActionExecuter.NAME); - - CompositeAction compositeAction = this.actionService.createCompositeAction(); - String actionId = compositeAction.getId(); - compositeAction.addAction(action1); - compositeAction.addAction(action2); - - this.actionService.saveAction(this.nodeRef, compositeAction); - assertEquals(1, this.actionService.getActions(this.nodeRef).size()); - CompositeAction savedCompositeAction = (CompositeAction)this.actionService.getAction(this.nodeRef, actionId); - - // Check the saved composite action - assertEquals(2, savedCompositeAction.getActions().size()); - for (Action action : savedCompositeAction.getActions()) - { - if (action.getActionDefinitionName().equals(AddFeaturesActionExecuter.NAME) == true) - { - assertEquals(action, action1); - } - else if (action.getActionDefinitionName().equals(CheckInActionExecuter.NAME) == true) - { - assertEquals(action, action2); - } - else - { - fail("We have an action here we are not expecting."); - } - } - - // Change the actions and re-save - compositeAction.removeAction(action1); - Action action3 = this.actionService.createAction(CheckOutActionExecuter.NAME); - compositeAction.addAction(action3); - action2.setParameterValue(CheckInActionExecuter.PARAM_DESCRIPTION, "description"); - - this.actionService.saveAction(this.nodeRef, compositeAction); - assertEquals(1, this.actionService.getActions(this.nodeRef).size()); - CompositeAction savedCompositeAction2 = (CompositeAction)this.actionService.getAction(this.nodeRef, actionId); - - assertEquals(2, savedCompositeAction2.getActions().size()); - for (Action action : savedCompositeAction2.getActions()) - { - if (action.getActionDefinitionName().equals(CheckOutActionExecuter.NAME) == true) - { - assertEquals(action, action3); - } - else if (action.getActionDefinitionName().equals(CheckInActionExecuter.NAME) == true) - { - assertEquals(action, action2); - assertEquals("description", action2.getParameterValue(CheckInActionExecuter.PARAM_DESCRIPTION)); - } - else - { - fail("We have an action here we are not expecting."); - } - } - } - - /** - * Test remove action - */ - public void testRemove() - { - assertEquals(0, this.actionService.getActions(this.nodeRef).size()); - - Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - this.actionService.saveAction(this.nodeRef, action1); - Action action2 = this.actionService.createAction(CheckInActionExecuter.NAME); - this.actionService.saveAction(this.nodeRef, action2); - assertEquals(2, this.actionService.getActions(this.nodeRef).size()); - - this.actionService.removeAction(this.nodeRef, action1); - assertEquals(1, this.actionService.getActions(this.nodeRef).size()); - - this.actionService.removeAllActions(this.nodeRef); - assertEquals(0, this.actionService.getActions(this.nodeRef).size()); - } + } + else + { + fail("There is a condition here that we are not expecting."); + } + } + + // Modify the conditions of the action + ActionCondition actionCondition3 = this.actionService.createActionCondition(InCategoryEvaluator.NAME); + actionCondition3.setParameterValue(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_OWNABLE); + action.addActionCondition(actionCondition3); + action.removeActionCondition(actionCondition); + actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, "*.exe"); + actionCondition2.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS); + + this.actionService.saveAction(this.nodeRef, action); + Action savedAction2 = this.actionService.getAction(this.nodeRef, actionId); + + // Check that the conditions have been updated correctly + assertNotNull(savedAction2.getActionConditions()); + assertEquals(2, savedAction2.getActionConditions().size()); + for (ActionCondition savedCondition : savedAction2.getActionConditions()) + { + if (savedCondition.getActionConditionDefinitionName().equals(InCategoryEvaluator.NAME) == true) + { + assertEquals(1, savedCondition.getParameterValues().size()); + assertEquals(ContentModel.ASPECT_OWNABLE, savedCondition.getParameterValue(InCategoryEvaluator.PARAM_CATEGORY_ASPECT)); + } + else if (savedCondition.getActionConditionDefinitionName().equals(ComparePropertyValueEvaluator.NAME) == true) + { + assertEquals(2, savedCondition.getParameterValues().size()); + assertEquals("*.exe", savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE)); + assertEquals(ComparePropertyValueOperation.EQUALS, savedCondition.getParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION)); + } + else + { + fail("There is a condition here that we are not expecting."); + } + } + + //System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef)); + } + + /** + * Test saving a composite action + */ + public void testSaveCompositeAction() + { + Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + Action action2 = this.actionService.createAction(CheckInActionExecuter.NAME); + + CompositeAction compositeAction = this.actionService.createCompositeAction(); + String actionId = compositeAction.getId(); + compositeAction.addAction(action1); + compositeAction.addAction(action2); + + this.actionService.saveAction(this.nodeRef, compositeAction); + assertEquals(1, this.actionService.getActions(this.nodeRef).size()); + CompositeAction savedCompositeAction = (CompositeAction)this.actionService.getAction(this.nodeRef, actionId); + + // Check the saved composite action + assertEquals(2, savedCompositeAction.getActions().size()); + for (Action action : savedCompositeAction.getActions()) + { + if (action.getActionDefinitionName().equals(AddFeaturesActionExecuter.NAME) == true) + { + assertEquals(action, action1); + } + else if (action.getActionDefinitionName().equals(CheckInActionExecuter.NAME) == true) + { + assertEquals(action, action2); + } + else + { + fail("We have an action here we are not expecting."); + } + } + + // Change the actions and re-save + compositeAction.removeAction(action1); + Action action3 = this.actionService.createAction(CheckOutActionExecuter.NAME); + compositeAction.addAction(action3); + action2.setParameterValue(CheckInActionExecuter.PARAM_DESCRIPTION, "description"); + + this.actionService.saveAction(this.nodeRef, compositeAction); + assertEquals(1, this.actionService.getActions(this.nodeRef).size()); + CompositeAction savedCompositeAction2 = (CompositeAction)this.actionService.getAction(this.nodeRef, actionId); + + assertEquals(2, savedCompositeAction2.getActions().size()); + for (Action action : savedCompositeAction2.getActions()) + { + if (action.getActionDefinitionName().equals(CheckOutActionExecuter.NAME) == true) + { + assertEquals(action, action3); + } + else if (action.getActionDefinitionName().equals(CheckInActionExecuter.NAME) == true) + { + assertEquals(action, action2); + assertEquals("description", action2.getParameterValue(CheckInActionExecuter.PARAM_DESCRIPTION)); + } + else + { + fail("We have an action here we are not expecting."); + } + } + } + + /** + * Test remove action + */ + public void testRemove() + { + assertEquals(0, this.actionService.getActions(this.nodeRef).size()); + + Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + this.actionService.saveAction(this.nodeRef, action1); + Action action2 = this.actionService.createAction(CheckInActionExecuter.NAME); + this.actionService.saveAction(this.nodeRef, action2); + assertEquals(2, this.actionService.getActions(this.nodeRef).size()); + + this.actionService.removeAction(this.nodeRef, action1); + assertEquals(1, this.actionService.getActions(this.nodeRef).size()); + + this.actionService.removeAllActions(this.nodeRef); + assertEquals(0, this.actionService.getActions(this.nodeRef).size()); + } public void testConditionOrder() { @@ -658,313 +731,313 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest * Test the action result parameter */ public void testActionResult() - { - // Create the script node reference - NodeRef script = this.nodeService.createNode( + { + // Create the script node reference + NodeRef script = this.nodeService.createNode( this.folder, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testScript.js"), ContentModel.TYPE_CONTENT).getChildRef(); - this.nodeService.setProperty(script, ContentModel.PROP_NAME, "testScript.js"); - ContentWriter contentWriter = this.contentService.getWriter(script, ContentModel.PROP_CONTENT, true); - contentWriter.setMimetype("text/plain"); - contentWriter.setEncoding("UTF-8"); - contentWriter.putContent("\"VALUE\";"); - - // Create the action - Action action1 = this.actionService.createAction(ScriptActionExecuter.NAME); - action1.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, script); - - // Execute the action - this.actionService.executeAction(action1, this.nodeRef); - - // Get the result - String result = (String)action1.getParameterValue(ActionExecuter.PARAM_RESULT); - assertNotNull(result); - assertEquals("VALUE", result); - } - - /** =================================================================================== - * Test asynchronous actions - */ - - /** - * Test asynchronous execute action - */ - public void testAsyncExecuteAction() - { - assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); - - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); - action.setExecuteAsynchronously(true); - - this.actionService.executeAction(action, this.nodeRef); - - setComplete(); - endTransaction(); - - final NodeService finalNodeService = this.nodeService; - final NodeRef finalNodeRef = this.nodeRef; - + this.nodeService.setProperty(script, ContentModel.PROP_NAME, "testScript.js"); + ContentWriter contentWriter = this.contentService.getWriter(script, ContentModel.PROP_CONTENT, true); + contentWriter.setMimetype("text/plain"); + contentWriter.setEncoding("UTF-8"); + contentWriter.putContent("\"VALUE\";"); + + // Create the action + Action action1 = this.actionService.createAction(ScriptActionExecuter.NAME); + action1.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, script); + + // Execute the action + this.actionService.executeAction(action1, this.nodeRef); + + // Get the result + String result = (String)action1.getParameterValue(ActionExecuter.PARAM_RESULT); + assertNotNull(result); + assertEquals("VALUE", result); + } + + /** =================================================================================== + * Test asynchronous actions + */ + + /** + * Test asynchronous execute action + */ + public void testAsyncExecuteAction() + { + assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE)); + + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); + action.setExecuteAsynchronously(true); + + this.actionService.executeAction(action, this.nodeRef); + + setComplete(); + endTransaction(); + + final NodeService finalNodeService = this.nodeService; + final NodeRef finalNodeRef = this.nodeRef; + postAsyncActionTest( this.transactionService, - 1000, - 10, - new AsyncTest() - { - public boolean executeTest() - { - return ( - finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_CLASSIFIABLE)); - }; - }); - } - - - - /** - * Test async composite action execution - */ - public void testAsyncCompositeActionExecute() - { - // Create the composite action - Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); - Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - CompositeAction compAction = this.actionService.createCompositeAction(); - compAction.setTitle("title"); - compAction.setDescription("description"); - compAction.addAction(action1); - compAction.addAction(action2); - compAction.setExecuteAsynchronously(true); - - // Execute the composite action - this.actionService.executeAction(compAction, this.nodeRef); - - setComplete(); - endTransaction(); - - final NodeService finalNodeService = this.nodeService; - final NodeRef finalNodeRef = this.nodeRef; - - postAsyncActionTest( + 1000, + 10, + new AsyncTest() + { + public boolean executeTest() + { + return ( + finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_CLASSIFIABLE)); + }; + }); + } + + + + /** + * Test async composite action execution + */ + public void testAsyncCompositeActionExecute() + { + // Create the composite action + Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); + Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + CompositeAction compAction = this.actionService.createCompositeAction(); + compAction.setTitle("title"); + compAction.setDescription("description"); + compAction.addAction(action1); + compAction.addAction(action2); + compAction.setExecuteAsynchronously(true); + + // Execute the composite action + this.actionService.executeAction(compAction, this.nodeRef); + + setComplete(); + endTransaction(); + + final NodeService finalNodeService = this.nodeService; + final NodeRef finalNodeRef = this.nodeRef; + + postAsyncActionTest( this.transactionService, - 1000, - 10, - new AsyncTest() - { - public boolean executeTest() - { - return ( - finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_VERSIONABLE) && - finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_LOCKABLE)); - }; - }); - } - - public void xtestAsyncLoadTest() - { - // TODO this is very weak .. how do we improve this ??? - - Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - action.setExecuteAsynchronously(true); - - for (int i = 0; i < 1000; i++) - { - this.actionService.executeAction(action, this.nodeRef); - } - - setComplete(); - endTransaction(); - - // TODO how do we assess whether the large number of actions stacked cause a problem ?? - } - - /** - * - * @param sleepTime - * @param maxTries - * @param test - * @param context - */ - public static void postAsyncActionTest( + 1000, + 10, + new AsyncTest() + { + public boolean executeTest() + { + return ( + finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_VERSIONABLE) && + finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_LOCKABLE)); + }; + }); + } + + public void xtestAsyncLoadTest() + { + // TODO this is very weak .. how do we improve this ??? + + Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); + action.setExecuteAsynchronously(true); + + for (int i = 0; i < 1000; i++) + { + this.actionService.executeAction(action, this.nodeRef); + } + + setComplete(); + endTransaction(); + + // TODO how do we assess whether the large number of actions stacked cause a problem ?? + } + + /** + * + * @param sleepTime + * @param maxTries + * @param test + * @param context + */ + public static void postAsyncActionTest( TransactionService transactionService, final long sleepTime, final int maxTries, final AsyncTest test) - { - try - { - int tries = 0; - boolean done = false; - while (done == false && tries < maxTries) - { - try - { - // Increment the tries counter - tries++; - - // Sleep for a bit - Thread.sleep(sleepTime); - - done = (transactionService.getRetryingTransactionHelper().doInTransaction( - new RetryingTransactionCallback() - { - public Boolean execute() - { - // See if the action has been performed + { + try + { + int tries = 0; + boolean done = false; + while (done == false && tries < maxTries) + { + try + { + // Increment the tries counter + tries++; + + // Sleep for a bit + Thread.sleep(sleepTime); + + done = (transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionCallback() + { + public Boolean execute() + { + // See if the action has been performed boolean done = test.executeTest(); return done; - } - })).booleanValue(); - } - catch (InterruptedException e) - { - // Do nothing - e.printStackTrace(); - } - } - - if (done == false) - { - throw new RuntimeException("Asynchronous action was not executed."); - } - } - catch (Throwable exception) - { - exception.printStackTrace(); - fail("An exception was encountered whilst checking the async action was executed: " + exception.getMessage()); - } - } - - /** - * Async test interface - */ - public interface AsyncTest - { - boolean executeTest(); - } - - /** =================================================================================== - * Test failure behaviour - */ - - /** - * Test sync failure behaviour - */ - public void testSyncFailureBehaviour() - { - // Create an action that is going to fail - Action action = this.actionService.createAction(MoveActionExecuter.NAME); - action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN); - action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); - // Create a bad node ref - NodeRef badNodeRef = new NodeRef(this.storeRef, "123123"); - action.setParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER, badNodeRef); - - try - { - this.actionService.executeAction(action, this.nodeRef); - - // Fail if we get there since the exception should have been raised - fail("An exception should have been raised."); - } - catch (RuntimeException exception) - { - // Good! The exception was raised correctly - } - - // Test what happens when a element of a composite action fails (should raise and bubble up to parent bahviour) - // Create the composite action - Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); - Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); - action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, QName.createQName("{test}badDogAspect")); - CompositeAction compAction = this.actionService.createCompositeAction(); - compAction.setTitle("title"); - compAction.setDescription("description"); - compAction.addAction(action1); - compAction.addAction(action2); - - try - { - // Execute the composite action - this.actionService.executeAction(compAction, this.nodeRef); - - fail("An exception should have been raised here !!"); - } - catch (RuntimeException runtimeException) - { - // Good! The exception was raised - } - } - - /** - * Test the compensating action - */ - public void testCompensatingAction() - { - // Create an action that is going to fail - final Action action = this.actionService.createAction(MoveActionExecuter.NAME); - action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN); - action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); - // Create a bad node ref - NodeRef badNodeRef = new NodeRef(this.storeRef, "123123"); - action.setParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER, badNodeRef); - action.setTitle("title"); - - // Create the compensating action - Action compensatingAction = actionService.createAction(AddFeaturesActionExecuter.NAME); - compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); - compensatingAction.setTitle("title"); - action.setCompensatingAction(compensatingAction); - - // Set the action to execute asynchronously - action.setExecuteAsynchronously(true); - - this.actionService.executeAction(action, this.nodeRef); - - setComplete(); - endTransaction(); - - postAsyncActionTest( + } + })).booleanValue(); + } + catch (InterruptedException e) + { + // Do nothing + e.printStackTrace(); + } + } + + if (done == false) + { + throw new RuntimeException("Asynchronous action was not executed."); + } + } + catch (Throwable exception) + { + exception.printStackTrace(); + fail("An exception was encountered whilst checking the async action was executed: " + exception.getMessage()); + } + } + + /** + * Async test interface + */ + public interface AsyncTest + { + boolean executeTest(); + } + + /** =================================================================================== + * Test failure behaviour + */ + + /** + * Test sync failure behaviour + */ + public void testSyncFailureBehaviour() + { + // Create an action that is going to fail + Action action = this.actionService.createAction(MoveActionExecuter.NAME); + action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN); + action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); + // Create a bad node ref + NodeRef badNodeRef = new NodeRef(this.storeRef, "123123"); + action.setParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER, badNodeRef); + + try + { + this.actionService.executeAction(action, this.nodeRef); + + // Fail if we get there since the exception should have been raised + fail("An exception should have been raised."); + } + catch (RuntimeException exception) + { + // Good! The exception was raised correctly + } + + // Test what happens when a element of a composite action fails (should raise and bubble up to parent bahviour) + // Create the composite action + Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_LOCKABLE); + Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, QName.createQName("{test}badDogAspect")); + CompositeAction compAction = this.actionService.createCompositeAction(); + compAction.setTitle("title"); + compAction.setDescription("description"); + compAction.addAction(action1); + compAction.addAction(action2); + + try + { + // Execute the composite action + this.actionService.executeAction(compAction, this.nodeRef); + + fail("An exception should have been raised here !!"); + } + catch (RuntimeException runtimeException) + { + // Good! The exception was raised + } + } + + /** + * Test the compensating action + */ + public void testCompensatingAction() + { + // Create an action that is going to fail + final Action action = this.actionService.createAction(MoveActionExecuter.NAME); + action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN); + action.setParameterValue(MoveActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); + // Create a bad node ref + NodeRef badNodeRef = new NodeRef(this.storeRef, "123123"); + action.setParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER, badNodeRef); + action.setTitle("title"); + + // Create the compensating action + Action compensatingAction = actionService.createAction(AddFeaturesActionExecuter.NAME); + compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); + compensatingAction.setTitle("title"); + action.setCompensatingAction(compensatingAction); + + // Set the action to execute asynchronously + action.setExecuteAsynchronously(true); + + this.actionService.executeAction(action, this.nodeRef); + + setComplete(); + endTransaction(); + + postAsyncActionTest( this.transactionService, - 1000, - 10, - new AsyncTest() - { - public boolean executeTest() - { - return ( - ActionServiceImplTest.this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CLASSIFIABLE)); - }; - }); - - // Modify the compensating action so that it will also fail - compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, QName.createQName("{test}badAspect")); - - this.transactionService.getRetryingTransactionHelper().doInTransaction( - new RetryingTransactionCallback() - { - public Object execute() - { - try - { - ActionServiceImplTest.this.actionService.executeAction(action, ActionServiceImplTest.this.nodeRef); - } - catch (RuntimeException exception) - { - // The exception should have been ignored and execution continued - exception.printStackTrace(); - fail("An exception should not have been raised here."); - } - return null; - } - - }); - - } + 1000, + 10, + new AsyncTest() + { + public boolean executeTest() + { + return ( + ActionServiceImplTest.this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CLASSIFIABLE)); + }; + }); + + // Modify the compensating action so that it will also fail + compensatingAction.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, QName.createQName("{test}badAspect")); + + this.transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionCallback() + { + public Object execute() + { + try + { + ActionServiceImplTest.this.actionService.executeAction(action, ActionServiceImplTest.this.nodeRef); + } + catch (RuntimeException exception) + { + // The exception should have been ignored and execution continued + exception.printStackTrace(); + fail("An exception should not have been raised here."); + } + return null; + } + + }); + + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/action/ActionServiceRemote.java b/source/java/org/alfresco/repo/action/ActionServiceRemote.java index ad894df39c..d9a392df65 100644 --- a/source/java/org/alfresco/repo/action/ActionServiceRemote.java +++ b/source/java/org/alfresco/repo/action/ActionServiceRemote.java @@ -37,6 +37,7 @@ import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ActionServiceTransport; import org.alfresco.service.cmr.action.CompositeAction; +import org.alfresco.service.cmr.action.CompositeActionCondition; import org.alfresco.service.cmr.repository.NodeRef; /** @@ -222,4 +223,9 @@ public class ActionServiceRemote implements ActionService { fTransport.saveAction(fHolder.getTicket(), nodeRef, action); } + + public CompositeActionCondition createCompositeActionCondition() + { + return null; + } } diff --git a/source/java/org/alfresco/repo/action/ActionTestSuite.java b/source/java/org/alfresco/repo/action/ActionTestSuite.java index 2844a9b853..4c02498be7 100644 --- a/source/java/org/alfresco/repo/action/ActionTestSuite.java +++ b/source/java/org/alfresco/repo/action/ActionTestSuite.java @@ -60,6 +60,7 @@ public class ActionTestSuite extends TestSuite suite.addTestSuite(ActionConditionImplTest.class); suite.addTestSuite(CompositeActionImplTest.class); suite.addTestSuite(ActionServiceImplTest.class); + suite.addTestSuite(CompositeActionConditionImplTest.class); // Test evaluators suite.addTestSuite(IsSubTypeEvaluatorTest.class); diff --git a/source/java/org/alfresco/repo/action/CompositeActionConditionImpl.java b/source/java/org/alfresco/repo/action/CompositeActionConditionImpl.java new file mode 100644 index 0000000000..e97d4c00c6 --- /dev/null +++ b/source/java/org/alfresco/repo/action/CompositeActionConditionImpl.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2008 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.action; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.cmr.action.CompositeActionCondition; + +/** + * Composite action condition implementation + * + * @author Jean Barmash + */ + +public class CompositeActionConditionImpl extends ActionConditionImpl implements CompositeActionCondition +{ + + public CompositeActionConditionImpl(String id) + { + super(id, CompositeActionCondition.COMPOSITE_CONDITION); + } + + private static final long serialVersionUID = -5987435419674390938L; + + /** + * The actionCondition list + */ + private List actionConditions = new ArrayList(); + + private static Boolean OR = true; + private static Boolean AND = false; + + private Boolean AndOr = AND; + + public void addActionCondition(ActionCondition actionCondition) + { + this.actionConditions.add(actionCondition); + } + + public void addActionCondition(int index, ActionCondition actionCondition) + { + this.actionConditions.add(index, actionCondition); + } + + public ActionCondition getActionCondition(int index) + { + return this.actionConditions.get(index); + } + + public List getActionConditions() + { + return this.actionConditions; + } + + public boolean hasActionConditions() + { + return (this.actionConditions.isEmpty() == false); + } + + public int indexOfActionCondition(ActionCondition actionCondition) + { + return this.actionConditions.indexOf(actionCondition); + } + + public void removeActionCondition(ActionCondition actionCondition) + { + this.actionConditions.remove(actionCondition); + } + + public void removeAllActionConditions() + { + this.actionConditions.clear(); + } + + public void setActionCondition(int index, ActionCondition actionCondition) + { + this.actionConditions.set(index, actionCondition); + } + + public boolean isORCondition() + { + return AndOr; + } + + public void setORCondition(boolean andOr) + { + AndOr = andOr; + } +} diff --git a/source/java/org/alfresco/repo/action/CompositeActionConditionImplTest.java b/source/java/org/alfresco/repo/action/CompositeActionConditionImplTest.java new file mode 100644 index 0000000000..069e6e5ab2 --- /dev/null +++ b/source/java/org/alfresco/repo/action/CompositeActionConditionImplTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2005-2009 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.action; + +import junit.framework.TestCase; + +import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.cmr.action.CompositeActionCondition; +import org.alfresco.util.GUID; + +/** + * @author Gavin Cornwell + * @since 3.1 + */ +public class CompositeActionConditionImplTest extends TestCase +{ + + @Override + protected void setUp() throws Exception + { + + } + + protected CompositeActionCondition create() + { + return new CompositeActionConditionImpl(GUID.generate()); + } + + public void testGetRuleConditionDefintion() + { + ActionCondition temp = (ActionCondition) create(); + assertEquals(CompositeActionCondition.COMPOSITE_CONDITION, temp.getActionConditionDefinitionName()); + } + + public void testAddActionCondition() + { + CompositeActionCondition temp = (CompositeActionCondition) create(); + assertEquals(temp.getActionConditions().size(), 0); + temp.addActionCondition(new ActionConditionImpl("id", "condName", null)); + assertEquals(temp.getActionConditions().size(), 1); + } + + public void testHasActionConditions() + { + CompositeActionCondition temp = (CompositeActionCondition) create(); + assertEquals(temp.hasActionConditions(), false); + temp.addActionCondition(new ActionConditionImpl("id", "condName", null)); + assertEquals(temp.hasActionConditions(), true); + } + + public void testRemoveAllActionConditions() + { + CompositeActionCondition temp = (CompositeActionCondition) create(); + assertEquals(temp.hasActionConditions(), false); + temp.addActionCondition(new ActionConditionImpl("id", "condName", null)); + assertEquals(temp.hasActionConditions(), true); + temp.removeAllActionConditions(); + assertEquals(temp.hasActionConditions(), false); + } + + public void testSetORCondition() + { + CompositeActionCondition temp = (CompositeActionCondition) create(); + assertEquals(temp.isORCondition(), false); + temp.setORCondition(true); + assertEquals(temp.isORCondition(), true); + + } + + public void testSetGetInvertCondition() + { + ActionCondition temp = (ActionCondition) create(); + assertFalse(temp.getInvertCondition()); + temp.setInvertCondition(true); + assertTrue(temp.getInvertCondition()); + } + +} diff --git a/source/java/org/alfresco/repo/action/actionModel.xml b/source/java/org/alfresco/repo/action/actionModel.xml index 158762c431..3340d82493 100644 --- a/source/java/org/alfresco/repo/action/actionModel.xml +++ b/source/java/org/alfresco/repo/action/actionModel.xml @@ -21,9 +21,9 @@ - Action Base Type - cm:cmobject - + Action Base Type + cm:cmobject + d:text true @@ -40,10 +40,10 @@ - - Action - act:actionbase - + + Action + act:actionbase + d:text false @@ -64,7 +64,7 @@ d:text false - + @@ -81,23 +81,43 @@ - - - - Action Condition - act:actionbase - + + + + Action Condition + act:actionbase + d:boolean true - - - - Action/Condition Parameter - cm:cmobject - + + + + Composite Condition + act:actioncondition + + + d:boolean + true + + + + + + act:actioncondition + true + true + + + + + + + Action/Condition Parameter + cm:cmobject + d:text true @@ -107,11 +127,11 @@ true - - - - Composite Action - act:action + + + + Composite Action + act:action @@ -121,11 +141,11 @@ - - - - Saved Action Folder - cm:systemfolder + + + + Saved Action Folder + cm:systemfolder @@ -135,14 +155,14 @@ - + - - - Action Execution Details - cm:cmobject - + + + Action Execution Details + cm:cmobject + d:text false @@ -160,13 +180,13 @@ false - + - + - - + + Rules @@ -180,7 +200,7 @@ - + Action Execution History @@ -194,6 +214,6 @@ - + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/action/evaluator/ComparePropertyValueEvaluator.java b/source/java/org/alfresco/repo/action/evaluator/ComparePropertyValueEvaluator.java index 58b811a5b6..b0f5cb9498 100644 --- a/source/java/org/alfresco/repo/action/evaluator/ComparePropertyValueEvaluator.java +++ b/source/java/org/alfresco/repo/action/evaluator/ComparePropertyValueEvaluator.java @@ -34,6 +34,7 @@ import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation; import org.alfresco.repo.action.evaluator.compare.ContentPropertyName; import org.alfresco.repo.action.evaluator.compare.PropertyValueComparator; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionServiceException; import org.alfresco.service.cmr.action.ParameterDefinition; @@ -47,6 +48,8 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Compare property value evaluator @@ -55,19 +58,22 @@ import org.alfresco.service.namespace.QName; */ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstractBase { - /** - * Evaluator constants - */ - public final static String NAME = "compare-property-value"; + private static Log logger = LogFactory.getLog(ComparePropertyValueEvaluator.class); + + /** + * Evaluator constants + */ + public final static String NAME = "compare-property-value"; + public final static String PARAM_PROPERTY = "property"; public final static String PARAM_CONTENT_PROPERTY = "content-property"; - public final static String PARAM_VALUE = "value"; - public final static String PARAM_OPERATION = "operation"; - - /** + public final static String PARAM_VALUE = "value"; + public final static String PARAM_OPERATION = "operation"; + + /** * The default property to check if none is specified in the properties */ - private final static QName DEFAULT_PROPERTY = ContentModel.PROP_NAME; + private final static QName DEFAULT_PROPERTY = ContentModel.PROP_NAME; /** * I18N message ID's @@ -80,9 +86,9 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr */ private Map comparators = new HashMap(); - /** - * The node service - */ + /** + * The node service + */ protected NodeService nodeService; /** @@ -94,16 +100,16 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr * The dictionary service */ protected DictionaryService dictionaryService; - + /** * Set node service * * @param nodeService the node service */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } /** * Set the content service @@ -148,38 +154,41 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr { this.comparators.put(dataType, comparator); } - + /** - * Add paremeter defintions + * Add parameter definitions */ - @Override - protected void addParameterDefinitions(List paramList) - { + @Override + protected void addParameterDefinitions(List paramList) + { paramList.add(new ParameterDefinitionImpl(PARAM_PROPERTY, DataTypeDefinition.QNAME, false, getParamDisplayLabel(PARAM_PROPERTY))); paramList.add(new ParameterDefinitionImpl(PARAM_CONTENT_PROPERTY, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_CONTENT_PROPERTY))); - paramList.add(new ParameterDefinitionImpl(PARAM_VALUE, DataTypeDefinition.ANY, true, getParamDisplayLabel(PARAM_VALUE))); - paramList.add(new ParameterDefinitionImpl(PARAM_OPERATION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_OPERATION))); - } + paramList.add(new ParameterDefinitionImpl(PARAM_VALUE, DataTypeDefinition.ANY, true, getParamDisplayLabel(PARAM_VALUE))); + paramList.add(new ParameterDefinitionImpl(PARAM_OPERATION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_OPERATION))); + } - /** + /** * @see ActionConditionEvaluatorAbstractBase#evaluateImpl(ActionCondition, NodeRef) - */ - public boolean evaluateImpl( - ActionCondition ruleCondition, - NodeRef actionedUponNodeRef) - { - boolean result = false; - - if (this.nodeService.exists(actionedUponNodeRef) == true) - { - // Get the name value of the node + */ + public boolean evaluateImpl( + ActionCondition ruleCondition, + NodeRef actionedUponNodeRef) + { + boolean result = false; + + if (this.nodeService.exists(actionedUponNodeRef) == true) + { + // Get the name value of the node QName propertyQName = (QName)ruleCondition.getParameterValue(PARAM_PROPERTY); if (propertyQName == null) { + if (logger.isWarnEnabled()) + logger.warn("ComparePropertyValue - Property is NULL. Setting to " + DEFAULT_PROPERTY); + propertyQName = DEFAULT_PROPERTY; } - // Get the origional value and the value to match + // Get the original value and the value to match Serializable propertyValue = this.nodeService.getProperty(actionedUponNodeRef, propertyQName); Serializable compareValue = ruleCondition.getParameterValue(PARAM_VALUE); @@ -191,7 +200,7 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr operation = ComparePropertyValueOperation.valueOf(operationString); } - // Look at the type of the property (assume to be ANY if none found in dicitionary) + // Look at the type of the property (assume to be ANY if none found in dictionary) QName propertyTypeQName = DataTypeDefinition.ANY; PropertyDefinition propertyDefintion = this.dictionaryService.getProperty(propertyQName); if (propertyDefintion != null) @@ -199,6 +208,14 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr propertyTypeQName = propertyDefintion.getDataType().getName(); } + if (logger.isDebugEnabled()) + { + logger.debug("Evaluating Property Parameters, propertyQName - [" + propertyQName + + "] getInverted? [" + ruleCondition.getInvertCondition() +"] operation [" + + operation + "]"); + logger.debug("Compare Value [" + compareValue + "] Actual Value [" + propertyValue + "]"); + } + // Sort out what to do if the property is a content property if (DataTypeDefinition.CONTENT.equals(propertyTypeQName) == true) { @@ -254,6 +271,10 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr } else { + if (logger.isWarnEnabled()) + { + logger.warn("Comparator not found for property type " + propertyTypeQName); + } // The default behaviour is to assume the property can only be compared using equals if (operation != null && operation != ComparePropertyValueOperation.EQUALS) { @@ -267,8 +288,20 @@ public class ComparePropertyValueEvaluator extends ActionConditionEvaluatorAbstr result = compareValue.equals(propertyValue); } } + else + { + if (logger.isInfoEnabled()) + { + logger.info("Condition Comparator encountered null value for property [" + propertyTypeQName +"]"); + } + } } - - return result; - } + + if (logger.isDebugEnabled()) + { + logger.debug("Returning result " + result); + } + + return result; + } } diff --git a/source/java/org/alfresco/repo/action/evaluator/CompositeConditionEvaluator.java b/source/java/org/alfresco/repo/action/evaluator/CompositeConditionEvaluator.java new file mode 100644 index 0000000000..50b42f87fd --- /dev/null +++ b/source/java/org/alfresco/repo/action/evaluator/CompositeConditionEvaluator.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2008 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.action.evaluator; + +import java.util.List; + +import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.cmr.action.ParameterDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This class is needed to provide some infrastructure, but the actual evaluation of + * Composite Conditions happens inside the ActionServiceImpl as a special case. + * + * @author Jean Barmash + */ +public class CompositeConditionEvaluator extends ActionConditionEvaluatorAbstractBase +{ + + private static Log logger = LogFactory.getLog(CompositeConditionEvaluator.class); + + @Override + protected boolean evaluateImpl(ActionCondition actionCondition, + NodeRef actionedUponNodeRef) + { + logger.error("Evaluating composite condition. Should not be called."); + return false; + } + + @Override + protected void addParameterDefinitions(List paramList) + { + } +} diff --git a/source/java/org/alfresco/repo/action/evaluator/IsSubTypeEvaluator.java b/source/java/org/alfresco/repo/action/evaluator/IsSubTypeEvaluator.java index 33bebc8443..ca4194e8e7 100644 --- a/source/java/org/alfresco/repo/action/evaluator/IsSubTypeEvaluator.java +++ b/source/java/org/alfresco/repo/action/evaluator/IsSubTypeEvaluator.java @@ -36,18 +36,18 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; /** - * No condition evaluator implmentation. + * No condition evaluator implementation. * * @author Roy Wetherall */ public class IsSubTypeEvaluator extends ActionConditionEvaluatorAbstractBase { - /** - * Evaluator constants - */ - public static final String NAME = "is-subtype"; + /** + * Evaluator constants + */ + public static final String NAME = "is-subtype"; public static final String PARAM_TYPE = "type"; - + /** * The node service */ @@ -101,10 +101,10 @@ public class IsSubTypeEvaluator extends ActionConditionEvaluatorAbstractBase /** * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) */ - @Override - protected void addParameterDefinitions(List paramList) - { + @Override + protected void addParameterDefinitions(List paramList) + { paramList.add(new ParameterDefinitionImpl(PARAM_TYPE, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_TYPE))); - } + } } diff --git a/source/java/org/alfresco/repo/action/evaluator/NoConditionEvaluator.java b/source/java/org/alfresco/repo/action/evaluator/NoConditionEvaluator.java index bbf0b1e6b6..84bb784cb0 100644 --- a/source/java/org/alfresco/repo/action/evaluator/NoConditionEvaluator.java +++ b/source/java/org/alfresco/repo/action/evaluator/NoConditionEvaluator.java @@ -31,16 +31,16 @@ import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.repository.NodeRef; /** - * No condition evaluator implmentation. + * No condition evaluator implementation. * * @author Roy Wetherall */ public class NoConditionEvaluator extends ActionConditionEvaluatorAbstractBase { - /** - * Evaluator constants - */ - public static final String NAME = "no-condition"; + /** + * Evaluator constants + */ + public static final String NAME = "no-condition"; /** * @see org.alfresco.repo.action.evaluator.ActionConditionEvaluatorAbstractBase#evaluateImpl(org.alfresco.service.cmr.action.ActionCondition, org.alfresco.service.cmr.repository.NodeRef) @@ -53,10 +53,10 @@ public class NoConditionEvaluator extends ActionConditionEvaluatorAbstractBase /** * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) */ - @Override - protected void addParameterDefinitions(List paramList) - { - // No parameters to add - } + @Override + protected void addParameterDefinitions(List paramList) + { + // No parameters to add + } } diff --git a/source/java/org/alfresco/repo/action/evaluator/compare/PropertyValueComparator.java b/source/java/org/alfresco/repo/action/evaluator/compare/PropertyValueComparator.java index e60ab1e5d8..c296f2b982 100644 --- a/source/java/org/alfresco/repo/action/evaluator/compare/PropertyValueComparator.java +++ b/source/java/org/alfresco/repo/action/evaluator/compare/PropertyValueComparator.java @@ -48,7 +48,7 @@ public interface PropertyValueComparator * @param propertyValue the property value * @param compareValue the compare value * @param operation the operation used to compare the two values - * @return the result of the comparision, true if successful false otherwise + * @return the result of the comparison, true if successful false otherwise */ boolean compare( Serializable propertyValue, diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java index 17e1cd1e22..9625ef0102 100644 --- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java @@ -333,15 +333,24 @@ public class MailActionExecuter extends ActionExecuterAbstractBase } message.setText(text); - // set the from address - use the default if not set - String from = (String)ruleAction.getParameterValue(PARAM_FROM); - if (from == null || from.length() == 0) + // set the from address + NodeRef person = personService.getPerson(authService.getCurrentUserName()); + String fromActualUser = (String)nodeService.getProperty(person, ContentModel.PROP_EMAIL); + if( fromActualUser != null && fromActualUser.length() != 0) { - message.setFrom(fromAddress); + message.setFrom(fromActualUser); } else { - message.setFrom(from); + String from = (String)ruleAction.getParameterValue(PARAM_FROM); + if (from == null || from.length() == 0) + { + message.setFrom(fromAddress); + } + else + { + message.setFrom(from); + } } } }; diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java index a446b839f3..512978b075 100644 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java +++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java @@ -26,6 +26,7 @@ package org.alfresco.repo.avm.locking; import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.AbstractLifecycleBean; import org.springframework.context.ApplicationEvent; @@ -37,31 +38,33 @@ import org.springframework.context.ApplicationEvent; public class AVMLockingBootstrap extends AbstractLifecycleBean { private AVMLockingService fLockingService; + private TransactionService transactionService; public void setAvmLockingService(AVMLockingService service) { fLockingService = service; } - /* - * (non-Javadoc) - * - * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent) - */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + @Override protected void onBootstrap(ApplicationEvent event) { + // Do nothing if the repo is read-only + if (transactionService.isReadOnly()) + { + return; + } + if (fLockingService instanceof AVMLockingServiceImpl) { ((AVMLockingServiceImpl) fLockingService).init(); } } - /* - * (non-Javadoc) - * - * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent) - */ @Override protected void onShutdown(ApplicationEvent event) { diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java index a6291b9228..9718cb645f 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java @@ -311,14 +311,18 @@ public class CopyServiceImpl implements CopyService boolean copyToNewNode, Map copiedNodeRefs) { + // Get the destination and target associations up-front for performance reasons + List destinationChildAssocs = this.nodeService.getChildAssocs(destinationNodeRef); + List destinationAssocs = this.nodeService.getTargetAssocs(destinationNodeRef, RegexQNamePattern.MATCH_ALL); + QName sourceClassRef = this.nodeService.getType(sourceNodeRef); - invokeCopyComplete(sourceClassRef, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs); + invokeCopyComplete(sourceClassRef, sourceNodeRef, destinationNodeRef, destinationChildAssocs, destinationAssocs, copyToNewNode, copiedNodeRefs); // Get the source aspects Set sourceAspects = this.nodeService.getAspects(sourceNodeRef); for (QName sourceAspect : sourceAspects) { - invokeCopyComplete(sourceAspect, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs); + invokeCopyComplete(sourceAspect, sourceNodeRef, destinationNodeRef, destinationChildAssocs, destinationAssocs, copyToNewNode, copiedNodeRefs); } } @@ -333,13 +337,15 @@ public class CopyServiceImpl implements CopyService QName typeQName, NodeRef sourceNodeRef, NodeRef destinationNodeRef, + List destinationChildAssocs, + List destinationAssocs, boolean copyToNewNode, Map copiedNodeRefs) { Collection policies = this.onCopyCompleteDelegate.getList(typeQName); if (policies.isEmpty() == true) { - defaultOnCopyComplete(typeQName, sourceNodeRef, destinationNodeRef, copiedNodeRefs); + defaultOnCopyComplete(typeQName, sourceNodeRef, destinationNodeRef, destinationChildAssocs, destinationAssocs, copiedNodeRefs); } else { @@ -361,6 +367,8 @@ public class CopyServiceImpl implements CopyService QName typeQName, NodeRef sourceNodeRef, NodeRef destinationNodeRef, + List destinationChildAssocs, + List destinationAssocs, Map copiedNodeRefs) { ClassDefinition classDefinition = this.dictionaryService.getClass(typeQName); @@ -392,8 +400,8 @@ public class CopyServiceImpl implements CopyService Map assocDefs = classDefinition.getAssociations(); // TODO: Need way of getting child assocs of a given type - List childAssocRefs = this.nodeService.getChildAssocs(destinationNodeRef); - for (ChildAssociationRef childAssocRef : childAssocRefs) + //List childAssocRefs = this.nodeService.getChildAssocs(destinationNodeRef); + for (ChildAssociationRef childAssocRef : destinationChildAssocs) { if (assocDefs.containsKey(childAssocRef.getTypeQName()) && childAssocRef.isPrimary() == false && @@ -410,8 +418,8 @@ public class CopyServiceImpl implements CopyService } // TODO: Need way of getting assocs of a given type - List nodeAssocRefs = this.nodeService.getTargetAssocs(destinationNodeRef, RegexQNamePattern.MATCH_ALL); - for (AssociationRef nodeAssocRef : nodeAssocRefs) + //List nodeAssocRefs = this.nodeService.getTargetAssocs(destinationNodeRef, RegexQNamePattern.MATCH_ALL); + for (AssociationRef nodeAssocRef : destinationAssocs) { if (assocDefs.containsKey(nodeAssocRef.getTypeQName()) && copiedNodeRefs.containsKey(nodeAssocRef.getTargetRef()) == true) diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 420365ec0d..b19e316e92 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -238,7 +238,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair rootNodePair = nodeDaoService.getRootNode(storeRef); if (rootNodePair == null) { - throw new InvalidStoreRefException("Store does not exist", storeRef); + throw new InvalidStoreRefException("Store does not exist: " + storeRef, storeRef); } // done return rootNodePair.getSecond(); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java index 1185d01dec..e35f096a6c 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.transaction.RollbackException; import javax.transaction.SystemException; @@ -1017,6 +1018,9 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI */ public static class LuceneIndexBackupComponent implements InitializingBean { + ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + + boolean executing = false; private static String BACKUP_TEMP_NAME = ".indexbackup_temp"; @@ -1095,15 +1099,57 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI */ public void backup() { - RetryingTransactionCallback backupWork = new RetryingTransactionCallback() + rwLock.readLock().lock(); + try { - public Object execute() throws Exception + if (executing) { - backupImpl(); - return null; + return; } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(backupWork); + } + finally + { + rwLock.readLock().unlock(); + } + + rwLock.writeLock().lock(); + try + { + if (executing) + { + return; + } + executing = true; + } + finally + { + rwLock.writeLock().unlock(); + } + + try + { + RetryingTransactionCallback backupWork = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + backupImpl(); + return null; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(backupWork); + } + finally + { + rwLock.writeLock().lock(); + try + { + executing = false; + } + finally + { + rwLock.writeLock().unlock(); + } + } } private void backupImpl() @@ -1464,7 +1510,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI if (checkConfiguration) { - transactionService.getRetryingTransactionHelper().doInTransaction(backupWork); + transactionService.getRetryingTransactionHelper().doInTransaction(backupWork, true); } } @@ -1477,6 +1523,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI */ public static class LuceneIndexBackupJob implements Job { + /** KEY_LUCENE_INDEX_BACKUP_COMPONENT = 'luceneIndexBackupComponent' */ public static final String KEY_LUCENE_INDEX_BACKUP_COMPONENT = "luceneIndexBackupComponent"; diff --git a/source/java/org/alfresco/repo/site/SiteAVMBootstrap.java b/source/java/org/alfresco/repo/site/SiteAVMBootstrap.java index 7d0a202408..e292d19a40 100644 --- a/source/java/org/alfresco/repo/site/SiteAVMBootstrap.java +++ b/source/java/org/alfresco/repo/site/SiteAVMBootstrap.java @@ -32,7 +32,9 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.AbstractLifecycleBean; +import org.alfresco.util.PropertyCheck; import org.springframework.context.ApplicationEvent; /** @@ -54,12 +56,18 @@ public class SiteAVMBootstrap extends AbstractLifecycleBean /** The Permission Service to use */ private PermissionService permissionService; + private TransactionService transactionService; + /** * @param rootDir the rootDir to set */ public void setRootdir(String rootdir) { + if (rootDir != null && rootDir.length() == 0) + { + rootDir = null; + } this.rootDir = rootdir; } @@ -87,9 +95,11 @@ public class SiteAVMBootstrap extends AbstractLifecycleBean this.permissionService = permissionService; } - /* (non-Javadoc) - * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent) - */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + @Override protected void onBootstrap(ApplicationEvent event) { @@ -110,10 +120,18 @@ public class SiteAVMBootstrap extends AbstractLifecycleBean public void bootstrap() { // ensure properties have been set - assert(avmService != null); - assert(permissionService != null); - assert(storeName != null && storeName.length() != 0); - assert(rootDir != null && rootDir.length() != 0); + PropertyCheck.mandatory(this, "avmService", avmService); + PropertyCheck.mandatory(this, "permissionService", permissionService); + PropertyCheck.mandatory(this, "transactionService", transactionService); + PropertyCheck.mandatory(this, "storeName", storeName); + PropertyCheck.mandatory(this, "rootDir", rootDir); + + // Avoid read-only mode errors + if (transactionService.isReadOnly()) + { + // Do nothing + return; + } if (this.avmService.getStore(storeName) == null) { @@ -135,9 +153,6 @@ public class SiteAVMBootstrap extends AbstractLifecycleBean } } - /* (non-Javadoc) - * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent) - */ @Override protected void onShutdown(ApplicationEvent event) { diff --git a/source/java/org/alfresco/service/cmr/action/ActionService.java b/source/java/org/alfresco/service/cmr/action/ActionService.java index b7216bd5be..941d9ca27c 100644 --- a/source/java/org/alfresco/service/cmr/action/ActionService.java +++ b/source/java/org/alfresco/service/cmr/action/ActionService.java @@ -40,22 +40,22 @@ import org.alfresco.service.cmr.repository.NodeRef; @PublicService public interface ActionService { - /** - * Get a named action definition - * - * @param name the name of the action definition - * @return the action definition - */ + /** + * Get a named action definition + * + * @param name the name of the action definition + * @return the action definition + */ @Auditable(parameters = {"name"}) - ActionDefinition getActionDefinition(String name); - - /** - * Get all the action definitions - * - * @return the list action definitions - */ + ActionDefinition getActionDefinition(String name); + + /** + * Get all the action definitions + * + * @return the list action definitions + */ @Auditable() - List getActionDefinitions(); + List getActionDefinitions(); /** * Get all the action definitions that are applicable for the given node, based on @@ -66,189 +66,196 @@ public interface ActionService */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) List getActionDefinitions(NodeRef nodeRef); - - /** - * Get a named action condition definition - * - * @param name the name of the action condition definition - * @return the action condition definition - */ + + /** + * Get a named action condition definition + * + * @param name the name of the action condition definition + * @return the action condition definition + */ @Auditable(parameters = {"name"}) - ActionConditionDefinition getActionConditionDefinition(String name); - - /** - * Get all the action condition definitions - * - * @return the list of aciton condition definitions - */ + ActionConditionDefinition getActionConditionDefinition(String name); + + /** + * Get all the action condition definitions + * + * @return the list of action condition definitions + */ @Auditable(parameters = {}) - List getActionConditionDefinitions(); - - /** - * Create a new action - * - * @param name the action definition name - * @return the action - */ + List getActionConditionDefinitions(); + + /** + * Create a new action + * + * @param name the action definition name + * @return the action + */ @Auditable(parameters = {"name"}) - Action createAction(String name); - - /** - * Create a new action specifying the initial set of parameter values - * - * @param name the action definition name - * @param params the parameter values - * @return the action - */ + Action createAction(String name); + + /** + * Create a new action specifying the initial set of parameter values + * + * @param name the action definition name + * @param params the parameter values + * @return the action + */ @Auditable(parameters = {"name", "params"}) - Action createAction(String name, Map params); - - /** - * Create a composite action - * - * @return the composite action - */ + Action createAction(String name, Map params); + + /** + * Create a composite action + * + * @return the composite action + */ @Auditable() - CompositeAction createCompositeAction(); - - /** - * Create an action condition - * - * @param name the action condition definition name - * @return the action condition - */ + CompositeAction createCompositeAction(); + + /** + * Create an action condition + * + * @param name the action condition definition name + * @return the action condition + */ @Auditable(parameters = {"name"}) - ActionCondition createActionCondition(String name); - - /** - * Create an action condition specifying the initial set of parameter values - * - * @param name the action condition definition name - * @param params the parameter values - * @return the action condition - */ + ActionCondition createActionCondition(String name); + + /** + * Create an action condition specifying the initial set of parameter values + * + * @param name the action condition definition name + * @param params the parameter values + * @return the action condition + */ @Auditable(parameters = {"name", "params"}) - ActionCondition createActionCondition(String name, Map params); - - /** - * The actions conditions are always checked. - * - * @see ActionService#executeAction(Action, NodeRef, boolean) - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - */ + ActionCondition createActionCondition(String name, Map params); + + /** + * Create a composite actionCondition + * @return the composite actionCondition + */ + @Auditable() + CompositeActionCondition createCompositeActionCondition(); + + /** + * The actions conditions are always checked. + * + * @see ActionService#executeAction(Action, NodeRef, boolean) + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + */ @Auditable(key = Auditable.Key.ARG_1, parameters = {"action", "actionedUponNodeRef" }) - void executeAction(Action action, NodeRef actionedUponNodeRef); - - /** - * The action is executed based on the asynchronous attribute of the action. - * - * @see ActionService#executeAction(Action, NodeRef, boolean, boolean) - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - * @param checkConditions indicates whether the conditions should be checked - */ + void executeAction(Action action, NodeRef actionedUponNodeRef); + + /** + * The action is executed based on the asynchronous attribute of the action. + * + * @see ActionService#executeAction(Action, NodeRef, boolean, boolean) + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + * @param checkConditions indicates whether the conditions should be checked + */ @Auditable(key = Auditable.Key.ARG_1, parameters = {"action", "actionedUponNodeRef", "checkConditions" }) - void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions); - - /** - * Executes the specified action upon the node reference provided. - *

- * If specified that the conditions should be checked then any conditions - * set on the action are evaluated. - *

- * If the conditions fail then the action is not executed. - *

- * If an action has no conditions then the action will always be executed. - *

- * If the conditions are not checked then the action will always be executed. - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - * @param checkConditions indicates whether the conditions should be checked before - * executing the action - * @param executeAsynchronously indicates whether the action should be executed asychronously or not, this value overrides - * the value set on the action its self - */ + void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions); + + /** + * Executes the specified action upon the node reference provided. + *

+ * If specified that the conditions should be checked then any conditions + * set on the action are evaluated. + *

+ * If the conditions fail then the action is not executed. + *

+ * If an action has no conditions then the action will always be executed. + *

+ * If the conditions are not checked then the action will always be executed. + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + * @param checkConditions indicates whether the conditions should be checked before + * executing the action + * @param executeAsynchronously indicates whether the action should be executed asychronously or not, this value overrides + * the value set on the action its self + */ @Auditable(key = Auditable.Key.ARG_1, parameters = {"action", "actionedUponNodeRef", "checkConditions", "executeAsynchronously" }) - void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsynchronously); - - /** - * Evaluted the conditions set on an action. - *

- * Returns true if the action has no conditions. - *

- * If the action has more than one condition their results are combined using the 'AND' - * logical operator. - * - * @param action the action - * @param actionedUponNodeRef the actioned upon node reference - * @return true if the condition succeeds, false otherwise - */ + void executeAction(Action action, NodeRef actionedUponNodeRef, boolean checkConditions, boolean executeAsynchronously); + + /** + * Evaluted the conditions set on an action. + *

+ * Returns true if the action has no conditions. + *

+ * If the action has more than one condition their results are combined using the 'AND' + * logical operator. + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + * @return true if the condition succeeds, false otherwise + */ @Auditable(key = Auditable.Key.ARG_1, parameters = {"action", "actionedUponNodeRef" }) - boolean evaluateAction(Action action, NodeRef actionedUponNodeRef); - - /** - * Evaluate an action condition. - * - * @param condition the action condition - * @param actionedUponNodeRef the actioned upon node reference - * @return true if the condition succeeds, false otherwise - */ + boolean evaluateAction(Action action, NodeRef actionedUponNodeRef); + + /** + * Evaluate an action condition. + * + * @param condition the action condition + * @param actionedUponNodeRef the actioned upon node reference + * @return true if the condition succeeds, false otherwise + */ @Auditable(key = Auditable.Key.ARG_1, parameters = {"condition", "actionedUponNodeRef" }) - boolean evaluateActionCondition(ActionCondition condition, NodeRef actionedUponNodeRef); - - /** - * Save an action against a node reference. - *

- * The node will be made configurable if it is not already. - *

- * If the action already exists then its details will be updated. - * - * @param nodeRef the node reference - * @param action the action - */ + boolean evaluateActionCondition(ActionCondition condition, NodeRef actionedUponNodeRef); + + /** + * Save an action against a node reference. + *

+ * The node will be made configurable if it is not already. + *

+ * If the action already exists then its details will be updated. + * + * @param nodeRef the node reference + * @param action the action + */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "action" }) - void saveAction(NodeRef nodeRef, Action action); - - /** - * Gets all the actions currently saved on the given node reference. - * - * @param nodeRef the node reference - * @return the list of actions - */ + void saveAction(NodeRef nodeRef, Action action); + + /** + * Gets all the actions currently saved on the given node reference. + * + * @param nodeRef the node reference + * @return the list of actions + */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) - List getActions(NodeRef nodeRef); - - /** - * Gets an action stored against a given node reference. - *

- * Returns null if the action can not be found. - * - * @param nodeRef the node reference - * @param actionId the action id - * @return the action - */ + List getActions(NodeRef nodeRef); + + /** + * Gets an action stored against a given node reference. + *

+ * Returns null if the action can not be found. + * + * @param nodeRef the node reference + * @param actionId the action id + * @return the action + */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "actionId"}) - Action getAction(NodeRef nodeRef, String actionId); - - /** - * Removes an action associated with a node reference. - * - * @param nodeRef the node reference - * @param action the action - */ + Action getAction(NodeRef nodeRef, String actionId); + + /** + * Removes an action associated with a node reference. + * + * @param nodeRef the node reference + * @param action the action + */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "action" }) - void removeAction(NodeRef nodeRef, Action action); - - /** - * Removes all actions associated with a node reference - * - * @param nodeRef the node reference - */ + void removeAction(NodeRef nodeRef, Action action); + + /** + * Removes all actions associated with a node reference + * + * @param nodeRef the node reference + */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) - void removeAllActions(NodeRef nodeRef); - + void removeAllActions(NodeRef nodeRef); + } diff --git a/source/java/org/alfresco/service/cmr/action/CompositeActionCondition.java b/source/java/org/alfresco/service/cmr/action/CompositeActionCondition.java new file mode 100644 index 0000000000..69e6e55cd1 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/action/CompositeActionCondition.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2005-2008 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.service.cmr.action; + +import java.util.List; + +/** + * Composite action condition + * + * @author Jean Barmash + */ +public interface CompositeActionCondition extends ActionCondition +{ + + public static String COMPOSITE_CONDITION = "composite-condition"; + + /** + * Indicates whether there are any Conditions + * + * @return true if there are ActionConditions, false otherwise + */ + boolean hasActionConditions(); + + /** + * Add an ActionCondition to the end of the list + * + * @param ActionCondition the ActionCondition + */ + void addActionCondition(ActionCondition ActionCondition); + + /** + * Add an ActionCondition to the list at the index specified + * + * @param index the index + * @param ActionCondition the ActionCondition + */ + void addActionCondition(int index, ActionCondition ActionCondition); + + /** + * Replace the ActionCondition at the specified index with the passed ActionCondition. + * + * @param index the index + * @param ActionCondition the ActionCondition + */ + void setActionCondition(int index, ActionCondition ActionCondition); + + /** + * Gets the index of an ActionCondition + * + * @param ActionCondition the ActionCondition + * @return the index + */ + int indexOfActionCondition(ActionCondition ActionCondition); + + /** + * Get list containing the ActionConditions in their current order + * + * @return the list of ActionConditions + */ + List getActionConditions(); + + /** + * Get an ActionCondition at a given index + * + * @param index the index + * @return the ActionCondition + */ + ActionCondition getActionCondition(int index); + + /** + * Remove an ActionCondition from the list + * + * @param ActionCondition the ActionCondition + */ + void removeActionCondition(ActionCondition ActionCondition); + + /** + * Remove all ActionConditions from the list + */ + void removeAllActionConditions(); + + public boolean isORCondition(); + + public void setORCondition(boolean andOr); + +}