diff --git a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
index c04f9c45a5..f512a7c3ca 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/AlfrescoCifsAuthenticator.java
@@ -166,7 +166,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
{
// Start a transaction
- tx = getTransactionService().getUserTransaction( false);
+ tx = createTransaction();
tx.begin();
// Perform local MD4 password check
@@ -177,7 +177,7 @@ public class AlfrescoCifsAuthenticator extends CifsAuthenticatorBase
{
// Start a transaction
- tx = getTransactionService().getUserTransaction( false);
+ tx = createTransaction();
tx.begin();
// Perform passthru authentication password check
diff --git a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
index 2beead17e2..7175c7aa7e 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/CifsAuthenticatorBase.java
@@ -369,7 +369,7 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator
// Check if the user name is an administrator
- UserTransaction tx = getTransactionService().getUserTransaction();
+ UserTransaction tx = createTransaction();
try {
tx.begin();
@@ -400,4 +400,25 @@ public abstract class CifsAuthenticatorBase extends CifsAuthenticator
}
}
}
+
+ /**
+ * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode.
+ *
+ * return UserTransaction
+ */
+ protected final UserTransaction createTransaction()
+ {
+ // Get the transaction service
+
+ TransactionService txService = getTransactionService();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction");
+
+ // Create the transaction
+
+ return txService.getUserTransaction( txService.isReadOnly() ? true : false);
+ }
}
\ 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 72c6623956..33a2eca33f 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java
@@ -561,7 +561,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
{
// Start a transaction
- tx = getTransactionService().getUserTransaction( false);
+ tx = createTransaction();
tx.begin();
// Process the hashed password session setup
@@ -718,7 +718,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
// Start a transaction
- tx = getTransactionService().getUserTransaction( false);
+ tx = createTransaction();
tx.begin();
// Process the security blob
diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
index 98e369aac6..3a59a7cb4c 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
@@ -174,7 +174,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements
// Start a transaction
- UserTransaction tx = getTransactionService().getUserTransaction( false);
+ UserTransaction tx = createTransaction();
int authSts = AUTH_DISALLOW;
try
@@ -1015,7 +1015,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements
{
// Wrap the service calls in a transaction
- UserTransaction tx = getTransactionService().getUserTransaction( false);
+ UserTransaction tx = createTransaction();
try
{
diff --git a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
index ed0fc898ad..37acaa2b45 100644
--- a/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
+++ b/source/java/org/alfresco/filesys/auth/ftp/FTPAuthenticatorBase.java
@@ -1,191 +1,198 @@
-/*
- * 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);
- }
- }
- }
-
- /**
- * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode.
- *
- * return UserTransaction
- */
- protected final UserTransaction createTransaction()
- {
- // Get the transaction service
-
- TransactionService txService = getTransactionService();
-
- return txService.getUserTransaction( txService.isReadOnly() ? true : false);
- }
-}
+/*
+ * 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);
+ }
+ }
+ }
+
+ /**
+ * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode.
+ *
+ * return UserTransaction
+ */
+ protected final UserTransaction createTransaction()
+ {
+ // Get the transaction service
+
+ TransactionService txService = getTransactionService();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction");
+
+ // Create the transaction
+
+ return txService.getUserTransaction( txService.isReadOnly() ? true : false);
+ }
+}
diff --git a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java
index a3e60a532b..424f3b7440 100644
--- a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java
@@ -1,462 +1,484 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.filesys.auth.nfs;
-
-import java.util.HashMap;
-import java.util.List;
-
-import javax.transaction.Status;
-import javax.transaction.UserTransaction;
-
-import org.alfresco.config.ConfigElement;
-import org.alfresco.filesys.AlfrescoConfigSection;
-import org.alfresco.filesys.alfresco.AlfrescoClientInfo;
-import org.alfresco.jlan.oncrpc.AuthType;
-import org.alfresco.jlan.oncrpc.Rpc;
-import org.alfresco.jlan.oncrpc.RpcAuthenticationException;
-import org.alfresco.jlan.oncrpc.RpcAuthenticator;
-import org.alfresco.jlan.oncrpc.RpcPacket;
-import org.alfresco.jlan.oncrpc.nfs.NFS;
-import org.alfresco.jlan.server.SrvSession;
-import org.alfresco.jlan.server.auth.ClientInfo;
-import org.alfresco.jlan.server.config.InvalidConfigurationException;
-import org.alfresco.jlan.server.config.ServerConfiguration;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Alfresco RPC Authenticator Class
- *
- *
Provides authentication support for the NFS server.
- *
- * @author gkspencer
- */
-public class AlfrescoRpcAuthenticator implements RpcAuthenticator {
-
- // Debug logging
-
- private static final Log logger = LogFactory.getLog("org.alfresco.nfs.protocol.auth");
-
- // Authentication types aupported by this implementation
-
- private int[] _authTypes = { AuthType.Unix };
-
- // UID/GID to username conversions
-
- private HashMap m_idMap;
-
- // Alfresco configuration
-
- protected AlfrescoConfigSection m_alfrescoConfig;
-
- /**
- * Authenticate an RPC client and create a unique session id key.
- *
- * @param authType int
- * @param rpc RpcPacket
- * @return Object
- * @throws RpcAuthenticationException
- */
- public Object authenticateRpcClient(int authType, RpcPacket rpc)
- throws RpcAuthenticationException {
-
- // Create a unique session key depending on the authentication type
-
- Object sessKey = null;
-
- if (authType == AuthType.Unix) {
-
- // Get the gid and uid from the credentials data in the request
-
- rpc.positionAtCredentialsData();
- rpc.skipBytes(4);
- int nameLen = rpc.unpackInt();
- rpc.skipBytes(nameLen);
-
- int uid = rpc.unpackInt();
- int gid = rpc.unpackInt();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid);
-
- // Check that there is a user name mapping for the uid/gid
-
- Integer idKey = new Integer((gid << 16) + uid);
- String userName = m_idMap.get( idKey);
-
- if ( userName == null)
- throw new RpcAuthenticationException( NFS.StsAccess);
-
- // Check if the Unix authentication session table is valid
-
- sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid);
- }
- else if ( authType == AuthType.Null)
- {
- // Set the session key for the null authentication
-
- sessKey = new Integer(rpc.getClientAddress().hashCode());
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug( "RpcAuth: Type=Null client=" + rpc.getClientAddress());
- }
-
- // Check if the session key is valid, if not then the authentication
- // type is unsupported
-
- if (sessKey == null)
- throw new RpcAuthenticationException(Rpc.AuthBadCred, "Unsupported auth type, " + authType);
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("RpcAuth: RPC from " + rpc.getClientDetails()
- + ", authType=" + AuthType.getTypeAsString(authType)
- + ", sessKey=" + sessKey);
-
- // Return the session key
-
- return sessKey;
- }
-
- /**
- * Return the authentication types that are supported by this
- * implementation.
- *
- * @return int[]
- */
- public int[] getRpcAuthenticationTypes() {
- return _authTypes;
- }
-
- /**
- * Return the client information for the specified RPC request
- *
- * @param sessKey Object
- * @param rpc RpcPacket
- * @return ClientInfo
- */
- public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc)
- {
- // Create a client information object to hold the client details
-
- ClientInfo cInfo = null;
-
- // Get the authentication type
-
- int authType = rpc.getCredentialsType();
-
- // Unpack the client details from the RPC request
-
- if ( authType == AuthType.Unix) {
-
- // Unpack the credentials data
-
- rpc.positionAtCredentialsData();
- rpc.skipBytes(4); // stamp id
-
- String clientAddr = rpc.unpackString();
- int uid = rpc.unpackInt();
- int gid = rpc.unpackInt();
-
- // Check for an additional groups list
-
- int grpLen = rpc.unpackInt();
- int[] groups = null;
-
- if (grpLen > 0) {
- groups = new int[grpLen];
- rpc.unpackIntArray(groups);
- }
-
- // Get the user name mapping for the uid/gid and authenticate
-
- Integer idKey = new Integer((gid << 16) + uid);
- String userName = m_idMap.get( idKey);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug( "RpcClientInfo: username=" + userName + ", uid=" + uid + ", gid=" + gid);
-
- // Create the client information if there is a valid mapping
-
- if ( userName != null)
- {
- // Create the client information and fill in relevant fields
-
- cInfo = ClientInfo.getFactory().createInfo( userName, null);
-
- cInfo.setNFSAuthenticationType( authType);
- cInfo.setClientAddress( clientAddr);
- cInfo.setUid( uid);
- cInfo.setGid( gid);
-
- cInfo.setGroupsList(groups);
- }
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", name="
- + clientAddr + ", uid=" + uid + ", gid=" + gid + ", groups=" + grpLen);
- }
- else if ( authType == AuthType.Null)
- {
- // Create the client information
-
- cInfo = ClientInfo.getFactory().createInfo( "", null);
- cInfo.setClientAddress(rpc.getClientAddress().getHostAddress());
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", addr="
- + rpc.getClientAddress().getHostAddress());
- }
-
- // Return the client information
-
- return cInfo;
- }
-
- /**
- * Set the current authenticated user context for this thread
- *
- * @param sess SrvSession
- * @param client ClientInfo
- */
- public void setCurrentUser( SrvSession sess, ClientInfo client)
- {
- // Start a transaction
-
- UserTransaction tx = m_alfrescoConfig.getTransactionService().getUserTransaction( false);
-
- try
- {
- // start the transaction
-
- tx.begin();
-
- // Check the account type and setup the authentication context
-
- if ( client == null || client.isNullSession() || client instanceof AlfrescoClientInfo == false)
- {
- // Clear the authentication, null user should not be allowed to do any service calls
-
- m_alfrescoConfig.getAuthenticationComponent().clearCurrentSecurityContext();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Clear security context, client=" + client);
- }
- else if ( client.isGuest() == false)
- {
- // Access the Alfresco client
-
- AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client;
-
- // Check if the authentication token has been set for the client
-
- if ( alfClient.hasAuthenticationToken() == false)
- {
- // Set the current user and retrieve the authentication token
-
- m_alfrescoConfig.getAuthenticationComponent().setCurrentUser( client.getUserName());
- alfClient.setAuthenticationToken( m_alfrescoConfig.getAuthenticationComponent().getCurrentAuthentication());
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set user name=" + client.getUserName() + ", token=" + alfClient.getAuthenticationToken());
- }
- else
- {
- // Set the authentication context for the request
-
- m_alfrescoConfig.getAuthenticationComponent().setCurrentAuthentication( alfClient.getAuthenticationToken());
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set user using auth token, token=" + alfClient.getAuthenticationToken());
- }
- }
- else
- {
- // Enable guest access for the request
-
- m_alfrescoConfig.getAuthenticationComponent().setGuestUserAsCurrentUser();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set guest user");
- }
- }
- catch ( Exception ex)
- {
- if ( logger.isDebugEnabled())
- logger.debug( ex);
- }
- finally
- {
- // Commit the transaction
-
- if ( tx != null)
- {
- try
- {
- // Commit or rollback the transaction
-
- if ( tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
- {
- // Transaction is marked for rollback
-
- tx.rollback();
- }
- else
- {
- // Commit the transaction
-
- tx.commit();
- }
- }
- catch ( Exception ex)
- {
- }
- }
- }
- }
-
- /**
- * Initialize the RPC authenticator
- *
- * @param config ServerConfiguration
- * @param params NameValueList
- * @throws InvalidConfigurationException
- */
- public void initialize(ServerConfiguration config, ConfigElement params)
- throws InvalidConfigurationException {
-
- // Get the Alfresco configuration section, for access to services
-
- m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName);
-
- // Check for the user mappings
-
- ConfigElement userMappings = params.getChild("userMappings");
- if ( userMappings != null)
- {
- // Allocate the id mappings table
-
- m_idMap = new HashMap();
-
- // Get the user map elements
-
- List userMaps = userMappings.getChildren();
-
- // Process the user list
-
- for ( ConfigElement userElem : userMaps)
- {
- // Validate the element type
-
- if ( userElem.getName().equalsIgnoreCase( "user"))
- {
- // Get the user name, user id and group id
-
- String userName = userElem.getAttribute("name");
- String uidStr = userElem.getAttribute("uid");
- String gidStr = userElem.getAttribute("gid");
-
- if ( userName == null || userName.length() == 0)
- throw new InvalidConfigurationException("Empty user name, or name not specified");
-
- if ( uidStr == null || uidStr.length() == 0)
- throw new InvalidConfigurationException("Invalid uid, or uid not specified, for user " + userName);
-
- if ( gidStr == null || gidStr.length() == 0)
- throw new InvalidConfigurationException("Invalid gid, or gid not specified, for user " + userName);
-
- // Parse the uid/gid
-
- int uid = -1;
- int gid = -1;
-
- try
- {
- uid = Integer.parseInt( uidStr);
- }
- catch ( NumberFormatException ex)
- {
- throw new InvalidConfigurationException("Invalid uid value, " + uidStr + " for user " + userName);
- }
-
- try
- {
- gid = Integer.parseInt( gidStr);
- }
- catch ( NumberFormatException ex)
- {
- throw new InvalidConfigurationException("Invalid gid value, " + gidStr + " for user " + userName);
- }
-
- // Check if the mapping already exists
-
- Integer idKey = new Integer(( gid << 16) + uid);
- if ( m_idMap.containsKey( idKey) == false)
- {
- // Add the username uid/gid mapping
-
- m_idMap.put( idKey, userName);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Added RPC user mapping for user " + userName + " uid=" + uid + ", gid=" + gid);
- }
- else if ( logger.isDebugEnabled())
- {
- // DEBUG
-
- logger.debug("Ignored duplicate mapping for uid=" + uid + ", gid=" + gid);
- }
- }
- else
- throw new InvalidConfigurationException( "Invalid user mapping, " + userElem.getName());
- }
- }
-
- // Make sure there are some user mappings
-
- if ( m_idMap == null || m_idMap.size() == 0)
- throw new InvalidConfigurationException("No user mappings for RPC authenticator");
- }
-}
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.filesys.auth.nfs;
+
+import java.util.HashMap;
+import java.util.List;
+
+import javax.transaction.Status;
+import javax.transaction.UserTransaction;
+
+import org.alfresco.config.ConfigElement;
+import org.alfresco.filesys.AlfrescoConfigSection;
+import org.alfresco.filesys.alfresco.AlfrescoClientInfo;
+import org.alfresco.jlan.oncrpc.AuthType;
+import org.alfresco.jlan.oncrpc.Rpc;
+import org.alfresco.jlan.oncrpc.RpcAuthenticationException;
+import org.alfresco.jlan.oncrpc.RpcAuthenticator;
+import org.alfresco.jlan.oncrpc.RpcPacket;
+import org.alfresco.jlan.oncrpc.nfs.NFS;
+import org.alfresco.jlan.server.SrvSession;
+import org.alfresco.jlan.server.auth.ClientInfo;
+import org.alfresco.jlan.server.config.InvalidConfigurationException;
+import org.alfresco.jlan.server.config.ServerConfiguration;
+import org.alfresco.service.transaction.TransactionService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Alfresco RPC Authenticator Class
+ *
+ *
Provides authentication support for the NFS server.
+ *
+ * @author gkspencer
+ */
+public class AlfrescoRpcAuthenticator implements RpcAuthenticator {
+
+ // Debug logging
+
+ private static final Log logger = LogFactory.getLog("org.alfresco.nfs.protocol.auth");
+
+ // Authentication types aupported by this implementation
+
+ private int[] _authTypes = { AuthType.Unix };
+
+ // UID/GID to username conversions
+
+ private HashMap m_idMap;
+
+ // Alfresco configuration
+
+ protected AlfrescoConfigSection m_alfrescoConfig;
+
+ /**
+ * Authenticate an RPC client and create a unique session id key.
+ *
+ * @param authType int
+ * @param rpc RpcPacket
+ * @return Object
+ * @throws RpcAuthenticationException
+ */
+ public Object authenticateRpcClient(int authType, RpcPacket rpc)
+ throws RpcAuthenticationException {
+
+ // Create a unique session key depending on the authentication type
+
+ Object sessKey = null;
+
+ if (authType == AuthType.Unix) {
+
+ // Get the gid and uid from the credentials data in the request
+
+ rpc.positionAtCredentialsData();
+ rpc.skipBytes(4);
+ int nameLen = rpc.unpackInt();
+ rpc.skipBytes(nameLen);
+
+ int uid = rpc.unpackInt();
+ int gid = rpc.unpackInt();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid);
+
+ // Check that there is a user name mapping for the uid/gid
+
+ Integer idKey = new Integer((gid << 16) + uid);
+ String userName = m_idMap.get( idKey);
+
+ if ( userName == null)
+ throw new RpcAuthenticationException( NFS.StsAccess);
+
+ // Check if the Unix authentication session table is valid
+
+ sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid);
+ }
+ else if ( authType == AuthType.Null)
+ {
+ // Set the session key for the null authentication
+
+ sessKey = new Integer(rpc.getClientAddress().hashCode());
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "RpcAuth: Type=Null client=" + rpc.getClientAddress());
+ }
+
+ // Check if the session key is valid, if not then the authentication
+ // type is unsupported
+
+ if (sessKey == null)
+ throw new RpcAuthenticationException(Rpc.AuthBadCred, "Unsupported auth type, " + authType);
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("RpcAuth: RPC from " + rpc.getClientDetails()
+ + ", authType=" + AuthType.getTypeAsString(authType)
+ + ", sessKey=" + sessKey);
+
+ // Return the session key
+
+ return sessKey;
+ }
+
+ /**
+ * Return the authentication types that are supported by this
+ * implementation.
+ *
+ * @return int[]
+ */
+ public int[] getRpcAuthenticationTypes() {
+ return _authTypes;
+ }
+
+ /**
+ * Return the client information for the specified RPC request
+ *
+ * @param sessKey Object
+ * @param rpc RpcPacket
+ * @return ClientInfo
+ */
+ public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc)
+ {
+ // Create a client information object to hold the client details
+
+ ClientInfo cInfo = null;
+
+ // Get the authentication type
+
+ int authType = rpc.getCredentialsType();
+
+ // Unpack the client details from the RPC request
+
+ if ( authType == AuthType.Unix) {
+
+ // Unpack the credentials data
+
+ rpc.positionAtCredentialsData();
+ rpc.skipBytes(4); // stamp id
+
+ String clientAddr = rpc.unpackString();
+ int uid = rpc.unpackInt();
+ int gid = rpc.unpackInt();
+
+ // Check for an additional groups list
+
+ int grpLen = rpc.unpackInt();
+ int[] groups = null;
+
+ if (grpLen > 0) {
+ groups = new int[grpLen];
+ rpc.unpackIntArray(groups);
+ }
+
+ // Get the user name mapping for the uid/gid and authenticate
+
+ Integer idKey = new Integer((gid << 16) + uid);
+ String userName = m_idMap.get( idKey);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "RpcClientInfo: username=" + userName + ", uid=" + uid + ", gid=" + gid);
+
+ // Create the client information if there is a valid mapping
+
+ if ( userName != null)
+ {
+ // Create the client information and fill in relevant fields
+
+ cInfo = ClientInfo.getFactory().createInfo( userName, null);
+
+ cInfo.setNFSAuthenticationType( authType);
+ cInfo.setClientAddress( clientAddr);
+ cInfo.setUid( uid);
+ cInfo.setGid( gid);
+
+ cInfo.setGroupsList(groups);
+ }
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", name="
+ + clientAddr + ", uid=" + uid + ", gid=" + gid + ", groups=" + grpLen);
+ }
+ else if ( authType == AuthType.Null)
+ {
+ // Create the client information
+
+ cInfo = ClientInfo.getFactory().createInfo( "", null);
+ cInfo.setClientAddress(rpc.getClientAddress().getHostAddress());
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("RpcAuth: Client info, type=" + AuthType.getTypeAsString(authType) + ", addr="
+ + rpc.getClientAddress().getHostAddress());
+ }
+
+ // Return the client information
+
+ return cInfo;
+ }
+
+ /**
+ * Set the current authenticated user context for this thread
+ *
+ * @param sess SrvSession
+ * @param client ClientInfo
+ */
+ public void setCurrentUser( SrvSession sess, ClientInfo client)
+ {
+ // Start a transaction
+
+ UserTransaction tx = createTransaction();
+
+ try
+ {
+ // start the transaction
+
+ tx.begin();
+
+ // Check the account type and setup the authentication context
+
+ if ( client == null || client.isNullSession() || client instanceof AlfrescoClientInfo == false)
+ {
+ // Clear the authentication, null user should not be allowed to do any service calls
+
+ m_alfrescoConfig.getAuthenticationComponent().clearCurrentSecurityContext();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Clear security context, client=" + client);
+ }
+ else if ( client.isGuest() == false)
+ {
+ // Access the Alfresco client
+
+ AlfrescoClientInfo alfClient = (AlfrescoClientInfo) client;
+
+ // Check if the authentication token has been set for the client
+
+ if ( alfClient.hasAuthenticationToken() == false)
+ {
+ // Set the current user and retrieve the authentication token
+
+ m_alfrescoConfig.getAuthenticationComponent().setCurrentUser( client.getUserName());
+ alfClient.setAuthenticationToken( m_alfrescoConfig.getAuthenticationComponent().getCurrentAuthentication());
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set user name=" + client.getUserName() + ", token=" + alfClient.getAuthenticationToken());
+ }
+ else
+ {
+ // Set the authentication context for the request
+
+ m_alfrescoConfig.getAuthenticationComponent().setCurrentAuthentication( alfClient.getAuthenticationToken());
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set user using auth token, token=" + alfClient.getAuthenticationToken());
+ }
+ }
+ else
+ {
+ // Enable guest access for the request
+
+ m_alfrescoConfig.getAuthenticationComponent().setGuestUserAsCurrentUser();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set guest user");
+ }
+ }
+ catch ( Exception ex)
+ {
+ if ( logger.isDebugEnabled())
+ logger.debug( ex);
+ }
+ finally
+ {
+ // Commit the transaction
+
+ if ( tx != null)
+ {
+ try
+ {
+ // Commit or rollback the transaction
+
+ if ( tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
+ {
+ // Transaction is marked for rollback
+
+ tx.rollback();
+ }
+ else
+ {
+ // Commit the transaction
+
+ tx.commit();
+ }
+ }
+ catch ( Exception ex)
+ {
+ }
+ }
+ }
+ }
+
+ /**
+ * Initialize the RPC authenticator
+ *
+ * @param config ServerConfiguration
+ * @param params NameValueList
+ * @throws InvalidConfigurationException
+ */
+ public void initialize(ServerConfiguration config, ConfigElement params)
+ throws InvalidConfigurationException {
+
+ // Get the Alfresco configuration section, for access to services
+
+ m_alfrescoConfig = (AlfrescoConfigSection) config.getConfigSection( AlfrescoConfigSection.SectionName);
+
+ // Check for the user mappings
+
+ ConfigElement userMappings = params.getChild("userMappings");
+ if ( userMappings != null)
+ {
+ // Allocate the id mappings table
+
+ m_idMap = new HashMap();
+
+ // Get the user map elements
+
+ List userMaps = userMappings.getChildren();
+
+ // Process the user list
+
+ for ( ConfigElement userElem : userMaps)
+ {
+ // Validate the element type
+
+ if ( userElem.getName().equalsIgnoreCase( "user"))
+ {
+ // Get the user name, user id and group id
+
+ String userName = userElem.getAttribute("name");
+ String uidStr = userElem.getAttribute("uid");
+ String gidStr = userElem.getAttribute("gid");
+
+ if ( userName == null || userName.length() == 0)
+ throw new InvalidConfigurationException("Empty user name, or name not specified");
+
+ if ( uidStr == null || uidStr.length() == 0)
+ throw new InvalidConfigurationException("Invalid uid, or uid not specified, for user " + userName);
+
+ if ( gidStr == null || gidStr.length() == 0)
+ throw new InvalidConfigurationException("Invalid gid, or gid not specified, for user " + userName);
+
+ // Parse the uid/gid
+
+ int uid = -1;
+ int gid = -1;
+
+ try
+ {
+ uid = Integer.parseInt( uidStr);
+ }
+ catch ( NumberFormatException ex)
+ {
+ throw new InvalidConfigurationException("Invalid uid value, " + uidStr + " for user " + userName);
+ }
+
+ try
+ {
+ gid = Integer.parseInt( gidStr);
+ }
+ catch ( NumberFormatException ex)
+ {
+ throw new InvalidConfigurationException("Invalid gid value, " + gidStr + " for user " + userName);
+ }
+
+ // Check if the mapping already exists
+
+ Integer idKey = new Integer(( gid << 16) + uid);
+ if ( m_idMap.containsKey( idKey) == false)
+ {
+ // Add the username uid/gid mapping
+
+ m_idMap.put( idKey, userName);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Added RPC user mapping for user " + userName + " uid=" + uid + ", gid=" + gid);
+ }
+ else if ( logger.isDebugEnabled())
+ {
+ // DEBUG
+
+ logger.debug("Ignored duplicate mapping for uid=" + uid + ", gid=" + gid);
+ }
+ }
+ else
+ throw new InvalidConfigurationException( "Invalid user mapping, " + userElem.getName());
+ }
+ }
+
+ // Make sure there are some user mappings
+
+ if ( m_idMap == null || m_idMap.size() == 0)
+ throw new InvalidConfigurationException("No user mappings for RPC authenticator");
+ }
+
+ /**
+ * Create a transaction, this will be a wrteable transaction unless the system is in read-only mode.
+ *
+ * return UserTransaction
+ */
+ protected final UserTransaction createTransaction()
+ {
+ // Get the transaction service
+
+ TransactionService txService = m_alfrescoConfig.getTransactionService();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Using " + (txService.isReadOnly() ? "ReadOnly" : "Write") + " transaction");
+
+ // Create the transaction
+
+ return txService.getUserTransaction( txService.isReadOnly() ? true : false);
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/CifsHelper.java b/source/java/org/alfresco/filesys/repo/CifsHelper.java
index 1e15df2925..53be8fab68 100644
--- a/source/java/org/alfresco/filesys/repo/CifsHelper.java
+++ b/source/java/org/alfresco/filesys/repo/CifsHelper.java
@@ -1,691 +1,689 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing" */
-package org.alfresco.filesys.repo;
-
-import java.io.FileNotFoundException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-import java.util.StringTokenizer;
-
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.jlan.server.filesys.FileAttribute;
-import org.alfresco.jlan.server.filesys.FileExistsException;
-import org.alfresco.jlan.server.filesys.FileName;
-import org.alfresco.jlan.util.WildCard;
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.model.FileFolderService;
-import org.alfresco.service.cmr.model.FileInfo;
-import org.alfresco.service.cmr.repository.ContentData;
-import org.alfresco.service.cmr.repository.InvalidNodeRefException;
-import org.alfresco.service.cmr.repository.MimetypeService;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
-import org.alfresco.service.cmr.security.AccessStatus;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.util.SearchLanguageConversion;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Class with supplying helper methods and potentially acting as a cache for
- * queries.
- *
- * @author derekh
- */
-public class CifsHelper
-{
- // Logging
- private static Log logger = LogFactory.getLog(CifsHelper.class);
-
- // Services
- private DictionaryService dictionaryService;
- private NodeService nodeService;
- private FileFolderService fileFolderService;
- private MimetypeService mimetypeService;
- private PermissionService permissionService;
- private boolean isReadOnly;
-
- // Mark locked files as offline
-
- private boolean lockedFilesAsOffline;
-
- /**
- * Class constructor
- */
- public CifsHelper()
- {
- isReadOnly = false;
- }
-
- public void setDictionaryService(DictionaryService dictionaryService)
- {
- this.dictionaryService = dictionaryService;
- }
-
- public void setNodeService(NodeService nodeService)
- {
- this.nodeService = nodeService;
- }
-
- public void setFileFolderService(FileFolderService fileFolderService)
- {
- this.fileFolderService = fileFolderService;
- }
-
- public void setMimetypeService(MimetypeService mimetypeService)
- {
- this.mimetypeService = mimetypeService;
- }
-
- public void setPermissionService(PermissionService permissionService)
- {
- this.permissionService = permissionService;
- }
-
- /**
- * @return Returns true if all files/folders should be treated as read-only
- */
- public boolean isReadOnly()
- {
- return isReadOnly;
- }
-
- /**
- * Set whether the system allows files to be edited or not. The default is
- * to allow writes.
- * @param allowWrites true to allow writes, otherwise false for read-only mode
- */
- public void setAllowWrites(boolean allowWrites)
- {
- this.isReadOnly = !allowWrites;
- }
-
- /**
- * Enable marking of locked files as offline
- *
- * @param ena boolean
- */
- public final void setMarkLockedFilesAsOffline(boolean ena)
- {
- lockedFilesAsOffline = ena;
- }
-
- /**
- * Check if locked files should be marked as offline
- *
- * @return boolean
- */
- public final boolean hasLockedFilesAsOffline()
- {
- return lockedFilesAsOffline;
- }
-
- /**
- * @param serviceRegistry for repo connection
- * @param nodeRef
- * @return Returns true if the node is a subtype of {@link ContentModel#TYPE_FOLDER folder}
- * @throws AlfrescoRuntimeException if the type is neither related to a folder or content
- */
- public boolean isDirectory(NodeRef nodeRef)
- {
- QName nodeTypeQName = nodeService.getType(nodeRef);
- if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_FOLDER))
- {
- return true;
- }
- else if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT))
- {
- return false;
- }
- else
- {
- // it is not a directory, but what is it?
- return false;
- }
- }
-
- /**
- * Extract a single node's file info, where the node is reference by
- * a path relative to an ancestor node.
- *
- * @param pathRootNodeRef
- * @param path
- * @return Returns the existing node reference
- * @throws FileNotFoundException
- */
- public ContentFileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
- {
- // get the node being referenced
- NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
-
- return getFileInformation(nodeRef);
- }
-
- /**
- * Helper method to extract file info from a specific node.
- *
- * This method goes direct to the repo for all information and no data is
- * cached here.
- *
- * @param nodeRef the node that the path is relative to
- * @param path the path to get info for
- * @return Returns the file information pertinent to the node
- * @throws FileNotFoundException if the path refers to a non-existent file
- */
- public ContentFileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
- {
- // get the file info
- org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
-
- // retrieve required properties and create file info
- ContentFileInfo fileInfo = new ContentFileInfo();
- fileInfo.setNodeRef(nodeRef);
-
- // unset all attribute flags
- int fileAttributes = 0;
- fileInfo.setFileAttributes(fileAttributes);
-
- if (fileFolderInfo.isFolder())
- {
- // add directory attribute
- fileAttributes |= FileAttribute.Directory;
- fileInfo.setFileAttributes(fileAttributes);
- }
- else
- {
- Map nodeProperties = fileFolderInfo.getProperties();
-
- // Get the file size from the content
-
- ContentData contentData = (ContentData) nodeProperties.get(ContentModel.PROP_CONTENT);
- long size = 0L;
- if (contentData != null)
- {
- size = contentData.getSize();
- }
- fileInfo.setSize(size);
-
- // Set the allocation size by rounding up the size to a 512 byte block boundary
-
- if ( size > 0)
- fileInfo.setAllocationSize((size + 512L) & 0xFFFFFFFFFFFFFE00L);
-
- // Check the lock status of the file
-
- String lockTypeStr = (String) nodeProperties.get(ContentModel.PROP_LOCK_TYPE);
-
- if ( lockTypeStr != null )
- {
- // File is locked so mark it as read-only and offline
-
- int attr = fileInfo.getFileAttributes();
-
- if (( attr & FileAttribute.ReadOnly) == 0)
- attr += FileAttribute.ReadOnly;
-
- if ( hasLockedFilesAsOffline())
- attr += FileAttribute.NTOffline;
-
- fileInfo.setFileAttributes( attr);
- }
-
- // Check if it is a link node
-
- if ( fileFolderInfo.isLink())
- fileInfo.setLinkNodeRef( fileFolderInfo.getLinkNodeRef());
- }
-
- // created
- Date createdDate = fileFolderInfo.getCreatedDate();
- if (createdDate != null)
- {
- long created = DefaultTypeConverter.INSTANCE.longValue(createdDate);
- fileInfo.setCreationDateTime(created);
- }
- // modified
- Date modifiedDate = fileFolderInfo.getModifiedDate();
- if (modifiedDate != null)
- {
- long modified = DefaultTypeConverter.INSTANCE.longValue(modifiedDate);
- fileInfo.setModifyDateTime(modified);
- fileInfo.setAccessDateTime(modified);
- }
- // name
- String name = fileFolderInfo.getName();
- if (name != null)
- {
- fileInfo.setFileName(name);
- }
-
- // Read/write access
-
- boolean deniedPermission = permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED;
- if (isReadOnly || deniedPermission)
- {
- int attr = fileInfo.getFileAttributes();
- if (( attr & FileAttribute.ReadOnly) == 0)
- {
- attr += FileAttribute.ReadOnly;
- fileInfo.setFileAttributes(attr);
- }
- }
-
- // Set the normal file attribute if no other attributes are set
-
- if ( fileInfo.getFileAttributes() == 0)
- fileInfo.setFileAttributes(FileAttribute.NTNormal);
-
- // Debug
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Fetched file info: \n" +
- " info: " + fileInfo);
- }
-
- // Return the file information
-
- return fileInfo;
- }
-
- /**
- * Creates a file or directory using the given paths.
- *
- * If the directory path doesn't exist, then all the parent directories will be created.
- * If the file path is null, then the file will not be created
- *
- * @param rootNodeRef the root node of the path
- * @param path the path to a node
- * @param isFile true if the node to be created must be a file
- * @return Returns a newly created file or folder node
- * @throws FileExistsException if the file or folder already exists
- */
- public NodeRef createNode(NodeRef rootNodeRef, String path, boolean isFile) throws FileExistsException
- {
- // split the path up into its constituents
- StringTokenizer tokenizer = new StringTokenizer(path, FileName.DOS_SEPERATOR_STR, false);
- List folderPathElements = new ArrayList(10);
- String name = null;
- while (tokenizer.hasMoreTokens())
- {
- String pathElement = tokenizer.nextToken();
-
- if (!tokenizer.hasMoreTokens())
- {
- // the last token becomes the name
- name = pathElement;
- }
- else
- {
- // add the path element to the parent folder path
- folderPathElements.add(pathElement);
- }
- }
- // ensure that the folder path exists
- NodeRef parentFolderNodeRef = rootNodeRef;
- if (folderPathElements.size() > 0)
- {
- parentFolderNodeRef = FileFolderServiceImpl.makeFolders(
- fileFolderService,
- rootNodeRef,
- folderPathElements,
- ContentModel.TYPE_FOLDER).getNodeRef();
- }
- // add the file or folder
- QName typeQName = isFile ? ContentModel.TYPE_CONTENT : ContentModel.TYPE_FOLDER;
- try
- {
- NodeRef nodeRef = fileFolderService.create(parentFolderNodeRef, name, typeQName).getNodeRef();
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Created node: \n" +
- " device root: " + rootNodeRef + "\n" +
- " path: " + path + "\n" +
- " is file: " + isFile + "\n" +
- " new node: " + nodeRef);
- }
- return nodeRef;
- }
- catch (org.alfresco.service.cmr.model.FileExistsException e)
- {
- throw new FileExistsException(path);
- }
- }
-
- private void addDescendents(List pathRootNodeRefs, Stack pathElements, List results)
- {
- if (pathElements.isEmpty())
- {
- // if this method is called with an empty path element stack, then the
- // current context nodes are the results to be added
- results.addAll(pathRootNodeRefs);
- return;
- }
-
- // take the first path element off the stack
- String pathElement = pathElements.pop();
-
- // iterate over each path root node
- for (NodeRef pathRootNodeRef : pathRootNodeRefs)
- {
- // deal with cyclic relationships by not traversing down any node already in the results
- if (results.contains(pathRootNodeRef))
- {
- continue;
- }
- // get direct descendents along the path
- List directDescendents = getDirectDescendents(pathRootNodeRef, pathElement);
- // recurse onto the descendents
- addDescendents(directDescendents, pathElements, results);
- }
-
- // restore the path element stack
- pathElements.push(pathElement);
- }
-
- /**
- * Searches for the node or nodes that match the path element for the given parent node
- */
- private List getDirectDescendents(NodeRef pathRootNodeRef, String pathElement)
- {
- if (logger.isDebugEnabled())
- {
- logger.debug("Getting direct descendents: \n" +
- " Path Root: " + pathRootNodeRef + "\n" +
- " Path Element: " + pathElement);
- }
- List results = null;
- // if this contains no wildcards, then we can fasttrack it
- if (!WildCard.containsWildcards(pathElement))
- {
- // a specific name is required
- NodeRef foundNodeRef = fileFolderService.searchSimple(pathRootNodeRef, pathElement);
- if (foundNodeRef == null)
- {
- results = Collections.emptyList();
- }
- else
- {
- results = Collections.singletonList(foundNodeRef);
- }
- }
- else
- {
- // escape for the Lucene syntax search
- String escapedPathElement = SearchLanguageConversion.convertCifsToLucene(pathElement);
- // do the lookup
- List childInfos = fileFolderService.search(
- pathRootNodeRef,
- escapedPathElement,
- false);
- // convert to noderefs
- results = new ArrayList(childInfos.size());
- for (org.alfresco.service.cmr.model.FileInfo info : childInfos)
- {
- results.add(info.getNodeRef());
- }
- }
- // done
- return results;
- }
-
- /**
- * Finds the nodes being reference by the given directory and file paths.
- *
- * Examples of the path are:
- *
- *
\New Folder\New Text Document.txt
- *
\New Folder\Sub Folder
- *
- *
- * @param searchRootNodeRef the node from which to start the path search
- * @param path the search path to either a folder or file
- * @return Returns references to all matching nodes
- */
- public List getNodeRefs(NodeRef pathRootNodeRef, String path)
- {
- // tokenize the path and push into a stack in reverse order so that
- // the root directory gets popped first
- StringTokenizer tokenizer = new StringTokenizer(path, FileName.DOS_SEPERATOR_STR, false);
- String[] tokens = new String[tokenizer.countTokens()];
- int count = 0;
- while(tokenizer.hasMoreTokens())
- {
- tokens[count] = tokenizer.nextToken();
- count++;
- }
- Stack pathElements = new Stack();
- for (int i = tokens.length - 1; i >= 0; i--)
- {
- pathElements.push(tokens[i]);
- }
-
- // start with a single parent node
- List pathRootNodeRefs = Collections.singletonList(pathRootNodeRef);
-
- // result storage
- List results = new ArrayList(5);
-
- // kick off the path walking
- addDescendents(pathRootNodeRefs, pathElements, results);
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Retrieved node references for path: \n" +
- " path root: " + pathRootNodeRef + "\n" +
- " path: " + path + "\n" +
- " results: " + results);
- }
- return results;
- }
-
- /**
- * Attempts to fetch a specific single node at the given path.
- *
- * @throws FileNotFoundException if the path can't be resolved to a node
- *
- * @see #getNodeRefs(NodeRef, String)
- */
- public NodeRef getNodeRef(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
- {
- // attempt to get the file/folder node using hierarchy walking
- List nodeRefs = getNodeRefs(pathRootNodeRef, path);
- if (nodeRefs.size() == 0)
- {
- throw new FileNotFoundException(path);
- }
- else if (nodeRefs.size() > 1)
- {
- logger.warn("Multiple matching nodes: \n" +
- " search root: " + pathRootNodeRef + "\n" +
- " path: " + path);
- }
- // take the first one - not sure if it is possible for the path to refer to more than one
- NodeRef nodeRef = nodeRefs.get(0);
- // done
- return nodeRef;
- }
-
- /**
- * Relink the content data from a new node to an existing node to preserve the version history.
- *
- * @param oldNodeRef NodeRef
- * @param newNodeRef NodeRef
- */
- public void relinkNode(NodeRef tempNodeRef, NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName)
- throws FileNotFoundException, FileExistsException
- {
- // Get the properties for the old and new nodes
- org.alfresco.service.cmr.model.FileInfo tempFileInfo = fileFolderService.getFileInfo(tempNodeRef);
- org.alfresco.service.cmr.model.FileInfo fileToMoveInfo = fileFolderService.getFileInfo(nodeToMoveRef);
-
- // Save the current name of the old node
- String tempName = tempFileInfo.getName();
-
- try
- {
- // remove the tempory aspects from the nodes, this will be reapplied if the new name dictates it
- nodeService.removeAspect(tempNodeRef, ContentModel.ASPECT_TEMPORARY);
-
- // rename temp file to the new name
- fileFolderService.rename(tempNodeRef, newName);
-
- // rename new file to old name
- fileFolderService.rename(nodeToMoveRef, tempName);
- this.nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null);
- }
- catch (org.alfresco.service.cmr.model.FileNotFoundException e)
- {
- throw new FileNotFoundException(e.getMessage());
- }
- catch (org.alfresco.service.cmr.model.FileExistsException e)
- {
- throw new FileExistsException(e.getMessage());
- }
-
- if (!tempFileInfo.isFolder() && !fileToMoveInfo.isFolder())
- {
- // swap the content between the two
- ContentData oldContentData = tempFileInfo.getContentData();
- if (oldContentData == null)
- {
- String mimetype = mimetypeService.guessMimetype(tempName);
- oldContentData = ContentData.setMimetype(null, mimetype);
- }
-
- ContentData newContentData = fileToMoveInfo.getContentData();
-
- // Reset the mime type
-
- String mimetype = mimetypeService.guessMimetype(newName);
- newContentData = ContentData.setMimetype(newContentData, mimetype);
-
- nodeService.setProperty(tempNodeRef, ContentModel.PROP_CONTENT, newContentData);
- nodeService.setProperty(nodeToMoveRef, ContentModel.PROP_CONTENT, oldContentData);
- }
- }
-
- /**
- * Move a node
- *
- * @param nodeToMoveRef Node to be moved
- * @param newParentNodeRef New parent folder node
- * @param newName New name for the moved node
- * @throws FileExistsException
- */
- public void move(NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName) throws FileExistsException
- {
- try
- {
- fileFolderService.move(nodeToMoveRef, newParentNodeRef, newName);
- }
- catch (org.alfresco.service.cmr.model.FileExistsException e)
- {
- throw new FileExistsException(newName);
- }
- catch (Throwable e)
- {
- throw new AlfrescoRuntimeException("Move failed: \n" +
- " node to move: " + nodeToMoveRef + "\n" +
- " new parent: " + newParentNodeRef + "\n" +
- " new name: " + newName,
- e);
- }
- }
-
- /**
- * Rename a node
- *
- * @param nodeToRenameRef Node to be renamed
- * @param newName New name for the node
- * @throws FileExistsException
- */
- public void rename(NodeRef nodeToRenameRef, String newName) throws FileExistsException
- {
- try
- {
- fileFolderService.rename(nodeToRenameRef, newName);
- }
- catch (org.alfresco.service.cmr.model.FileExistsException e)
- {
- throw new FileExistsException(newName);
- }
- catch (Throwable e)
- {
- throw new AlfrescoRuntimeException("Rename failed: \n" +
- " node to rename: " + nodeToRenameRef + "\n" +
- " new name: " + newName,
- e);
- }
- }
-
- /**
- * Return the file name for a node
- *
- * @param node NodeRef
- * @return String
- * @throws FileNotFoundException
- */
- public String getFileName(NodeRef node)
- {
- String fname = null;
-
- try
- {
- fname = (String) nodeService.getProperty( node, ContentModel.PROP_NAME);
- }
- catch (InvalidNodeRefException ex)
- {
- }
-
- return fname;
- }
-
- /**
- * Check if the folder node is empty
- *
- * @param folderNode NodeRef
- * @return boolean
- */
- public boolean isFolderEmpty( NodeRef folderNode) {
-
- // Check if the node has any child files/folders
-
- List files = fileFolderService.listFiles( folderNode);
- if ( files == null || files.size() == 0)
- return true;
- return false;
- }
-}
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing" */
+package org.alfresco.filesys.repo;
+
+import java.io.FileNotFoundException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.StringTokenizer;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.jlan.server.filesys.FileAttribute;
+import org.alfresco.jlan.server.filesys.FileExistsException;
+import org.alfresco.jlan.server.filesys.FileName;
+import org.alfresco.jlan.util.WildCard;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.SearchLanguageConversion;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Class with supplying helper methods and potentially acting as a cache for
+ * queries.
+ *
+ * @author derekh
+ */
+public class CifsHelper
+{
+ // Logging
+ private static Log logger = LogFactory.getLog(CifsHelper.class);
+
+ // Services
+ private DictionaryService dictionaryService;
+ private NodeService nodeService;
+ private FileFolderService fileFolderService;
+ private MimetypeService mimetypeService;
+ private PermissionService permissionService;
+ private boolean isReadOnly;
+
+ // Mark locked files as offline
+
+ private boolean lockedFilesAsOffline;
+
+ /**
+ * Class constructor
+ */
+ public CifsHelper()
+ {
+ isReadOnly = false;
+ }
+
+ public void setDictionaryService(DictionaryService dictionaryService)
+ {
+ this.dictionaryService = dictionaryService;
+ }
+
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public void setFileFolderService(FileFolderService fileFolderService)
+ {
+ this.fileFolderService = fileFolderService;
+ }
+
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
+ /**
+ * @return Returns true if all files/folders should be treated as read-only
+ */
+ public boolean isReadOnly()
+ {
+ return isReadOnly;
+ }
+
+ /**
+ * Set whether the system allows files to be edited or not. The default is
+ * to allow writes.
+ * @param allowWrites true to allow writes, otherwise false for read-only mode
+ */
+ public void setAllowWrites(boolean allowWrites)
+ {
+ this.isReadOnly = !allowWrites;
+ }
+
+ /**
+ * Enable marking of locked files as offline
+ *
+ * @param ena boolean
+ */
+ public final void setMarkLockedFilesAsOffline(boolean ena)
+ {
+ lockedFilesAsOffline = ena;
+ }
+
+ /**
+ * Check if locked files should be marked as offline
+ *
+ * @return boolean
+ */
+ public final boolean hasLockedFilesAsOffline()
+ {
+ return lockedFilesAsOffline;
+ }
+
+ /**
+ * @param serviceRegistry for repo connection
+ * @param nodeRef
+ * @return Returns true if the node is a subtype of {@link ContentModel#TYPE_FOLDER folder}
+ * @throws AlfrescoRuntimeException if the type is neither related to a folder or content
+ */
+ public boolean isDirectory(NodeRef nodeRef)
+ {
+ QName nodeTypeQName = nodeService.getType(nodeRef);
+ if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_FOLDER))
+ {
+ return true;
+ }
+ else if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT))
+ {
+ return false;
+ }
+ else
+ {
+ // it is not a directory, but what is it?
+ return false;
+ }
+ }
+
+ /**
+ * Extract a single node's file info, where the node is reference by
+ * a path relative to an ancestor node.
+ *
+ * @param pathRootNodeRef
+ * @param path
+ * @return Returns the existing node reference
+ * @throws FileNotFoundException
+ */
+ public ContentFileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
+ {
+ // get the node being referenced
+ NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
+
+ return getFileInformation(nodeRef);
+ }
+
+ /**
+ * Helper method to extract file info from a specific node.
+ *
+ * This method goes direct to the repo for all information and no data is
+ * cached here.
+ *
+ * @param nodeRef the node that the path is relative to
+ * @param path the path to get info for
+ * @return Returns the file information pertinent to the node
+ * @throws FileNotFoundException if the path refers to a non-existent file
+ */
+ public ContentFileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
+ {
+ // get the file info
+ org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
+
+ // retrieve required properties and create file info
+ ContentFileInfo fileInfo = new ContentFileInfo();
+ fileInfo.setNodeRef(nodeRef);
+
+ // unset all attribute flags
+ int fileAttributes = 0;
+ fileInfo.setFileAttributes(fileAttributes);
+
+ if (fileFolderInfo.isFolder())
+ {
+ // add directory attribute
+ fileAttributes |= FileAttribute.Directory;
+ fileInfo.setFileAttributes(fileAttributes);
+ }
+ else
+ {
+ Map nodeProperties = fileFolderInfo.getProperties();
+
+ // Get the file size from the content
+
+ ContentData contentData = (ContentData) nodeProperties.get(ContentModel.PROP_CONTENT);
+ long size = 0L;
+ if (contentData != null)
+ {
+ size = contentData.getSize();
+ }
+ fileInfo.setSize(size);
+
+ // Set the allocation size by rounding up the size to a 512 byte block boundary
+
+ if ( size > 0)
+ fileInfo.setAllocationSize((size + 512L) & 0xFFFFFFFFFFFFFE00L);
+
+ // Check the lock status of the file
+
+ String lockTypeStr = (String) nodeProperties.get(ContentModel.PROP_LOCK_TYPE);
+
+ if ( lockTypeStr != null )
+ {
+ // File is locked so mark it as read-only and offline
+
+ int attr = fileInfo.getFileAttributes();
+
+ if (( attr & FileAttribute.ReadOnly) == 0)
+ attr += FileAttribute.ReadOnly;
+
+ if ( hasLockedFilesAsOffline())
+ attr += FileAttribute.NTOffline;
+
+ fileInfo.setFileAttributes( attr);
+ }
+
+ // Check if it is a link node
+
+ if ( fileFolderInfo.isLink())
+ fileInfo.setLinkNodeRef( fileFolderInfo.getLinkNodeRef());
+ }
+
+ // created
+ Date createdDate = fileFolderInfo.getCreatedDate();
+ if (createdDate != null)
+ {
+ long created = DefaultTypeConverter.INSTANCE.longValue(createdDate);
+ fileInfo.setCreationDateTime(created);
+ }
+ // modified
+ Date modifiedDate = fileFolderInfo.getModifiedDate();
+ if (modifiedDate != null)
+ {
+ long modified = DefaultTypeConverter.INSTANCE.longValue(modifiedDate);
+ fileInfo.setModifyDateTime(modified);
+ fileInfo.setAccessDateTime(modified);
+ }
+ // name
+ String name = fileFolderInfo.getName();
+ if (name != null)
+ {
+ fileInfo.setFileName(name);
+ }
+
+ // Read/write access
+
+ boolean deniedPermission = permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED;
+ if (isReadOnly || deniedPermission)
+ {
+ int attr = fileInfo.getFileAttributes();
+ if (( attr & FileAttribute.ReadOnly) == 0)
+ {
+ attr += FileAttribute.ReadOnly;
+ fileInfo.setFileAttributes(attr);
+ }
+ }
+
+ // Set the normal file attribute if no other attributes are set
+
+ if ( fileInfo.getFileAttributes() == 0)
+ fileInfo.setFileAttributes(FileAttribute.NTNormal);
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Fetched file info: \n" +
+ " info: " + fileInfo);
+ }
+
+ // Return the file information
+
+ return fileInfo;
+ }
+
+ /**
+ * Creates a file or directory using the given paths.
+ *
+ * If the directory path doesn't exist, then all the parent directories will be created.
+ * If the file path is null, then the file will not be created
+ *
+ * @param rootNodeRef the root node of the path
+ * @param path the path to a node
+ * @param isFile true if the node to be created must be a file
+ * @return Returns a newly created file or folder node
+ * @throws FileExistsException if the file or folder already exists
+ */
+ public NodeRef createNode(NodeRef rootNodeRef, String path, boolean isFile) throws FileExistsException
+ {
+ // split the path up into its constituents
+ StringTokenizer tokenizer = new StringTokenizer(path, FileName.DOS_SEPERATOR_STR, false);
+ List folderPathElements = new ArrayList(10);
+ String name = null;
+ while (tokenizer.hasMoreTokens())
+ {
+ String pathElement = tokenizer.nextToken();
+
+ if (!tokenizer.hasMoreTokens())
+ {
+ // the last token becomes the name
+ name = pathElement;
+ }
+ else
+ {
+ // add the path element to the parent folder path
+ folderPathElements.add(pathElement);
+ }
+ }
+ // ensure that the folder path exists
+ NodeRef parentFolderNodeRef = rootNodeRef;
+ if (folderPathElements.size() > 0)
+ {
+ parentFolderNodeRef = FileFolderServiceImpl.makeFolders(
+ fileFolderService,
+ rootNodeRef,
+ folderPathElements,
+ ContentModel.TYPE_FOLDER).getNodeRef();
+ }
+ // add the file or folder
+ QName typeQName = isFile ? ContentModel.TYPE_CONTENT : ContentModel.TYPE_FOLDER;
+ try
+ {
+ NodeRef nodeRef = fileFolderService.create(parentFolderNodeRef, name, typeQName).getNodeRef();
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Created node: \n" +
+ " device root: " + rootNodeRef + "\n" +
+ " path: " + path + "\n" +
+ " is file: " + isFile + "\n" +
+ " new node: " + nodeRef);
+ }
+ return nodeRef;
+ }
+ catch (org.alfresco.service.cmr.model.FileExistsException e)
+ {
+ throw new FileExistsException(path);
+ }
+ }
+
+ private void addDescendents(List pathRootNodeRefs, Stack pathElements, List results)
+ {
+ if (pathElements.isEmpty())
+ {
+ // if this method is called with an empty path element stack, then the
+ // current context nodes are the results to be added
+ results.addAll(pathRootNodeRefs);
+ return;
+ }
+
+ // take the first path element off the stack
+ String pathElement = pathElements.pop();
+
+ // iterate over each path root node
+ for (NodeRef pathRootNodeRef : pathRootNodeRefs)
+ {
+ // deal with cyclic relationships by not traversing down any node already in the results
+ if (results.contains(pathRootNodeRef))
+ {
+ continue;
+ }
+ // get direct descendents along the path
+ List directDescendents = getDirectDescendents(pathRootNodeRef, pathElement);
+ // recurse onto the descendents
+ addDescendents(directDescendents, pathElements, results);
+ }
+
+ // restore the path element stack
+ pathElements.push(pathElement);
+ }
+
+ /**
+ * Searches for the node or nodes that match the path element for the given parent node
+ */
+ private List getDirectDescendents(NodeRef pathRootNodeRef, String pathElement)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Getting direct descendents: \n" +
+ " Path Root: " + pathRootNodeRef + "\n" +
+ " Path Element: " + pathElement);
+ }
+ List results = null;
+ // if this contains no wildcards, then we can fasttrack it
+ if (!WildCard.containsWildcards(pathElement))
+ {
+ // a specific name is required
+ NodeRef foundNodeRef = fileFolderService.searchSimple(pathRootNodeRef, pathElement);
+ if (foundNodeRef == null)
+ {
+ results = Collections.emptyList();
+ }
+ else
+ {
+ results = Collections.singletonList(foundNodeRef);
+ }
+ }
+ else
+ {
+ // escape for the Lucene syntax search
+ String escapedPathElement = SearchLanguageConversion.convertCifsToLucene(pathElement);
+ // do the lookup
+ List childInfos = fileFolderService.search(
+ pathRootNodeRef,
+ escapedPathElement,
+ false);
+ // convert to noderefs
+ results = new ArrayList(childInfos.size());
+ for (org.alfresco.service.cmr.model.FileInfo info : childInfos)
+ {
+ results.add(info.getNodeRef());
+ }
+ }
+ // done
+ return results;
+ }
+
+ /**
+ * Finds the nodes being reference by the given directory and file paths.
+ *
+ * Examples of the path are:
+ *
+ *
\New Folder\New Text Document.txt
+ *
\New Folder\Sub Folder
+ *
+ *
+ * @param searchRootNodeRef the node from which to start the path search
+ * @param path the search path to either a folder or file
+ * @return Returns references to all matching nodes
+ */
+ public List getNodeRefs(NodeRef pathRootNodeRef, String path)
+ {
+ // tokenize the path and push into a stack in reverse order so that
+ // the root directory gets popped first
+ StringTokenizer tokenizer = new StringTokenizer(path, FileName.DOS_SEPERATOR_STR, false);
+ String[] tokens = new String[tokenizer.countTokens()];
+ int count = 0;
+ while(tokenizer.hasMoreTokens())
+ {
+ tokens[count] = tokenizer.nextToken();
+ count++;
+ }
+ Stack pathElements = new Stack();
+ for (int i = tokens.length - 1; i >= 0; i--)
+ {
+ pathElements.push(tokens[i]);
+ }
+
+ // start with a single parent node
+ List pathRootNodeRefs = Collections.singletonList(pathRootNodeRef);
+
+ // result storage
+ List results = new ArrayList(5);
+
+ // kick off the path walking
+ addDescendents(pathRootNodeRefs, pathElements, results);
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Retrieved node references for path: \n" +
+ " path root: " + pathRootNodeRef + "\n" +
+ " path: " + path + "\n" +
+ " results: " + results);
+ }
+ return results;
+ }
+
+ /**
+ * Attempts to fetch a specific single node at the given path.
+ *
+ * @throws FileNotFoundException if the path can't be resolved to a node
+ *
+ * @see #getNodeRefs(NodeRef, String)
+ */
+ public NodeRef getNodeRef(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
+ {
+ // attempt to get the file/folder node using hierarchy walking
+ List nodeRefs = getNodeRefs(pathRootNodeRef, path);
+ if (nodeRefs.size() == 0)
+ {
+ throw new FileNotFoundException(path);
+ }
+ else if (nodeRefs.size() > 1)
+ {
+ logger.warn("Multiple matching nodes: \n" +
+ " search root: " + pathRootNodeRef + "\n" +
+ " path: " + path);
+ }
+ // take the first one - not sure if it is possible for the path to refer to more than one
+ NodeRef nodeRef = nodeRefs.get(0);
+ // done
+ return nodeRef;
+ }
+
+ /**
+ * Relink the content data from a new node to an existing node to preserve the version history.
+ *
+ * @param oldNodeRef NodeRef
+ * @param newNodeRef NodeRef
+ */
+ public void relinkNode(NodeRef tempNodeRef, NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName)
+ throws FileNotFoundException, FileExistsException
+ {
+ // Get the properties for the old and new nodes
+ org.alfresco.service.cmr.model.FileInfo tempFileInfo = fileFolderService.getFileInfo(tempNodeRef);
+ org.alfresco.service.cmr.model.FileInfo fileToMoveInfo = fileFolderService.getFileInfo(nodeToMoveRef);
+
+ // Save the current name of the old node
+ String tempName = tempFileInfo.getName();
+
+ try
+ {
+ // Rename operation will add or remove the sys:temporary aspect appropriately
+
+ // rename temp file to the new name
+ fileFolderService.rename(tempNodeRef, newName);
+
+ // rename new file to old name
+ fileFolderService.rename(nodeToMoveRef, tempName);
+ }
+ catch (org.alfresco.service.cmr.model.FileNotFoundException e)
+ {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ catch (org.alfresco.service.cmr.model.FileExistsException e)
+ {
+ throw new FileExistsException(e.getMessage());
+ }
+
+ if (!tempFileInfo.isFolder() && !fileToMoveInfo.isFolder())
+ {
+ // swap the content between the two
+ ContentData oldContentData = tempFileInfo.getContentData();
+ if (oldContentData == null)
+ {
+ String mimetype = mimetypeService.guessMimetype(tempName);
+ oldContentData = ContentData.setMimetype(null, mimetype);
+ }
+
+ ContentData newContentData = fileToMoveInfo.getContentData();
+
+ // Reset the mime type
+
+ String mimetype = mimetypeService.guessMimetype(newName);
+ newContentData = ContentData.setMimetype(newContentData, mimetype);
+
+ nodeService.setProperty(tempNodeRef, ContentModel.PROP_CONTENT, newContentData);
+ nodeService.setProperty(nodeToMoveRef, ContentModel.PROP_CONTENT, oldContentData);
+ }
+ }
+
+ /**
+ * Move a node
+ *
+ * @param nodeToMoveRef Node to be moved
+ * @param newParentNodeRef New parent folder node
+ * @param newName New name for the moved node
+ * @throws FileExistsException
+ */
+ public void move(NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName) throws FileExistsException
+ {
+ try
+ {
+ fileFolderService.move(nodeToMoveRef, newParentNodeRef, newName);
+ }
+ catch (org.alfresco.service.cmr.model.FileExistsException e)
+ {
+ throw new FileExistsException(newName);
+ }
+ catch (Throwable e)
+ {
+ throw new AlfrescoRuntimeException("Move failed: \n" +
+ " node to move: " + nodeToMoveRef + "\n" +
+ " new parent: " + newParentNodeRef + "\n" +
+ " new name: " + newName,
+ e);
+ }
+ }
+
+ /**
+ * Rename a node
+ *
+ * @param nodeToRenameRef Node to be renamed
+ * @param newName New name for the node
+ * @throws FileExistsException
+ */
+ public void rename(NodeRef nodeToRenameRef, String newName) throws FileExistsException
+ {
+ try
+ {
+ fileFolderService.rename(nodeToRenameRef, newName);
+ }
+ catch (org.alfresco.service.cmr.model.FileExistsException e)
+ {
+ throw new FileExistsException(newName);
+ }
+ catch (Throwable e)
+ {
+ throw new AlfrescoRuntimeException("Rename failed: \n" +
+ " node to rename: " + nodeToRenameRef + "\n" +
+ " new name: " + newName,
+ e);
+ }
+ }
+
+ /**
+ * Return the file name for a node
+ *
+ * @param node NodeRef
+ * @return String
+ * @throws FileNotFoundException
+ */
+ public String getFileName(NodeRef node)
+ {
+ String fname = null;
+
+ try
+ {
+ fname = (String) nodeService.getProperty( node, ContentModel.PROP_NAME);
+ }
+ catch (InvalidNodeRefException ex)
+ {
+ }
+
+ return fname;
+ }
+
+ /**
+ * Check if the folder node is empty
+ *
+ * @param folderNode NodeRef
+ * @return boolean
+ */
+ public boolean isFolderEmpty( NodeRef folderNode) {
+
+ // Check if the node has any child files/folders
+
+ List files = fileFolderService.listFiles( folderNode);
+ if ( files == null || files.size() == 0)
+ return true;
+ return false;
+ }
+}
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java
index d317444504..fd4f4b99ed 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java
@@ -41,34 +41,32 @@ public class AVMPermissionsPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.updateAvmPermissions.result";
-
+
private AccessControlListDAO accessControlListDao;
private AclDaoComponentImpl aclDaoComponent;
-
+
@Override
protected String applyInternal() throws Exception
{
Thread progressThread = null;
if (aclDaoComponent.supportsProgressTracking())
{
- Long toDo = aclDaoComponent.getAVMHeadNodeCount();
- Long maxId = aclDaoComponent.getMaxAclId();
-
- progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher");
+ progressThread = new Thread(new ProgressWatcher(), "WCMPactchProgressWatcher");
progressThread.start();
}
-
- Map summary = accessControlListDao.patchAcls();
-
+
+ Map summary = this.accessControlListDao.patchAcls();
+
if (progressThread != null)
{
progressThread.interrupt();
progressThread.join();
}
-
+
// build the result message
- String msg = I18NUtil.getMessage(MSG_SUCCESS, summary.get(ACLType.DEFINING), summary.get(ACLType.LAYERED));
+ String msg = I18NUtil.getMessage(AVMPermissionsPatch.MSG_SUCCESS, summary.get(ACLType.DEFINING), summary
+ .get(ACLType.LAYERED));
// done
return msg;
}
@@ -82,8 +80,7 @@ public class AVMPermissionsPatch extends AbstractPatch
{
this.aclDaoComponent = aclDaoComponent;
}
-
-
+
private class ProgressWatcher implements Runnable
{
private boolean running = true;
@@ -92,15 +89,9 @@ public class AVMPermissionsPatch extends AbstractPatch
Long max;
- ProgressWatcher(Long toDo, Long max)
- {
- this.toDo = toDo;
- this.max = max;
- }
-
public void run()
{
- while (running)
+ while (this.running)
{
try
{
@@ -108,27 +99,35 @@ public class AVMPermissionsPatch extends AbstractPatch
}
catch (InterruptedException e)
{
- running = false;
+ this.running = false;
}
- if (running)
+ if (this.running)
{
- RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
+ RetryingTransactionHelper txHelper = AVMPermissionsPatch.this.transactionService
+ .getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback()
{
public Long execute() throws Throwable
{
- return aclDaoComponent.getAVMNodeCountWithNewACLS(max);
+ if (ProgressWatcher.this.toDo == null)
+ {
+ ProgressWatcher.this.toDo = AVMPermissionsPatch.this.aclDaoComponent
+ .getAVMHeadNodeCount();
+ ProgressWatcher.this.max = AVMPermissionsPatch.this.aclDaoComponent.getMaxAclId();
+ }
+ return AVMPermissionsPatch.this.aclDaoComponent
+ .getAVMNodeCountWithNewACLS(ProgressWatcher.this.max);
}
}, true, true);
- reportProgress(toDo, done);
+ reportProgress(this.toDo, done);
}
}
}
}
-
+
}
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java
index 4497cb89e7..3ab5171b4d 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java
@@ -41,34 +41,31 @@ public class DmPermissionsPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.updateDmPermissions.result";
-
+
private AccessControlListDAO accessControlListDao;
private AclDaoComponentImpl aclDaoComponent;
-
+
@Override
protected String applyInternal() throws Exception
{
Thread progressThread = null;
- if (aclDaoComponent.supportsProgressTracking())
+ if (this.aclDaoComponent.supportsProgressTracking())
{
- Long toDo = aclDaoComponent.getDmNodeCount();
- Long maxId = aclDaoComponent.getMaxAclId();
-
- progressThread = new Thread(new ProgressWatcher(toDo, maxId), "DMPatchProgressWatcher");
+ progressThread = new Thread(new ProgressWatcher(), "DMPatchProgressWatcher");
progressThread.start();
}
-
- Map summary = accessControlListDao.patchAcls();
-
+
+ Map summary = this.accessControlListDao.patchAcls();
+
if (progressThread != null)
{
progressThread.interrupt();
progressThread.join();
}
-
+
// build the result message
- String msg = I18NUtil.getMessage(MSG_SUCCESS, summary.get(ACLType.DEFINING));
+ String msg = I18NUtil.getMessage(DmPermissionsPatch.MSG_SUCCESS, summary.get(ACLType.DEFINING));
// done
return msg;
}
@@ -85,14 +82,14 @@ public class DmPermissionsPatch extends AbstractPatch
/**
* Set the acl dao component
+ *
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
-
-
+
private class ProgressWatcher implements Runnable
{
private boolean running = true;
@@ -101,15 +98,9 @@ public class DmPermissionsPatch extends AbstractPatch
Long max;
- ProgressWatcher(Long toDo, Long max)
- {
- this.toDo = toDo;
- this.max = max;
- }
-
public void run()
{
- while (running)
+ while (this.running)
{
try
{
@@ -117,27 +108,35 @@ public class DmPermissionsPatch extends AbstractPatch
}
catch (InterruptedException e)
{
- running = false;
+ this.running = false;
}
- if (running)
+ if (this.running)
{
- RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
+ RetryingTransactionHelper txHelper = DmPermissionsPatch.this.transactionService
+ .getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback()
{
public Long execute() throws Throwable
{
- return aclDaoComponent.getDmNodeCountWithNewACLS(max);
+ if (ProgressWatcher.this.toDo == null)
+ {
+ ProgressWatcher.this.toDo = DmPermissionsPatch.this.aclDaoComponent
+ .getDmNodeCount();
+ ProgressWatcher.this.max = DmPermissionsPatch.this.aclDaoComponent.getMaxAclId();
+ }
+ return DmPermissionsPatch.this.aclDaoComponent
+ .getDmNodeCountWithNewACLS(ProgressWatcher.this.max);
}
}, true, true);
- reportProgress(toDo, done);
+ reportProgress(this.toDo, done);
}
}
}
}
-
+
}
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java
index c54fa710f3..df9066c77b 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java
@@ -24,33 +24,25 @@
*/
package org.alfresco.repo.admin.patch.impl;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import net.sf.acegisecurity.providers.jaas.AuthorityGranter;
-
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.avm.AVMNodeConverter;
-import org.alfresco.repo.avm.AVMRepository;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl;
import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor;
import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
-import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AuthorityService;
@@ -58,7 +50,6 @@ import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
-import org.alfresco.service.transaction.TransactionService;
/**
* Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set
@@ -68,8 +59,11 @@ import org.alfresco.service.transaction.TransactionService;
*/
public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
{
- public static final String[] PERMISSIONS = new String[] { PermissionService.WCM_CONTENT_MANAGER, PermissionService.WCM_CONTENT_PUBLISHER,
- PermissionService.WCM_CONTENT_CONTRIBUTOR, PermissionService.WCM_CONTENT_REVIEWER };
+ public static final String[] PERMISSIONS = new String[]
+ {
+ PermissionService.WCM_CONTENT_MANAGER, PermissionService.WCM_CONTENT_PUBLISHER,
+ PermissionService.WCM_CONTENT_CONTRIBUTOR, PermissionService.WCM_CONTENT_REVIEWER
+ };
private static final String MSG_SUCCESS = "patch.moveWCMToGroupBasedPermissionsPatch.result";
@@ -82,7 +76,7 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
AclDaoComponentImpl aclDaoComponent;
AuthorityService authorityService;
-
+
String replaceAllWith = PermissionService.WCM_CONTENT_MANAGER;
public void setAvmService(AVMService avmService)
@@ -90,7 +84,8 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
this.avmService = avmService;
}
- public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
+ public void setAvmSnapShotTriggeredIndexingMethodInterceptor(
+ AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
{
this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor;
}
@@ -110,8 +105,6 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
this.authorityService = authorityService;
}
-
-
public void setReplaceAllWith(String replaceAllWith)
{
this.replaceAllWith = replaceAllWith;
@@ -121,20 +114,17 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
protected String applyInternal() throws Exception
{
Thread progressThread = null;
- if (aclDaoComponent.supportsProgressTracking())
+ if (this.aclDaoComponent.supportsProgressTracking())
{
- Long toDo = aclDaoComponent.getAVMHeadNodeCount();
- Long maxId = aclDaoComponent.getMaxAclId();
-
- progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher");
+ progressThread = new Thread(new ProgressWatcher(), "WCMPactchProgressWatcher");
progressThread.start();
}
- List stores = avmService.getStores();
+ List stores = this.avmService.getStores();
for (AVMStoreDescriptor store : stores)
{
- Map storeProperties = avmService.getStoreProperties(store.getName());
+ Map storeProperties = this.avmService.getStoreProperties(store.getName());
switch (StoreType.getStoreType(store.getName(), store, storeProperties))
{
@@ -174,14 +164,14 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
}
// build the result message
- String msg = I18NUtil.getMessage(MSG_SUCCESS);
+ String msg = I18NUtil.getMessage(MoveWCMToGroupBasedPermissionsPatch.MSG_SUCCESS);
// done
return msg;
}
private boolean isPermissionSet(NodeRef nodeRef, String authority, String permission)
{
- Set set = permissionService.getAllSetPermissions(nodeRef);
+ Set set = this.permissionService.getAllSetPermissions(nodeRef);
for (AccessPermission ap : set)
{
if (ap.getAuthority().equals(authority) && ap.isSetDirectly() && ap.getPermission().equals(permission))
@@ -194,7 +184,7 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
private boolean isMaskSet(StoreRef storeRef, String authority, String permission)
{
- Set set = permissionService.getAllSetPermissions(storeRef);
+ Set set = this.permissionService.getAllSetPermissions(storeRef);
for (AccessPermission ap : set)
{
if (ap.getAuthority().equals(authority) && ap.isSetDirectly() && ap.getPermission().equals(permission))
@@ -207,14 +197,14 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
private void makeGroupsIfRequired(String stagingStoreName, NodeRef dirRef)
{
- for (String permission : PERMISSIONS)
+ for (String permission : MoveWCMToGroupBasedPermissionsPatch.PERMISSIONS)
{
String shortName = stagingStoreName + "-" + permission;
- String group = authorityService.getName(AuthorityType.GROUP, shortName);
- if (!authorityService.authorityExists(group))
+ String group = this.authorityService.getName(AuthorityType.GROUP, shortName);
+ if (!this.authorityService.authorityExists(group))
{
- String newGroup = authorityService.createAuthority(AuthorityType.GROUP, null, shortName);
- permissionService.setPermission(dirRef, newGroup, permission, true);
+ String newGroup = this.authorityService.createAuthority(AuthorityType.GROUP, null, shortName);
+ this.permissionService.setPermission(dirRef, newGroup, permission, true);
}
}
}
@@ -222,11 +212,11 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
private void addToGroupIfRequired(String stagingStoreName, String user, String permission)
{
String shortName = stagingStoreName + "-" + permission;
- String group = authorityService.getName(AuthorityType.GROUP, shortName);
- Set members = authorityService.getContainedAuthorities(AuthorityType.USER, group, true);
+ String group = this.authorityService.getName(AuthorityType.GROUP, shortName);
+ Set members = this.authorityService.getContainedAuthorities(AuthorityType.USER, group, true);
if (!members.contains(user))
{
- authorityService.addAuthority(group, user);
+ this.authorityService.addAuthority(group, user);
}
}
@@ -246,23 +236,24 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
{
QName propQName = QName.createQName(null, ".web_project.noderef");
- PropertyValue pValue = avmService.getStoreProperty(stagingStoreName, propQName);
+ PropertyValue pValue = this.avmService.getStoreProperty(stagingStoreName, propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (userrole.equals(PermissionService.ALL_PERMISSIONS))
{
- nodeService.setProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE, replaceAllWith);
+ this.nodeService.setProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE, this.replaceAllWith);
}
}
@@ -279,35 +270,37 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
if (!isPermissionSet(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
- permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ,
+ true);
}
// Add group permissions
- for (String permission : PERMISSIONS)
+ for (String permission : MoveWCMToGroupBasedPermissionsPatch.PERMISSIONS)
{
- String cms = authorityService.getName(AuthorityType.GROUP, store.getName() + "-" + permission);
- permissionService.setPermission(dirRef, cms, permission, true);
+ String cms = this.authorityService.getName(AuthorityType.GROUP, store.getName() + "-" + permission);
+ this.permissionService.setPermission(dirRef, cms, permission, true);
}
- PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
+ PropertyValue pValue = this.avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
// remove existing
if (isPermissionSet(dirRef, username, userrole))
{
- permissionService.deletePermission(dirRef, username, userrole);
+ this.permissionService.deletePermission(dirRef, username, userrole);
}
addToGroupIfRequired(store.getName(), username, userrole);
@@ -322,35 +315,38 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
if (!isMaskSet(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
- permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES,
+ PermissionService.READ, true);
}
- String cms = authorityService.getName(AuthorityType.GROUP, store.getName() + "-" + PermissionService.WCM_CONTENT_MANAGER);
+ String cms = this.authorityService.getName(AuthorityType.GROUP, store.getName() + "-"
+ + PermissionService.WCM_CONTENT_MANAGER);
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.CHANGE_PERMISSIONS))
{
- permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.CHANGE_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.CHANGE_PERMISSIONS, true);
}
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.READ_PERMISSIONS))
{
- permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.READ_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.READ_PERMISSIONS, true);
}
QName propQName = QName.createQName(null, ".web_project.noderef");
- PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
+ PropertyValue pValue = this.avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (userrole.equals(PermissionService.WCM_CONTENT_MANAGER))
{
@@ -358,12 +354,14 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
if (isMaskSet(dirRef.getStoreRef(), username, PermissionService.CHANGE_PERMISSIONS))
{
- permissionService.deletePermission(dirRef.getStoreRef(), username, PermissionService.CHANGE_PERMISSIONS);
+ this.permissionService.deletePermission(dirRef.getStoreRef(), username,
+ PermissionService.CHANGE_PERMISSIONS);
}
if (isMaskSet(dirRef.getStoreRef(), username, PermissionService.READ_PERMISSIONS))
{
- permissionService.deletePermission(dirRef.getStoreRef(), username, PermissionService.READ_PERMISSIONS);
+ this.permissionService.deletePermission(dirRef.getStoreRef(), username,
+ PermissionService.READ_PERMISSIONS);
}
}
}
@@ -382,18 +380,21 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, sandBoxStore.getName() + ":/www");
- Map woof = avmService.getStoreProperties(stagingAreaName);
- PropertyValue pValue = avmService.getStoreProperty(stagingAreaName, propQName);
+ Map woof = this.avmService.getStoreProperties(stagingAreaName);
+ PropertyValue pValue = this.avmService.getStoreProperty(stagingAreaName, propQName);
if (!isMaskSet(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
- permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES,
+ PermissionService.READ, true);
}
- String cms = authorityService.getName(AuthorityType.GROUP, stagingAreaName + "-" + PermissionService.WCM_CONTENT_MANAGER);
+ String cms = this.authorityService.getName(AuthorityType.GROUP, stagingAreaName + "-"
+ + PermissionService.WCM_CONTENT_MANAGER);
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.WCM_CONTENT_MANAGER))
{
- permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.WCM_CONTENT_MANAGER, true);
+ this.permissionService
+ .setPermission(dirRef.getStoreRef(), cms, PermissionService.WCM_CONTENT_MANAGER, true);
}
if (pValue != null)
@@ -401,22 +402,24 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (username.equals(owner))
{
- permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.ALL_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), username,
+ PermissionService.ALL_PERMISSIONS, true);
}
else if (userrole.equals("ContentManager"))
{
if (isMaskSet(dirRef.getStoreRef(), username, userrole))
{
- permissionService.deletePermission(dirRef.getStoreRef(), username, userrole);
+ this.permissionService.deletePermission(dirRef.getStoreRef(), username, userrole);
}
}
}
@@ -456,15 +459,13 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
Long max;
- ProgressWatcher(Long toDo, Long max)
+ ProgressWatcher()
{
- this.toDo = toDo;
- this.max = max;
}
public void run()
{
- while (running)
+ while (this.running)
{
try
{
@@ -472,23 +473,32 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
}
catch (InterruptedException e)
{
- running = false;
+ this.running = false;
}
- if (running)
+ if (this.running)
{
- RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
+ RetryingTransactionHelper txHelper = MoveWCMToGroupBasedPermissionsPatch.this.transactionService
+ .getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback()
{
public Long execute() throws Throwable
{
- return aclDaoComponent.getAVMNodeCountWithNewACLS(max);
+ if (ProgressWatcher.this.toDo == null)
+ {
+ ProgressWatcher.this.toDo = MoveWCMToGroupBasedPermissionsPatch.this.aclDaoComponent
+ .getAVMHeadNodeCount();
+ ProgressWatcher.this.max = MoveWCMToGroupBasedPermissionsPatch.this.aclDaoComponent
+ .getMaxAclId();
+ }
+ return MoveWCMToGroupBasedPermissionsPatch.this.aclDaoComponent
+ .getAVMNodeCountWithNewACLS(org.alfresco.repo.admin.patch.impl.MoveWCMToGroupBasedPermissionsPatch.ProgressWatcher.this.max);
}
}, true, true);
- reportProgress(toDo, done);
+ reportProgress(this.toDo, done);
}
}
}
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java
index f37c4ed840..cd2fc774e2 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java
@@ -44,11 +44,9 @@ import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
-import org.alfresco.service.transaction.TransactionService;
/**
* Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set
@@ -73,7 +71,8 @@ public class WCMPermissionPatch extends AbstractPatch
this.avmService = avmService;
}
- public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
+ public void setAvmSnapShotTriggeredIndexingMethodInterceptor(
+ AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
{
this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor;
}
@@ -92,19 +91,16 @@ public class WCMPermissionPatch extends AbstractPatch
protected String applyInternal() throws Exception
{
Thread progressThread = null;
- if (aclDaoComponent.supportsProgressTracking())
+ if (this.aclDaoComponent.supportsProgressTracking())
{
- Long toDo = aclDaoComponent.getAVMHeadNodeCount();
- Long maxId = aclDaoComponent.getMaxAclId();
-
- progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher");
+ progressThread = new Thread(new ProgressWatcher(), "WCMPactchProgressWatcher");
progressThread.start();
}
- List stores = avmService.getStores();
+ List stores = this.avmService.getStores();
for (AVMStoreDescriptor store : stores)
{
- Map storeProperties = avmService.getStoreProperties(store.getName());
+ Map storeProperties = this.avmService.getStoreProperties(store.getName());
switch (StoreType.getStoreType(store.getName(), store, storeProperties))
{
@@ -145,20 +141,20 @@ public class WCMPermissionPatch extends AbstractPatch
}
// build the result message
- String msg = I18NUtil.getMessage(MSG_SUCCESS);
+ String msg = I18NUtil.getMessage(WCMPermissionPatch.MSG_SUCCESS);
// done
return msg;
}
private void clearPermissions(AVMStoreDescriptor store)
{
- AVMNodeDescriptor www = avmService.lookup(-1, store.getName() + ":/www");
+ AVMNodeDescriptor www = this.avmService.lookup(-1, store.getName() + ":/www");
if (www.isLayeredDirectory() && www.isPrimary())
{
// throw away any acl
AVMRepository.GetInstance().setACL(store.getName() + ":/www", null);
// build the default layer acl
- avmService.retargetLayeredDirectory(store.getName() + ":/www", www.getIndirection());
+ this.avmService.retargetLayeredDirectory(store.getName() + ":/www", www.getIndirection());
}
}
@@ -167,23 +163,24 @@ public class WCMPermissionPatch extends AbstractPatch
QName propQName = QName.createQName(null, ".web_project.noderef");
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, store.getName() + ":/www");
- permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
- PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
+ PropertyValue pValue = this.avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
- permissionService.setPermission(dirRef, username, userrole, true);
+ this.permissionService.setPermission(dirRef, username, userrole, true);
}
}
}
@@ -191,28 +188,32 @@ public class WCMPermissionPatch extends AbstractPatch
private void setStagingAreaMasks(AVMStoreDescriptor store)
{
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, store.getName() + ":/www");
- permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES,
+ PermissionService.READ, true);
QName propQName = QName.createQName(null, ".web_project.noderef");
- PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
+ PropertyValue pValue = this.avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (userrole.equals("ContentManager"))
{
- permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.CHANGE_PERMISSIONS, true);
- permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.READ_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), username,
+ PermissionService.CHANGE_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), username,
+ PermissionService.READ_PERMISSIONS, true);
}
}
}
@@ -230,30 +231,33 @@ public class WCMPermissionPatch extends AbstractPatch
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, sandBoxStore.getName() + ":/www");
- Map woof = avmService.getStoreProperties(stagingAreaName);
- PropertyValue pValue = avmService.getStoreProperty(stagingAreaName, propQName);
+ this.avmService.getStoreProperties(stagingAreaName);
+ PropertyValue pValue = this.avmService.getStoreProperty(stagingAreaName, propQName);
- permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES,
+ PermissionService.READ, true);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
- List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+ List userInfoRefs = this.nodeService.getChildAssocs(webProjectNodeRef,
+ WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
- String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
- String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+ String username = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String) this.nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (username.equals(owner))
{
- permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.ALL_PERMISSIONS, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), username,
+ PermissionService.ALL_PERMISSIONS, true);
}
else if (userrole.equals("ContentManager"))
{
- permissionService.setPermission(dirRef.getStoreRef(), username, userrole, true);
+ this.permissionService.setPermission(dirRef.getStoreRef(), username, userrole, true);
}
}
}
@@ -292,15 +296,9 @@ public class WCMPermissionPatch extends AbstractPatch
Long max;
- ProgressWatcher(Long toDo, Long max)
- {
- this.toDo = toDo;
- this.max = max;
- }
-
public void run()
{
- while (running)
+ while (this.running)
{
try
{
@@ -308,23 +306,31 @@ public class WCMPermissionPatch extends AbstractPatch
}
catch (InterruptedException e)
{
- running = false;
+ this.running = false;
}
- if (running)
+ if (this.running)
{
- RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
+ RetryingTransactionHelper txHelper = WCMPermissionPatch.this.transactionService
+ .getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback()
{
public Long execute() throws Throwable
{
- return aclDaoComponent.getAVMNodeCountWithNewACLS(max);
+ if (ProgressWatcher.this.toDo == null)
+ {
+ ProgressWatcher.this.toDo = WCMPermissionPatch.this.aclDaoComponent
+ .getAVMHeadNodeCount();
+ ProgressWatcher.this.max = WCMPermissionPatch.this.aclDaoComponent.getMaxAclId();
+ }
+ return WCMPermissionPatch.this.aclDaoComponent
+ .getAVMNodeCountWithNewACLS(ProgressWatcher.this.max);
}
}, true, true);
- reportProgress(toDo, done);
+ reportProgress(this.toDo, done);
}
}
}
diff --git a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java
index 8a5cb7bd7d..c2b11c5eaa 100644
--- a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java
+++ b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java
@@ -117,14 +117,6 @@ public class AVMSyncServiceImpl implements AVMSyncService
if (fgLogger.isDebugEnabled())
{
fgLogger.debug(srcPath + " : " + dstPath);
- try
- {
- throw new Exception();
- }
- catch (Exception e)
- {
- fgLogger.debug("Stack Trace: ", e);
- }
}
if (srcPath == null || dstPath == null)
{
@@ -410,17 +402,6 @@ public class AVMSyncServiceImpl implements AVMSyncService
boolean overrideConflicts, boolean overrideOlder, String tag, String description)
{
long start = System.currentTimeMillis();
- if (fgLogger.isDebugEnabled())
- {
- try
- {
- throw new Exception("Stack Trace.");
- }
- catch (Exception e)
- {
- fgLogger.debug("Stack trace: ", e);
- }
- }
Map storeVersions = new HashMap();
Set destStores = new HashSet();
for (AVMDifference diff : diffList)
@@ -1028,14 +1009,6 @@ public class AVMSyncServiceImpl implements AVMSyncService
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("flatten: " + layerNode + " " + underlyingNode);
- try
- {
- throw new Exception("Stack Trace:");
- }
- catch (Exception e)
- {
- fgLogger.debug("Stack Trace: ", e);
- }
}
flatten(layerNode, underlyingNode);
}
diff --git a/source/java/org/alfresco/repo/content/AbstractContentStore.java b/source/java/org/alfresco/repo/content/AbstractContentStore.java
index 616327596c..a58bc7081a 100644
--- a/source/java/org/alfresco/repo/content/AbstractContentStore.java
+++ b/source/java/org/alfresco/repo/content/AbstractContentStore.java
@@ -272,4 +272,20 @@ public abstract class AbstractContentStore implements ContentStore
ContentReader reader = getReader(contentUrl);
return reader.exists();
}
+
+ /**
+ * @return Returns -1 always
+ */
+ public long getTotalSize()
+ {
+ return -1L;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getRootLocation()
+ {
+ return ".";
+ }
}
diff --git a/source/java/org/alfresco/repo/content/AbstractRoutingContentStore.java b/source/java/org/alfresco/repo/content/AbstractRoutingContentStore.java
index 73dc4c1666..f661e646d3 100644
--- a/source/java/org/alfresco/repo/content/AbstractRoutingContentStore.java
+++ b/source/java/org/alfresco/repo/content/AbstractRoutingContentStore.java
@@ -245,6 +245,22 @@ public abstract class AbstractRoutingContentStore implements ContentStore
return supported;
}
+ /**
+ * @return Returns . always
+ */
+ public String getRootLocation()
+ {
+ return ".";
+ }
+
+ /**
+ * @return Returns -1 always
+ */
+ public long getTotalSize()
+ {
+ return -1L;
+ }
+
/**
* @see #selectReadStore(String)
*/
diff --git a/source/java/org/alfresco/repo/content/AbstractWritableContentStoreTest.java b/source/java/org/alfresco/repo/content/AbstractWritableContentStoreTest.java
index 8ff56ced5a..72ba9213ca 100644
--- a/source/java/org/alfresco/repo/content/AbstractWritableContentStoreTest.java
+++ b/source/java/org/alfresco/repo/content/AbstractWritableContentStoreTest.java
@@ -102,6 +102,25 @@ public abstract class AbstractWritableContentStoreTest extends AbstractReadOnlyC
ContentStore store = getStore();
assertTrue("The store cannot be read-only", store.isWriteSupported());
}
+
+ /**
+ * Just check that the method doesn't blow up
+ */
+ public void testTotalSize() throws Exception
+ {
+ ContentStore store = getStore();
+ store.getTotalSize();
+ }
+
+ /**
+ * Just check that the method doesn't blow up
+ */
+ public void testRootLocation() throws Exception
+ {
+ ContentStore store = getStore();
+ String rootLocation = store.getRootLocation();
+ assertNotNull("The root location may not be null", rootLocation);
+ }
/**
* Helper to ensure that illegal content URLs are flagged for getWriter requests
diff --git a/source/java/org/alfresco/repo/content/ContentStore.java b/source/java/org/alfresco/repo/content/ContentStore.java
index e10072a98e..28ae8d21d2 100644
--- a/source/java/org/alfresco/repo/content/ContentStore.java
+++ b/source/java/org/alfresco/repo/content/ContentStore.java
@@ -102,6 +102,28 @@ public interface ContentStore
*/
public boolean isWriteSupported();
+ /**
+ * Calculates the total size of content stored.
+ *
+ * NOTE: For efficiency, some implementations may provide a guess. If not, this call could
+ * take a long time.
+ *
+ * Implementations should focus on calculating a size value quickly, rather than accurately.
+ *
+ * @return
+ * Returns the total, possibly approximate size (in bytes) of the binary data stored or -1
+ * if no size data is available.
+ */
+ public long getTotalSize();
+
+ /**
+ * Get the location where the store is rooted. The format of the returned value will depend on the
+ * specific implementation of the store.
+ *
+ * @return Returns the store's root location or . if no information is available
+ */
+ public String getRootLocation();
+
/**
* Check for the existence of content in the store.
*
diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentStoreCreatedEvent.java b/source/java/org/alfresco/repo/content/ContentStoreCreatedEvent.java
similarity index 75%
rename from source/java/org/alfresco/repo/content/filestore/FileContentStoreCreatedEvent.java
rename to source/java/org/alfresco/repo/content/ContentStoreCreatedEvent.java
index 3bb3f0fa11..e1c69e9bd7 100644
--- a/source/java/org/alfresco/repo/content/filestore/FileContentStoreCreatedEvent.java
+++ b/source/java/org/alfresco/repo/content/ContentStoreCreatedEvent.java
@@ -22,10 +22,9 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.repo.content.filestore;
-
-import java.io.File;
+package org.alfresco.repo.content;
+import org.alfresco.repo.content.filestore.FileContentStore;
import org.springframework.context.ApplicationEvent;
/**
@@ -33,14 +32,12 @@ import org.springframework.context.ApplicationEvent;
* purposes.
*
* @author dward
+ * @since 3.1
*/
-public class FileContentStoreCreatedEvent extends ApplicationEvent
+public class ContentStoreCreatedEvent extends ApplicationEvent
{
private static final long serialVersionUID = 7090069096441126707L;
- /** The root directory of the store. */
- private final File rootDirectory;
-
/**
* The Constructor.
*
@@ -49,19 +46,16 @@ public class FileContentStoreCreatedEvent extends ApplicationEvent
* @param rootDirectory
* the root directory
*/
- public FileContentStoreCreatedEvent(FileContentStore source, File rootDirectory)
+ public ContentStoreCreatedEvent(ContentStore source)
{
super(source);
- this.rootDirectory = rootDirectory;
}
-
+
/**
- * Gets the root directory.
- *
- * @return the root directory
+ * @return Returns the source {@link ContentStore}
*/
- public File getRootDirectory()
+ public ContentStore getContentStore()
{
- return this.rootDirectory;
+ return (ContentStore) getSource();
}
}
diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java
index fe4a9b884b..629c2e3f6a 100644
--- a/source/java/org/alfresco/repo/content/RoutingContentService.java
+++ b/source/java/org/alfresco/repo/content/RoutingContentService.java
@@ -200,7 +200,7 @@ public class RoutingContentService implements ContentService, ApplicationContext
Map after)
{
boolean fire = false;
- boolean newContent = false;
+ boolean isNewContent = false;
// check if any of the content properties have changed
for (QName propertyQName : after.keySet())
{
@@ -221,49 +221,39 @@ public class RoutingContentService implements ContentService, ApplicationContext
{
ContentData beforeValue = (ContentData) before.get(propertyQName);
ContentData afterValue = (ContentData) after.get(propertyQName);
- if (afterValue != null && afterValue.getContentUrl() == null)
+ boolean hasContentBefore = ContentData.hasContent(beforeValue);
+ boolean hasContentAfter = ContentData.hasContent(afterValue);
+
+ // There are some shortcuts here
+ if (!hasContentBefore && !hasContentAfter)
{
- // no URL - ignore
+ // Really, nothing happened
+ continue;
}
- else if (!EqualsHelper.nullSafeEquals(beforeValue, afterValue))
+ else if (EqualsHelper.nullSafeEquals(beforeValue, afterValue))
{
- // So debug ...
- if (logger.isDebugEnabled() == true)
- {
- String beforeString = "";
- if (beforeValue != null)
- {
- beforeString = beforeValue.toString();
- }
- String afterString = "";
- if (afterValue != null)
- {
- afterString = afterValue.toString();
- }
- logger.debug("onContentUpate: before = " + beforeString + "; after = " + afterString);
- }
-
- // Figure out if the content is new or not
- String beforeContentUrl = null;
- if (beforeValue != null)
- {
- beforeContentUrl = beforeValue.getContentUrl();
- }
- String afterContentUrl = null;
- if (afterValue != null)
- {
- afterContentUrl = afterValue.getContentUrl();
- }
- if (beforeContentUrl == null && afterContentUrl != null)
- {
- newContent = true;
- }
-
- // the content changed
- // at the moment, we are only interested in this one change
- fire = true;
- break;
+ // Still, nothing happening
+ continue;
}
+
+ // Check for new content
+ isNewContent = !hasContentBefore && hasContentAfter;
+
+ // So debug ...
+ if (logger.isDebugEnabled() == true)
+ {
+ String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
+ logger.debug(
+ "onContentUpdate will fire: \n" +
+ " Name: " + name + "\n" +
+ " Is new: " + isNewContent + "\n" +
+ " Before: " + beforeValue + "\n" +
+ " After: " + afterValue);
+ }
+
+ // We are interested in any content change
+ fire = true;
+ break;
}
catch (ClassCastException e)
{
@@ -278,7 +268,7 @@ public class RoutingContentService implements ContentService, ApplicationContext
Set types = new HashSet(this.nodeService.getAspects(nodeRef));
types.add(this.nodeService.getType(nodeRef));
OnContentUpdatePolicy policy = this.onContentUpdateDelegate.get(nodeRef, types);
- policy.onContentUpdate(nodeRef, newContent);
+ policy.onContentUpdate(nodeRef, isNewContent);
}
}
@@ -327,10 +317,11 @@ public class RoutingContentService implements ContentService, ApplicationContext
Serializable propValue = nodeService.getProperty(nodeRef, propertyQName);
if (propValue instanceof Collection)
{
- Collection colPropValue = (Collection)propValue;
+ @SuppressWarnings("unchecked")
+ Collection colPropValue = (Collection)propValue;
if (colPropValue.size() > 0)
{
- propValue = (Serializable)colPropValue.iterator().next();
+ propValue = colPropValue.iterator().next();
}
}
diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
index b221577067..4eeb51741a 100644
--- a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
+++ b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java
@@ -34,6 +34,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
+import org.alfresco.repo.content.ContentStoreCreatedEvent;
import org.alfresco.repo.content.EmptyContentReader;
import org.alfresco.repo.content.UnsupportedContentUrlException;
import org.alfresco.service.cmr.repository.ContentIOException;
@@ -352,6 +353,53 @@ public class FileContentStore extends AbstractContentStore implements Applicatio
return file.exists();
}
+ /**
+ * Performs a full, deep size calculation
+ */
+ @Override
+ public long getTotalSize()
+ {
+ return calculateDirectorySize(rootDirectory);
+ }
+
+ /**
+ * Recursive directory size calculation
+ */
+ private long calculateDirectorySize(File dir)
+ {
+ int size = 0;
+ File[] files = dir.listFiles();
+ for (File file : files)
+ {
+ if (file.isDirectory())
+ {
+ size += calculateDirectorySize(file);
+ }
+ else
+ {
+ size += file.length();
+ }
+ }
+ return size;
+ }
+
+ /**
+ * @return Returns the canonical path to the root directory
+ */
+ @Override
+ public String getRootLocation()
+ {
+ try
+ {
+ return rootDirectory.getCanonicalPath();
+ }
+ catch (Throwable e)
+ {
+ logger.warn("Unabled to return root location", e);
+ return super.getRootLocation();
+ }
+ }
+
/**
* This implementation requires that the URL start with
* {@link FileContentStore#STORE_PROTOCOL }.
@@ -585,7 +633,7 @@ public class FileContentStore extends AbstractContentStore implements Applicatio
try
{
// Neither context.isActive() or context.isRunning() seem to detect whether the refresh() has completed
- context.publishEvent(new FileContentStoreCreatedEvent(this, rootDirectory));
+ context.publishEvent(new ContentStoreCreatedEvent(this));
}
catch (IllegalStateException e)
{
@@ -593,11 +641,6 @@ public class FileContentStore extends AbstractContentStore implements Applicatio
}
}
- /*
- * (non-Javadoc)
- * @see
- * org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
- */
public void onApplicationEvent(ApplicationEvent event)
{
// Once the context has been refreshed, we tell other interested beans about the existence of this content store
@@ -605,7 +648,7 @@ public class FileContentStore extends AbstractContentStore implements Applicatio
if (event instanceof ContextRefreshedEvent)
{
((ContextRefreshedEvent) event).getApplicationContext().publishEvent(
- new FileContentStoreCreatedEvent(this, rootDirectory));
+ new ContentStoreCreatedEvent(this));
}
}
}
diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java b/source/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java
index 25c6c92d67..5614573ef3 100644
--- a/source/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java
+++ b/source/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java
@@ -88,4 +88,23 @@ public class FileContentStoreTest extends AbstractWritableContentStoreTest
// expected
}
}
+
+ @Override
+ public void testRootLocation() throws Exception
+ {
+ ContentStore store = getStore();
+ String root = store.getRootLocation();
+ assertNotNull("Root value can't be null", root);
+ File dir = new File(root);
+ assertTrue("Root location for FileContentStore must exist", dir.exists());
+ }
+
+ @Override
+ public void testTotalSize() throws Exception
+ {
+ ContentStore store = getStore();
+ store.getWriter(new ContentContext(null, null)).putContent("Test content");
+ long size = store.getTotalSize();
+ assertTrue("Size must be positive", size > 0L);
+ }
}
diff --git a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
index 32467fd151..86a8ef3f3c 100644
--- a/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/RuntimeExecutableContentTransformerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
+ * 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
@@ -56,6 +56,7 @@ public class RuntimeExecutableContentTransformerTest extends BaseAlfrescoTestCas
// the command to execute
RuntimeExec transformCommand = new RuntimeExec();
Map commandMap = new HashMap(5);
+ commandMap.put("Mac OS X", "mv -f ${source} ${target}");
commandMap.put("Linux", "mv -f ${source} ${target}");
commandMap.put(".*", "cmd /c copy /Y \"${source}\" \"${target}\"");
transformCommand.setCommandMap(commandMap);
diff --git a/source/java/org/alfresco/repo/descriptor/RepositoryDescriptorDAOImpl.java b/source/java/org/alfresco/repo/descriptor/RepositoryDescriptorDAOImpl.java
index 4557334807..75e164174e 100644
--- a/source/java/org/alfresco/repo/descriptor/RepositoryDescriptorDAOImpl.java
+++ b/source/java/org/alfresco/repo/descriptor/RepositoryDescriptorDAOImpl.java
@@ -30,6 +30,7 @@ import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -196,20 +197,15 @@ public class RepositoryDescriptorDAOImpl implements DescriptorDAO
// set the properties
if (!this.transactionService.isReadOnly())
{
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_NAME, serverDescriptor
- .getName());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_MAJOR,
- serverDescriptor.getVersionMajor());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_MINOR,
- serverDescriptor.getVersionMinor());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_REVISION,
- serverDescriptor.getVersionRevision());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_LABEL,
- serverDescriptor.getVersionLabel());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_BUILD,
- serverDescriptor.getVersionBuild());
- this.nodeService.setProperty(currentDescriptorNodeRef, ContentModel.PROP_SYS_VERSION_SCHEMA,
- serverDescriptor.getSchema());
+ Map props = new HashMap(11);
+ props.put(ContentModel.PROP_SYS_NAME, serverDescriptor.getName());
+ props.put(ContentModel.PROP_SYS_VERSION_MAJOR, serverDescriptor.getVersionMajor());
+ props.put(ContentModel.PROP_SYS_VERSION_MINOR, serverDescriptor.getVersionMinor());
+ props.put(ContentModel.PROP_SYS_VERSION_REVISION, serverDescriptor.getVersionRevision());
+ props.put(ContentModel.PROP_SYS_VERSION_LABEL, serverDescriptor.getVersionLabel());
+ props.put(ContentModel.PROP_SYS_VERSION_BUILD, serverDescriptor.getVersionBuild());
+ props.put(ContentModel.PROP_SYS_VERSION_SCHEMA, serverDescriptor.getSchema());
+ this.nodeService.addProperties(currentDescriptorNodeRef, props);
// The version edition property may already have been overwritten with a license, so only set the property
// if it doesn't already contain ContentData
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java
index 44c91eb724..9bcc4cc3ef 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java
@@ -39,6 +39,7 @@ import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
import org.alfresco.repo.tenant.SingleTServiceImpl;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
@@ -355,4 +356,20 @@ public class DictionaryDAOTest extends TestCase
assertEquals("three", def3);
}
+ public void testChildAssocPropagate()
+ {
+ // Check the default value
+ AssociationDefinition assocDef = service.getAssociation(QName.createQName(TEST_URL, "childassoc1"));
+ assertNotNull("No such child association found", assocDef);
+ assertTrue("Expected a child association", assocDef instanceof ChildAssociationDefinition);
+ ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef;
+ assertFalse("Expected 'false' for default timestamp propagation", childAssocDef.getPropagateTimestamps());
+
+ // Check the explicit value
+ assocDef = service.getAssociation(QName.createQName(TEST_URL, "childassocPropagate"));
+ assertNotNull("No such child association found", assocDef);
+ assertTrue("Expected a child association", assocDef instanceof ChildAssociationDefinition);
+ childAssocDef = (ChildAssociationDefinition) assocDef;
+ assertTrue("Expected 'true' for timestamp propagation", childAssocDef.getPropagateTimestamps());
+ }
}
diff --git a/source/java/org/alfresco/repo/dictionary/M2ChildAssociation.java b/source/java/org/alfresco/repo/dictionary/M2ChildAssociation.java
index 3b29767875..348a591483 100644
--- a/source/java/org/alfresco/repo/dictionary/M2ChildAssociation.java
+++ b/source/java/org/alfresco/repo/dictionary/M2ChildAssociation.java
@@ -35,6 +35,7 @@ public class M2ChildAssociation extends M2ClassAssociation
{
private String requiredChildName = null;
private Boolean allowDuplicateChildName = null;
+ private Boolean propagateTimestamps = null;
/*package*/ M2ChildAssociation()
@@ -71,4 +72,13 @@ public class M2ChildAssociation extends M2ClassAssociation
this.allowDuplicateChildName = allowDuplicateChildName;
}
+ public boolean isPropagateTimestamps()
+ {
+ return propagateTimestamps == null ? false : propagateTimestamps;
+ }
+
+ public void setPropagateTimestamps(boolean propagateTimestamps)
+ {
+ this.propagateTimestamps = propagateTimestamps;
+ }
}
diff --git a/source/java/org/alfresco/repo/dictionary/M2ChildAssociationDefinition.java b/source/java/org/alfresco/repo/dictionary/M2ChildAssociationDefinition.java
index 53038ad1b2..5a604895f8 100644
--- a/source/java/org/alfresco/repo/dictionary/M2ChildAssociationDefinition.java
+++ b/source/java/org/alfresco/repo/dictionary/M2ChildAssociationDefinition.java
@@ -50,21 +50,20 @@ import org.alfresco.service.namespace.NamespacePrefixResolver;
}
- /* (non-Javadoc)
- * @see org.alfresco.repo.dictionary.ChildAssociationDefinition#getRequiredChildName()
- */
public String getRequiredChildName()
{
return ((M2ChildAssociation)getM2Association()).getRequiredChildName();
}
- /* (non-Javadoc)
- * @see org.alfresco.repo.dictionary.ChildAssociationDefinition#getDuplicateChildNamesAllowed()
- */
public boolean getDuplicateChildNamesAllowed()
{
return ((M2ChildAssociation)getM2Association()).allowDuplicateChildName();
}
-
+
+
+ public boolean getPropagateTimestamps()
+ {
+ return ((M2ChildAssociation)getM2Association()).isPropagateTimestamps();
+ }
}
diff --git a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
index 500c04df53..cc8e44c0c7 100644
--- a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
+++ b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
@@ -109,6 +109,20 @@
fredtrue
+
+
+ true
+ true
+
+
+ test:referenceable
+ false
+ false
+
+ fred
+ true
+ true
+
diff --git a/source/java/org/alfresco/repo/dictionary/m2binding.xml b/source/java/org/alfresco/repo/dictionary/m2binding.xml
index 01b6641f8b..12223aa415 100644
--- a/source/java/org/alfresco/repo/dictionary/m2binding.xml
+++ b/source/java/org/alfresco/repo/dictionary/m2binding.xml
@@ -173,6 +173,7 @@
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/model/filefolder/TempFileMarkerInterceptor.java b/source/java/org/alfresco/repo/model/filefolder/TempFileMarkerInterceptor.java
index 435a205db4..142d965c2c 100644
--- a/source/java/org/alfresco/repo/model/filefolder/TempFileMarkerInterceptor.java
+++ b/source/java/org/alfresco/repo/model/filefolder/TempFileMarkerInterceptor.java
@@ -91,6 +91,7 @@ public class TempFileMarkerInterceptor implements MethodInterceptor
{
FileInfo fileInfo = (FileInfo) ret;
String filename = fileInfo.getName();
+ NodeRef nodeRef = fileInfo.getNodeRef();
if (logger.isDebugEnabled())
{
@@ -98,6 +99,7 @@ public class TempFileMarkerInterceptor implements MethodInterceptor
}
// check against all the regular expressions
+ boolean matched = false;
for (String regexp : filterRegularExpressions)
{
if (!filename.matches(regexp))
@@ -107,8 +109,8 @@ public class TempFileMarkerInterceptor implements MethodInterceptor
}
else
{
+ matched = true;
// it matched, so apply the aspect
- NodeRef nodeRef = fileInfo.getNodeRef();
nodeService.addAspect(nodeRef, ContentModel.ASPECT_TEMPORARY, null);
// no further checking required
if (logger.isDebugEnabled())
@@ -118,6 +120,17 @@ public class TempFileMarkerInterceptor implements MethodInterceptor
break;
}
}
+ // If there was NOT a match then the file should not be marked as temporary
+ // after any of the operations in question.
+ if (!matched && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY))
+ {
+ // Remove the aspect
+ nodeService.removeAspect(nodeRef, ContentModel.ASPECT_TEMPORARY);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Removed temporary marker: " + fileInfo);
+ }
+ }
}
// done
return ret;
diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
index 2757a87675..42cf091efd 100644
--- a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
+++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
@@ -1,502 +1,502 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.repo.transaction;
-
-import java.lang.reflect.Method;
-import java.sql.BatchUpdateException;
-import java.sql.SQLException;
-import java.util.Random;
-
-import javax.transaction.RollbackException;
-import javax.transaction.Status;
-import javax.transaction.UserTransaction;
-
-import net.sf.ehcache.distribution.RemoteCacheException;
-
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.error.ExceptionStackUtil;
-import org.alfresco.repo.security.permissions.AccessDeniedException;
-import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
-import org.alfresco.service.transaction.TransactionService;
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.transaction;
+
+import java.lang.reflect.Method;
+import java.sql.BatchUpdateException;
+import java.sql.SQLException;
+import java.util.Random;
+
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.UserTransaction;
+
+import net.sf.ehcache.distribution.RemoteCacheException;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.error.ExceptionStackUtil;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
+import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.ObjectNotFoundException;
-import org.hibernate.StaleObjectStateException;
-import org.hibernate.StaleStateException;
-import org.hibernate.cache.CacheException;
-import org.hibernate.exception.ConstraintViolationException;
-import org.hibernate.exception.LockAcquisitionException;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.SQLGrammarException;
-import org.springframework.aop.MethodBeforeAdvice;
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.dao.ConcurrencyFailureException;
-import org.springframework.dao.DataIntegrityViolationException;
-import org.springframework.dao.DeadlockLoserDataAccessException;
-import org.springframework.jdbc.UncategorizedSQLException;
-
-/**
- * A helper that runs a unit of work inside a UserTransaction,
- * transparently retrying the unit of work if the cause of
- * failure is an optimistic locking or deadlock condition.
- *
- * Defaults:
- *
- *
maxRetries: 20
- *
minRetryWaitMs: 100
- *
maxRetryWaitMs: 2000
- *
retryWaitIncrementMs: 100
- *
- *
- * To get details of 'why' transactions are retried use the following log level:
- * Summary: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=INFO
- * Details: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=DEBUG
- *
- *
- * @author Derek Hulley
- */
-public class RetryingTransactionHelper
-{
- private static final String MSG_READ_ONLY = "permissions.err_read_only";
- private static final String KEY_ACTIVE_TRANSACTION = "RetryingTransactionHelper.ActiveTxn";
- private static Log logger = LogFactory.getLog(RetryingTransactionHelper.class);
-
- /**
- * Exceptions that trigger retries.
- */
- @SuppressWarnings("unchecked")
- public static final Class[] RETRY_EXCEPTIONS;
- static
- {
- RETRY_EXCEPTIONS = new Class[] {
- ConcurrencyFailureException.class,
- DeadlockLoserDataAccessException.class,
- StaleObjectStateException.class,
- LockAcquisitionException.class,
- ConstraintViolationException.class,
- UncategorizedSQLException.class,
- SQLException.class,
- BatchUpdateException.class,
- DataIntegrityViolationException.class,
- StaleStateException.class,
- ObjectNotFoundException.class,
- CacheException.class, // Usually a cache replication issue
+import org.springframework.aop.MethodBeforeAdvice;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.dao.ConcurrencyFailureException;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.DeadlockLoserDataAccessException;
+import org.springframework.jdbc.UncategorizedSQLException;
+
+/**
+ * A helper that runs a unit of work inside a UserTransaction,
+ * transparently retrying the unit of work if the cause of
+ * failure is an optimistic locking or deadlock condition.
+ *
+ * Defaults:
+ *
+ *
maxRetries: 20
+ *
minRetryWaitMs: 100
+ *
maxRetryWaitMs: 2000
+ *
retryWaitIncrementMs: 100
+ *
+ *
+ * To get details of 'why' transactions are retried use the following log level:
+ * Summary: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=INFO
+ * Details: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=DEBUG
+ *
+ *
+ * @author Derek Hulley
+ */
+public class RetryingTransactionHelper
+{
+ private static final String MSG_READ_ONLY = "permissions.err_read_only";
+ private static final String KEY_ACTIVE_TRANSACTION = "RetryingTransactionHelper.ActiveTxn";
+ private static Log logger = LogFactory.getLog(RetryingTransactionHelper.class);
+
+ /**
+ * Exceptions that trigger retries.
+ */
+ @SuppressWarnings("unchecked")
+ public static final Class[] RETRY_EXCEPTIONS;
+ static
+ {
+ RETRY_EXCEPTIONS = new Class[] {
+ ConcurrencyFailureException.class,
+ DeadlockLoserDataAccessException.class,
+ StaleObjectStateException.class,
+ LockAcquisitionException.class,
+ ConstraintViolationException.class,
+ UncategorizedSQLException.class,
+ SQLException.class,
+ BatchUpdateException.class,
+ DataIntegrityViolationException.class,
+ StaleStateException.class,
+ ObjectNotFoundException.class,
+ CacheException.class, // Usually a cache replication issue
RemoteCacheException.class, // A cache replication issue
SQLGrammarException.class // Actually specific to MS SQL Server 2005 - we check for this
- };
- }
-
- /**
- * Reference to the TransactionService instance.
- */
- private TransactionService txnService;
-
-// /** Performs post-failure exception neatening */
-// private ExceptionTransformer exceptionTransformer;
- /** The maximum number of retries. -1 for infinity. */
- private int maxRetries;
- /** The minimum time to wait between retries. */
- private int minRetryWaitMs;
- /** The maximum time to wait between retries. */
- private int maxRetryWaitMs;
- /** How much to increase the wait time with each retry. */
- private int retryWaitIncrementMs;
-
- /**
- * Whether the the transactions may only be reads
- */
- private boolean readOnly;
-
- /**
- * Random number generator for retry delays.
- */
- private Random random;
-
- /**
- * Callback interface
- * @author britt
- */
- public interface RetryingTransactionCallback
- {
- /**
- * Perform a unit of transactional work.
- *
- * @return Return the result of the unit of work
- * @throws Throwable This can be anything and will guarantee either a retry or a rollback
- */
- public Result execute() throws Throwable;
- };
-
- /**
- * Default constructor.
- */
- public RetryingTransactionHelper()
- {
- this.random = new Random(System.currentTimeMillis());
- this.maxRetries = 20;
- this.minRetryWaitMs = 100;
- this.maxRetryWaitMs = 2000;
- this.retryWaitIncrementMs = 100;
- }
-
- // Setters.
-
-// /**
-// * Optionally set the component that will transform or neaten any exceptions that are
-// * propagated.
-// */
-// public void setExceptionTransformer(ExceptionTransformer exceptionTransformer)
-// {
-// this.exceptionTransformer = exceptionTransformer;
-// }
-//
- /**
- * Set the TransactionService.
- */
- public void setTransactionService(TransactionService service)
- {
- this.txnService = service;
- }
-
- /**
- * Set the maximimum number of retries. -1 for infinity.
- */
- public void setMaxRetries(int maxRetries)
- {
- this.maxRetries = maxRetries;
- }
-
- public void setMinRetryWaitMs(int minRetryWaitMs)
- {
- this.minRetryWaitMs = minRetryWaitMs;
- }
-
- public void setMaxRetryWaitMs(int maxRetryWaitMs)
- {
- this.maxRetryWaitMs = maxRetryWaitMs;
- }
-
- public void setRetryWaitIncrementMs(int retryWaitIncrementMs)
- {
- this.retryWaitIncrementMs = retryWaitIncrementMs;
- }
-
- /**
- * Set whether this helper only supports read transactions.
- */
- public void setReadOnly(boolean readOnly)
- {
- this.readOnly = readOnly;
- }
-
- /**
- * Execute a callback in a transaction until it succeeds, fails
- * because of an error not the result of an optimistic locking failure,
- * or a deadlock loser failure, or until a maximum number of retries have
- * been attempted.
- *
- * If there is already an active transaction, then the callback is merely
- * executed and any retry logic is left to the caller. The transaction
- * will attempt to be read-write.
- *
- * @param cb The callback containing the unit of work.
- * @return Returns the result of the unit of work.
- * @throws RuntimeException all checked exceptions are converted
- */
- public R doInTransaction(RetryingTransactionCallback cb)
- {
- return doInTransaction(cb, false, false);
- }
-
- /**
- * Execute a callback in a transaction until it succeeds, fails
- * because of an error not the result of an optimistic locking failure,
- * or a deadlock loser failure, or until a maximum number of retries have
- * been attempted.
- *
- * If there is already an active transaction, then the callback is merely
- * executed and any retry logic is left to the caller.
- *
- * @param cb The callback containing the unit of work.
- * @param readOnly Whether this is a read only transaction.
- * @return Returns the result of the unit of work.
- * @throws RuntimeException all checked exceptions are converted
- */
- public R doInTransaction(RetryingTransactionCallback cb, boolean readOnly)
- {
- return doInTransaction(cb, readOnly, false);
- }
-
- /**
- * Execute a callback in a transaction until it succeeds, fails
- * because of an error not the result of an optimistic locking failure,
- * or a deadlock loser failure, or until a maximum number of retries have
- * been attempted.
- *
- * It is possible to force a new transaction to be created or to partake in
- * any existing transaction.
- *
- * @param cb The callback containing the unit of work.
- * @param readOnly Whether this is a read only transaction.
- * @param requiresNew true to force a new transaction or
- * false to partake in any existing transaction.
- * @return Returns the result of the unit of work.
- * @throws RuntimeException all checked exceptions are converted
- */
- public R doInTransaction(RetryingTransactionCallback cb, boolean readOnly, boolean requiresNew)
- {
- if (this.readOnly && !readOnly)
- {
- throw new AccessDeniedException(MSG_READ_ONLY);
- }
- // Track the last exception caught, so that we
- // can throw it if we run out of retries.
- RuntimeException lastException = null;
- for (int count = 0; maxRetries < 0 || count < maxRetries; ++count)
- {
- UserTransaction txn = null;
- try
- {
- if (requiresNew)
- {
- txn = txnService.getNonPropagatingUserTransaction(readOnly);
- }
- else
- {
- TxnReadState readState = AlfrescoTransactionSupport.getTransactionReadState();
- switch (readState)
- {
- case TXN_READ_ONLY:
- if (!readOnly)
- {
- // The current transaction is read-only, but a writable transaction is requested
- throw new AlfrescoRuntimeException("Read-Write transaction started within read-only transaction");
- }
- // We are in a read-only transaction and this is what we require so continue with it.
- break;
- case TXN_READ_WRITE:
- // We are in a read-write transaction. It cannot be downgraded so just continue with it.
- break;
- case TXN_NONE:
- // There is no current transaction so we need a new one.
- txn = txnService.getUserTransaction(readOnly);
- break;
- default:
- throw new RuntimeException("Unknown transaction state: " + readState);
- }
- }
- if (txn != null)
- {
- txn.begin();
- // Wrap it to protect it
- UserTransactionProtectionAdvise advise = new UserTransactionProtectionAdvise();
- ProxyFactory proxyFactory = new ProxyFactory(txn);
- proxyFactory.addAdvice(advise);
- UserTransaction wrappedTxn = (UserTransaction) proxyFactory.getProxy();
- // Store the UserTransaction for static retrieval. There is no need to unbind it
- // because the transaction management will do that for us.
- AlfrescoTransactionSupport.bindResource(KEY_ACTIVE_TRANSACTION, wrappedTxn);
- }
- // Do the work.
- R result = cb.execute();
- // Only commit if we 'own' the transaction.
- if (txn != null)
- {
- if (txn.getStatus() == Status.STATUS_MARKED_ROLLBACK)
- {
- // Something caused the transaction to be marked for rollback
- // There is no recovery or retrying with this
- txn.rollback();
- }
- else
- {
- // The transaction hasn't been flagged for failure so the commit
- // sould still be good.
- txn.commit();
- }
- }
- if (logger.isDebugEnabled())
- {
- if (count != 0)
- {
- logger.debug("\n" +
- "Transaction succeeded: \n" +
- " Thread: " + Thread.currentThread().getName() + "\n" +
- " Txn: " + txn + "\n" +
- " Iteration: " + count);
- }
- }
- return result;
- }
- catch (Throwable e)
- {
- // Somebody else 'owns' the transaction, so just rethrow.
- if (txn == null)
- {
- RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException(
- e, "Exception from transactional callback: " + cb);
- throw ee;
- }
- if (logger.isDebugEnabled())
- {
- logger.debug("\n" +
- "Transaction commit failed: \n" +
- " Thread: " + Thread.currentThread().getName() + "\n" +
- " Txn: " + txn + "\n" +
- " Iteration: " + count + "\n" +
- " Exception follows:",
- e);
- }
- // Rollback if we can.
- if (txn != null)
- {
- try
- {
- int txnStatus = txn.getStatus();
- // We can only rollback if a transaction was started (NOT NO_TRANSACTION) and
- // if that transaction has not been rolled back (NOT ROLLEDBACK).
- // If an exception occurs while the transaction is being created (e.g. no database connection)
- // then the status will be NO_TRANSACTION.
- if (txnStatus != Status.STATUS_NO_TRANSACTION && txnStatus != Status.STATUS_ROLLEDBACK)
- {
- txn.rollback();
- }
- }
- catch (Throwable e1)
- {
- // A rollback failure should not preclude a retry, but logging of the rollback failure is required
- logger.error("Rollback failure. Normal retry behaviour will resume.", e1);
- }
- }
- if (e instanceof RollbackException)
- {
- lastException = (e.getCause() instanceof RuntimeException) ?
- (RuntimeException)e.getCause() : new AlfrescoRuntimeException("Exception in Transaction.", e.getCause());
- }
- else
- {
- lastException = (e instanceof RuntimeException) ?
- (RuntimeException)e : new AlfrescoRuntimeException("Exception in Transaction.", e);
- }
- // Check if there is a cause for retrying
- Throwable retryCause = extractRetryCause(e);
- if (retryCause != null)
- {
- // Sleep a random amount of time before retrying.
- // The sleep interval increases with the number of retries.
- int sleepIntervalRandom = count > 0 ? random.nextInt(count * retryWaitIncrementMs) : minRetryWaitMs;
- int sleepInterval = Math.min(maxRetryWaitMs, sleepIntervalRandom);
- sleepInterval = Math.max(sleepInterval, minRetryWaitMs);
- if (logger.isInfoEnabled() && !logger.isDebugEnabled())
- {
- String msg = String.format(
- "Retrying %s: count %2d; wait: %1.1fs; msg: \"%s\"; exception: (%s)",
- Thread.currentThread().getName(),
- count, (double)sleepInterval/1000D,
- retryCause.getMessage(),
- retryCause.getClass().getName());
- logger.info(msg);
- }
- try
- {
- Thread.sleep(sleepInterval);
- }
- catch (InterruptedException ie)
- {
- // Do nothing.
- }
- // Try again
- continue;
- }
- else
- {
- // It was a 'bad' exception.
- throw lastException;
- }
- }
- }
- // We've worn out our welcome and retried the maximum number of times.
- // So, fail.
- throw lastException;
- }
-
- /**
- * Sometimes, the exception means retry and sometimes not.
- *
- * @param cause the cause to examine
- * @return Returns the original cause if it is a valid retry cause, otherwise null
- */
- @SuppressWarnings("unchecked")
- public static Throwable extractRetryCause(Throwable cause)
- {
- Throwable retryCause = ExceptionStackUtil.getCause(cause, RETRY_EXCEPTIONS);
+ };
+ }
+
+ /**
+ * Reference to the TransactionService instance.
+ */
+ private TransactionService txnService;
+
+// /** Performs post-failure exception neatening */
+// private ExceptionTransformer exceptionTransformer;
+ /** The maximum number of retries. -1 for infinity. */
+ private int maxRetries;
+ /** The minimum time to wait between retries. */
+ private int minRetryWaitMs;
+ /** The maximum time to wait between retries. */
+ private int maxRetryWaitMs;
+ /** How much to increase the wait time with each retry. */
+ private int retryWaitIncrementMs;
+
+ /**
+ * Whether the the transactions may only be reads
+ */
+ private boolean readOnly;
+
+ /**
+ * Random number generator for retry delays.
+ */
+ private Random random;
+
+ /**
+ * Callback interface
+ * @author britt
+ */
+ public interface RetryingTransactionCallback
+ {
+ /**
+ * Perform a unit of transactional work.
+ *
+ * @return Return the result of the unit of work
+ * @throws Throwable This can be anything and will guarantee either a retry or a rollback
+ */
+ public Result execute() throws Throwable;
+ };
+
+ /**
+ * Default constructor.
+ */
+ public RetryingTransactionHelper()
+ {
+ this.random = new Random(System.currentTimeMillis());
+ this.maxRetries = 20;
+ this.minRetryWaitMs = 100;
+ this.maxRetryWaitMs = 2000;
+ this.retryWaitIncrementMs = 100;
+ }
+
+ // Setters.
+
+// /**
+// * Optionally set the component that will transform or neaten any exceptions that are
+// * propagated.
+// */
+// public void setExceptionTransformer(ExceptionTransformer exceptionTransformer)
+// {
+// this.exceptionTransformer = exceptionTransformer;
+// }
+//
+ /**
+ * Set the TransactionService.
+ */
+ public void setTransactionService(TransactionService service)
+ {
+ this.txnService = service;
+ }
+
+ /**
+ * Set the maximimum number of retries. -1 for infinity.
+ */
+ public void setMaxRetries(int maxRetries)
+ {
+ this.maxRetries = maxRetries;
+ }
+
+ public void setMinRetryWaitMs(int minRetryWaitMs)
+ {
+ this.minRetryWaitMs = minRetryWaitMs;
+ }
+
+ public void setMaxRetryWaitMs(int maxRetryWaitMs)
+ {
+ this.maxRetryWaitMs = maxRetryWaitMs;
+ }
+
+ public void setRetryWaitIncrementMs(int retryWaitIncrementMs)
+ {
+ this.retryWaitIncrementMs = retryWaitIncrementMs;
+ }
+
+ /**
+ * Set whether this helper only supports read transactions.
+ */
+ public void setReadOnly(boolean readOnly)
+ {
+ this.readOnly = readOnly;
+ }
+
+ /**
+ * Execute a callback in a transaction until it succeeds, fails
+ * because of an error not the result of an optimistic locking failure,
+ * or a deadlock loser failure, or until a maximum number of retries have
+ * been attempted.
+ *
+ * If there is already an active transaction, then the callback is merely
+ * executed and any retry logic is left to the caller. The transaction
+ * will attempt to be read-write.
+ *
+ * @param cb The callback containing the unit of work.
+ * @return Returns the result of the unit of work.
+ * @throws RuntimeException all checked exceptions are converted
+ */
+ public R doInTransaction(RetryingTransactionCallback cb)
+ {
+ return doInTransaction(cb, false, false);
+ }
+
+ /**
+ * Execute a callback in a transaction until it succeeds, fails
+ * because of an error not the result of an optimistic locking failure,
+ * or a deadlock loser failure, or until a maximum number of retries have
+ * been attempted.
+ *
+ * If there is already an active transaction, then the callback is merely
+ * executed and any retry logic is left to the caller.
+ *
+ * @param cb The callback containing the unit of work.
+ * @param readOnly Whether this is a read only transaction.
+ * @return Returns the result of the unit of work.
+ * @throws RuntimeException all checked exceptions are converted
+ */
+ public R doInTransaction(RetryingTransactionCallback cb, boolean readOnly)
+ {
+ return doInTransaction(cb, readOnly, false);
+ }
+
+ /**
+ * Execute a callback in a transaction until it succeeds, fails
+ * because of an error not the result of an optimistic locking failure,
+ * or a deadlock loser failure, or until a maximum number of retries have
+ * been attempted.
+ *
+ * It is possible to force a new transaction to be created or to partake in
+ * any existing transaction.
+ *
+ * @param cb The callback containing the unit of work.
+ * @param readOnly Whether this is a read only transaction.
+ * @param requiresNew true to force a new transaction or
+ * false to partake in any existing transaction.
+ * @return Returns the result of the unit of work.
+ * @throws RuntimeException all checked exceptions are converted
+ */
+ public R doInTransaction(RetryingTransactionCallback cb, boolean readOnly, boolean requiresNew)
+ {
+ if (this.readOnly && !readOnly)
+ {
+ throw new AccessDeniedException(MSG_READ_ONLY);
+ }
+ // Track the last exception caught, so that we
+ // can throw it if we run out of retries.
+ RuntimeException lastException = null;
+ for (int count = 0; count == 0 || count < maxRetries; count++)
+ {
+ UserTransaction txn = null;
+ try
+ {
+ if (requiresNew)
+ {
+ txn = txnService.getNonPropagatingUserTransaction(readOnly);
+ }
+ else
+ {
+ TxnReadState readState = AlfrescoTransactionSupport.getTransactionReadState();
+ switch (readState)
+ {
+ case TXN_READ_ONLY:
+ if (!readOnly)
+ {
+ // The current transaction is read-only, but a writable transaction is requested
+ throw new AlfrescoRuntimeException("Read-Write transaction started within read-only transaction");
+ }
+ // We are in a read-only transaction and this is what we require so continue with it.
+ break;
+ case TXN_READ_WRITE:
+ // We are in a read-write transaction. It cannot be downgraded so just continue with it.
+ break;
+ case TXN_NONE:
+ // There is no current transaction so we need a new one.
+ txn = txnService.getUserTransaction(readOnly);
+ break;
+ default:
+ throw new RuntimeException("Unknown transaction state: " + readState);
+ }
+ }
+ if (txn != null)
+ {
+ txn.begin();
+ // Wrap it to protect it
+ UserTransactionProtectionAdvise advise = new UserTransactionProtectionAdvise();
+ ProxyFactory proxyFactory = new ProxyFactory(txn);
+ proxyFactory.addAdvice(advise);
+ UserTransaction wrappedTxn = (UserTransaction) proxyFactory.getProxy();
+ // Store the UserTransaction for static retrieval. There is no need to unbind it
+ // because the transaction management will do that for us.
+ AlfrescoTransactionSupport.bindResource(KEY_ACTIVE_TRANSACTION, wrappedTxn);
+ }
+ // Do the work.
+ R result = cb.execute();
+ // Only commit if we 'own' the transaction.
+ if (txn != null)
+ {
+ if (txn.getStatus() == Status.STATUS_MARKED_ROLLBACK)
+ {
+ // Something caused the transaction to be marked for rollback
+ // There is no recovery or retrying with this
+ txn.rollback();
+ }
+ else
+ {
+ // The transaction hasn't been flagged for failure so the commit
+ // sould still be good.
+ txn.commit();
+ }
+ }
+ if (logger.isDebugEnabled())
+ {
+ if (count != 0)
+ {
+ logger.debug("\n" +
+ "Transaction succeeded: \n" +
+ " Thread: " + Thread.currentThread().getName() + "\n" +
+ " Txn: " + txn + "\n" +
+ " Iteration: " + count);
+ }
+ }
+ return result;
+ }
+ catch (Throwable e)
+ {
+ // Somebody else 'owns' the transaction, so just rethrow.
+ if (txn == null)
+ {
+ RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException(
+ e, "Exception from transactional callback: " + cb);
+ throw ee;
+ }
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("\n" +
+ "Transaction commit failed: \n" +
+ " Thread: " + Thread.currentThread().getName() + "\n" +
+ " Txn: " + txn + "\n" +
+ " Iteration: " + count + "\n" +
+ " Exception follows:",
+ e);
+ }
+ // Rollback if we can.
+ if (txn != null)
+ {
+ try
+ {
+ int txnStatus = txn.getStatus();
+ // We can only rollback if a transaction was started (NOT NO_TRANSACTION) and
+ // if that transaction has not been rolled back (NOT ROLLEDBACK).
+ // If an exception occurs while the transaction is being created (e.g. no database connection)
+ // then the status will be NO_TRANSACTION.
+ if (txnStatus != Status.STATUS_NO_TRANSACTION && txnStatus != Status.STATUS_ROLLEDBACK)
+ {
+ txn.rollback();
+ }
+ }
+ catch (Throwable e1)
+ {
+ // A rollback failure should not preclude a retry, but logging of the rollback failure is required
+ logger.error("Rollback failure. Normal retry behaviour will resume.", e1);
+ }
+ }
+ if (e instanceof RollbackException)
+ {
+ lastException = (e.getCause() instanceof RuntimeException) ?
+ (RuntimeException)e.getCause() : new AlfrescoRuntimeException("Exception in Transaction.", e.getCause());
+ }
+ else
+ {
+ lastException = (e instanceof RuntimeException) ?
+ (RuntimeException)e : new AlfrescoRuntimeException("Exception in Transaction.", e);
+ }
+ // Check if there is a cause for retrying
+ Throwable retryCause = extractRetryCause(e);
+ if (retryCause != null)
+ {
+ // Sleep a random amount of time before retrying.
+ // The sleep interval increases with the number of retries.
+ int sleepIntervalRandom = count > 0 ? random.nextInt(count * retryWaitIncrementMs) : minRetryWaitMs;
+ int sleepInterval = Math.min(maxRetryWaitMs, sleepIntervalRandom);
+ sleepInterval = Math.max(sleepInterval, minRetryWaitMs);
+ if (logger.isInfoEnabled() && !logger.isDebugEnabled())
+ {
+ String msg = String.format(
+ "Retrying %s: count %2d; wait: %1.1fs; msg: \"%s\"; exception: (%s)",
+ Thread.currentThread().getName(),
+ count, (double)sleepInterval/1000D,
+ retryCause.getMessage(),
+ retryCause.getClass().getName());
+ logger.info(msg);
+ }
+ try
+ {
+ Thread.sleep(sleepInterval);
+ }
+ catch (InterruptedException ie)
+ {
+ // Do nothing.
+ }
+ // Try again
+ continue;
+ }
+ else
+ {
+ // It was a 'bad' exception.
+ throw lastException;
+ }
+ }
+ }
+ // We've worn out our welcome and retried the maximum number of times.
+ // So, fail.
+ throw lastException;
+ }
+
+ /**
+ * Sometimes, the exception means retry and sometimes not.
+ *
+ * @param cause the cause to examine
+ * @return Returns the original cause if it is a valid retry cause, otherwise null
+ */
+ @SuppressWarnings("unchecked")
+ public static Throwable extractRetryCause(Throwable cause)
+ {
+ Throwable retryCause = ExceptionStackUtil.getCause(cause, RETRY_EXCEPTIONS);
if (retryCause == null || retryCause instanceof SQLGrammarException
&& ((SQLGrammarException) retryCause).getErrorCode() != 3960)
- {
- return null;
- }
+ {
+ return null;
+ }
// A simple match
return retryCause;
- }
-
- /**
- * Utility method to get the active transaction. The transaction status can be queried and
- * marked for rollback.
- *
- * NOTE: Any attempt to actually commit or rollback the transaction will cause failures.
- *
- * @return Returns the currently active user transaction or null if
- * there isn't one.
- */
- public static UserTransaction getActiveUserTransaction()
- {
- // Dodge if there is no wrapping transaction
- if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_NONE)
- {
- return null;
- }
- // Get the current transaction. There might not be one if the transaction was not started using
- // this class i.e. it wasn't started with retries.
- UserTransaction txn = (UserTransaction) AlfrescoTransactionSupport.getResource(KEY_ACTIVE_TRANSACTION);
- if (txn == null)
- {
- return null;
- }
- // Done
- return txn;
- }
-
- private static class UserTransactionProtectionAdvise implements MethodBeforeAdvice
- {
- public void before(Method method, Object[] args, Object target) throws Throwable
- {
- String methodName = method.getName();
- if (methodName.equals("begin") || methodName.equals("commit") || methodName.equals("rollback"))
- {
- throw new IllegalAccessException(
- "The user transaction cannot be manipulated from within the transactional work load");
- }
- }
- }
-}
+ }
+
+ /**
+ * Utility method to get the active transaction. The transaction status can be queried and
+ * marked for rollback.
+ *
+ * NOTE: Any attempt to actually commit or rollback the transaction will cause failures.
+ *
+ * @return Returns the currently active user transaction or null if
+ * there isn't one.
+ */
+ public static UserTransaction getActiveUserTransaction()
+ {
+ // Dodge if there is no wrapping transaction
+ if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_NONE)
+ {
+ return null;
+ }
+ // Get the current transaction. There might not be one if the transaction was not started using
+ // this class i.e. it wasn't started with retries.
+ UserTransaction txn = (UserTransaction) AlfrescoTransactionSupport.getResource(KEY_ACTIVE_TRANSACTION);
+ if (txn == null)
+ {
+ return null;
+ }
+ // Done
+ return txn;
+ }
+
+ private static class UserTransactionProtectionAdvise implements MethodBeforeAdvice
+ {
+ public void before(Method method, Object[] args, Object target) throws Throwable
+ {
+ String methodName = method.getName();
+ if (methodName.equals("begin") || methodName.equals("commit") || methodName.equals("rollback"))
+ {
+ throw new IllegalAccessException(
+ "The user transaction cannot be manipulated from within the transactional work load");
+ }
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java
index ca89b6d152..6b0db570e7 100644
--- a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java
+++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelperTest.java
@@ -24,6 +24,8 @@
*/
package org.alfresco.repo.transaction;
+import java.util.ConcurrentModificationException;
+
import javax.transaction.Status;
import javax.transaction.UserTransaction;
@@ -43,6 +45,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
+import org.apache.commons.lang.mutable.MutableInt;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.ConcurrencyFailureException;
@@ -468,11 +471,50 @@ public class RetryingTransactionHelperTest extends TestCase
txnHelper.doInTransaction(killConnectionCallback);
}
+ public void testZeroAndNegativeRetries()
+ {
+ final MutableInt callCount = new MutableInt(0);
+ RetryingTransactionCallback callback = new RetryingTransactionCallback()
+ {
+ public Long execute() throws Throwable
+ {
+ callCount.setValue(callCount.intValue() + 1);
+ throw new ConcurrentModificationException();
+ }
+ };
+ // No retries
+ callCount.setValue(0);
+ txnHelper.setMaxRetries(0);
+ try
+ {
+ txnHelper.doInTransaction(callback);
+ }
+ catch (ConcurrentModificationException e)
+ {
+ // Expected
+ }
+ assertEquals("Should have been called exactly once", 1, callCount.intValue());
+
+ // Negative retries
+ callCount.setValue(0);
+ txnHelper.setMaxRetries(-1);
+ try
+ {
+ txnHelper.doInTransaction(callback);
+ }
+ catch (ConcurrentModificationException e)
+ {
+ // Expected
+ }
+ assertEquals("Should have been called exactly once", 1, callCount.intValue());
+ }
+
/**
* Helper class to kill the session's DB connection
*/
private class HibernateConnectionKiller extends HibernateDaoSupport
{
+ @SuppressWarnings("deprecation")
private void killConnection() throws Exception
{
getSession().connection().rollback();
diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutor.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutor.java
index 4b28a82f60..76a38a05de 100644
--- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutor.java
+++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutor.java
@@ -28,6 +28,7 @@ import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.jbpm.JbpmConfiguration;
import org.jbpm.job.executor.JobExecutor;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
@@ -45,6 +46,7 @@ public class AlfrescoJobExecutor extends JobExecutor
private static Log log = LogFactory.getLog(JobExecutor.class);
private TransactionService transactionService;
+ private JbpmConfiguration jbpmConfiguration;
/**
@@ -55,6 +57,7 @@ public class AlfrescoJobExecutor extends JobExecutor
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
transactionService = (TransactionService)factory.getFactory().getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
+ jbpmConfiguration = (JbpmConfiguration)factory.getFactory().getBean("jbpm_configuration");
}
/**
@@ -74,7 +77,7 @@ public class AlfrescoJobExecutor extends JobExecutor
protected synchronized void startThread()
{
String threadName = getNextThreadName();
- Thread thread = new AlfrescoJobExecutorThread(threadName, this, getJbpmConfiguration(), getIdleInterval(), getMaxIdleInterval(), getMaxLockTime(), getHistoryMaxSize());
+ Thread thread = new AlfrescoJobExecutorThread(threadName, this, jbpmConfiguration, getIdleInterval(), getMaxIdleInterval(), getMaxLockTime(), getHistoryMaxSize());
getThreads().put(threadName, thread);
log.debug("starting new job executor thread '" + threadName + "'");
thread.start();
diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java
index c31cf4aef8..a1d6b3c2d7 100644
--- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java
+++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java
@@ -24,6 +24,11 @@
*/
package org.alfresco.repo.workflow.jbpm;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.jbpm.JbpmConfiguration;
import org.jbpm.job.Job;
@@ -38,6 +43,13 @@ import org.jbpm.job.executor.JobExecutorThread;
public class AlfrescoJobExecutorThread extends JobExecutorThread
{
private AlfrescoJobExecutor alfrescoJobExecutor;
+ private boolean isActive = true;
+
+ @Override
+ public void setActive(boolean isActive)
+ {
+ this.isActive = isActive;
+ }
/**
* Constructor
@@ -48,15 +60,52 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
this.alfrescoJobExecutor = jobExecutor;
}
+ @Override
+ protected Collection acquireJobs()
+ {
+ if (!isActive)
+ {
+ return Collections.EMPTY_LIST;
+ }
+ return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
+ new RetryingTransactionHelper.RetryingTransactionCallback() {
+ public Collection execute() throws Throwable
+ {
+ return AlfrescoJobExecutorThread.super.acquireJobs();
+ }
+ });
+ }
+
+ @Override
+ protected Date getNextDueDate()
+ {
+ if (!isActive)
+ {
+ return null;
+ }
+ return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
+ new RetryingTransactionHelper.RetryingTransactionCallback() {
+ public Date execute() throws Throwable
+ {
+ return AlfrescoJobExecutorThread.super.getNextDueDate();
+ }
+ }, true);
+ }
+
/**
* {@inheritDoc}
*/
@Override
protected void executeJob(Job job)
{
+ if (!isActive)
+ {
+ return;
+ }
alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(new TransactionJob(job));
}
+
/**
* Helper class for holding Job reference
*
@@ -76,14 +125,15 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
this.job = job;
}
- /**
- * {@inheritDoc}
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
*/
public Object execute() throws Throwable
{
AlfrescoJobExecutorThread.super.executeJob(job);
return null;
}
+
}
-
+
}
diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java
index 5404e04bbb..d0be26505f 100644
--- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java
+++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java
@@ -89,7 +89,17 @@ public class AlfrescoTimer extends Timer
@SuppressWarnings("synthetic-access")
public Boolean doWork() throws Exception
{
- return AlfrescoTimer.super.execute(jbpmContext);
+ boolean deleteTimer = AlfrescoTimer.super.execute(jbpmContext);
+
+ // NOTE: there may be an issue in jBPM where a timer that causes a process to
+ // end is deleted twice (once via specific delete operation and once via
+ // delete DML statement) which causes a hibernate exception.
+ // Only delete timer if not at end of process
+ if (getProcessInstance().getEnd() != null)
+ {
+ deleteTimer = false;
+ }
+ return deleteTimer;
}
}, (username == null) ? "system" : username);
diff --git a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml
index cebd0f5951..5711d2e273 100644
--- a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml
+++ b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml
@@ -1,7 +1,14 @@
-
+
-
+
+
+
+
+
+
+
+
@@ -27,7 +34,7 @@
-
+
diff --git a/source/java/org/alfresco/service/cmr/dictionary/ChildAssociationDefinition.java b/source/java/org/alfresco/service/cmr/dictionary/ChildAssociationDefinition.java
index 89f1de7134..61c5043ec4 100644
--- a/source/java/org/alfresco/service/cmr/dictionary/ChildAssociationDefinition.java
+++ b/source/java/org/alfresco/service/cmr/dictionary/ChildAssociationDefinition.java
@@ -43,4 +43,8 @@ public interface ChildAssociationDefinition extends AssociationDefinition
*/
public boolean getDuplicateChildNamesAllowed();
+ /**
+ * @return whether timestamps should be propagated upwards along primary associations
+ */
+ public boolean getPropagateTimestamps();
}
diff --git a/source/java/org/alfresco/service/cmr/repository/ContentData.java b/source/java/org/alfresco/service/cmr/repository/ContentData.java
index 1c7d0ce473..2c1947aa35 100644
--- a/source/java/org/alfresco/service/cmr/repository/ContentData.java
+++ b/source/java/org/alfresco/service/cmr/repository/ContentData.java
@@ -154,6 +154,21 @@ public class ContentData implements Serializable
return ret;
}
+ /**
+ * Helper method to determine if the data represents any physical content or not.
+ *
+ * @param contentData the content to check (may be null)
+ * @return true if the value is non-null and has a content URL of non-zero length
+ */
+ public static boolean hasContent(ContentData contentData)
+ {
+ if (contentData == null)
+ {
+ return false;
+ }
+ return (contentData.contentUrl != null) && (contentData.size > 0L);
+ }
+
/**
* Create a content data using the {@link I18NUtil#getLocale() default locale}.
*
diff --git a/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java b/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java
index f0e9f11099..2cd9ba6557 100644
--- a/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java
+++ b/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java
@@ -1,104 +1,106 @@
-/*
- * 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.wcm;
-
-import junit.framework.TestCase;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.security.AuthenticationService;
-import org.alfresco.service.cmr.security.PersonService;
-import org.alfresco.util.ApplicationContextHelper;
-import org.alfresco.util.PropertyMap;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * Abstract WCM Service implementation unit test
- *
- * @author janv
- */
-public class AbstractWCMServiceImplTest extends TestCase
-{
- // override jbpm.job.executor idleInterval to 10s (was 1.5m) for WCM unit tests
- protected static ApplicationContext ctx =new ClassPathXmlApplicationContext(
- new String[] {ApplicationContextHelper.CONFIG_LOCATIONS[0], "classpath:wcm/wcm-jbpm-context.xml"}
- );
-
- protected static final long SUBMIT_DELAY = 20000L; // 20s - to allow async submit direct workflow to complete (as per 10s idleInterval above)
-
- //
- // test data
- //
-
- protected static final String TEST_RUN = ""+System.currentTimeMillis();
- protected static final boolean CLEAN = true; // cleanup during teardown
-
- //
- // services
- //
-
- protected AuthenticationService authenticationService;
- protected PersonService personService;
-
-
- @Override
- protected void setUp() throws Exception
- {
- // Get the required services
- authenticationService = (AuthenticationService)ctx.getBean("AuthenticationService");
- personService = (PersonService)ctx.getBean("PersonService");
- }
-
- @Override
- protected void tearDown() throws Exception
- {
- }
-
- protected void createUser(String userName)
- {
- if (authenticationService.authenticationExists(userName) == false)
- {
- authenticationService.createAuthentication(userName, "PWD".toCharArray());
-
- PropertyMap ppOne = new PropertyMap(4);
- ppOne.put(ContentModel.PROP_USERNAME, userName);
- ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
- ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
- ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
- ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
-
- personService.createPerson(ppOne);
- }
- }
-
- protected void deleteUser(String userName)
- {
- if (authenticationService.authenticationExists(userName) == true)
- {
- personService.deletePerson(userName);
- authenticationService.deleteAuthentication(userName);
- }
- }
-}
+/*
+ * 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.wcm;
+
+import junit.framework.TestCase;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.alfresco.util.PropertyMap;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Abstract WCM Service implementation unit test
+ *
+ * @author janv
+ */
+public class AbstractWCMServiceImplTest extends TestCase
+{
+ // override jbpm.job.executor idleInterval to 5s (was 1.5m) for WCM unit tests
+ private static final String SUBMIT_CONFIG_LOCATION = "classpath:wcm/wcm-jbpm-context.xml";
+ protected static final long SUBMIT_DELAY = 10000L; // (in millis) 10s - to allow async submit direct workflow to complete (as per 5s idleInterval above)
+
+
+ protected static ApplicationContext ctx =new ClassPathXmlApplicationContext(
+ new String[] {ApplicationContextHelper.CONFIG_LOCATIONS[0], SUBMIT_CONFIG_LOCATION}
+ );
+
+ //
+ // test data
+ //
+
+ protected static final String TEST_RUN = ""+System.currentTimeMillis();
+ protected static final boolean CLEAN = true; // cleanup during teardown
+
+ //
+ // services
+ //
+
+ protected AuthenticationService authenticationService;
+ protected PersonService personService;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ // Get the required services
+ authenticationService = (AuthenticationService)ctx.getBean("AuthenticationService");
+ personService = (PersonService)ctx.getBean("PersonService");
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ }
+
+ protected void createUser(String userName)
+ {
+ if (authenticationService.authenticationExists(userName) == false)
+ {
+ authenticationService.createAuthentication(userName, "PWD".toCharArray());
+
+ PropertyMap ppOne = new PropertyMap(4);
+ ppOne.put(ContentModel.PROP_USERNAME, userName);
+ ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
+ ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
+ ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
+ ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
+
+ personService.createPerson(ppOne);
+ }
+ }
+
+ protected void deleteUser(String userName)
+ {
+ if (authenticationService.authenticationExists(userName) == true)
+ {
+ personService.deletePerson(userName);
+ authenticationService.deleteAuthentication(userName);
+ }
+ }
+}
diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
index 15087fa7d0..92c53bf7c6 100644
--- a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
+++ b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
@@ -52,7 +52,6 @@ import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.DNSNameMangler;
import org.alfresco.util.GUID;
-import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -1013,34 +1012,26 @@ public final class SandboxFactory extends WCMUtil
return workflowStoreName;
}
- public List listSandboxes(final String wpStoreId, String userName)
+ // list all sandboxes for a web project
+ public List listAllSandboxes(final String wpStoreId)
{
- ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
- ParameterCheck.mandatoryString("userName", userName);
+ List stores = avmService.getStores();
- return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork>()
+ List sbInfos = new ArrayList();
+ for (AVMStoreDescriptor store : stores)
{
- public List doWork() throws Exception
+ String storeName = store.getName();
+
+ // list main stores - not preview stores or workflow stores
+ if ((storeName.startsWith(wpStoreId)) &&
+ (! WCMUtil.isPreviewStore(storeName)) &&
+ (! WCMUtil.isWorkflowStore(storeName)))
{
- List stores = avmService.getStores();
-
- List sbInfos = new ArrayList();
- for (AVMStoreDescriptor store : stores)
- {
- String storeName = store.getName();
-
- // list main stores - not preview stores or workflow stores
- if ((storeName.startsWith(wpStoreId)) &&
- (! WCMUtil.isPreviewStore(storeName)) &&
- (! WCMUtil.isWorkflowStore(storeName)))
- {
- sbInfos.add(getSandbox(storeName));
- }
- }
-
- return sbInfos;
+ sbInfos.add(getSandbox(storeName));
}
- }, userName);
+ }
+
+ return sbInfos;
}
public void deleteSandbox(String sbStoreId)
@@ -1146,13 +1137,7 @@ public final class SandboxFactory extends WCMUtil
public void updateSandboxRoles(final String wpStoreId, List usersToUpdate, Set permissionsList)
{
// walk existing user sandboxes and remove manager permissions to exclude old managers
- List sbInfos = AuthenticationUtil.runAs(new RunAsWork>()
- {
- public List doWork() throws Exception
- {
- return listSandboxes(wpStoreId, AuthenticationUtil.getSystemUserName());
- }
- }, AuthenticationUtil.getSystemUserName());
+ List sbInfos = listAllSandboxes(wpStoreId); // all sandboxes
for (SandboxInfo sbInfo : sbInfos)
{
diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxService.java b/source/java/org/alfresco/wcm/sandbox/SandboxService.java
index 4a99a796c1..719d43f94d 100644
--- a/source/java/org/alfresco/wcm/sandbox/SandboxService.java
+++ b/source/java/org/alfresco/wcm/sandbox/SandboxService.java
@@ -314,7 +314,7 @@ public interface SandboxService
*
* @param assets list of assets
*/
- public void revertListNodes(String sbStoreId, List assets);
+ public void revertListAssets(String sbStoreId, List assets);
/**
* Revert sandbox to a specific snapshot version ID (ie. for staging sandbox)
diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java
index 7ad436a1bc..1932658ad5 100644
--- a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java
+++ b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java
@@ -246,7 +246,29 @@ public class SandboxServiceImpl implements SandboxService
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
- return sandboxFactory.listSandboxes(wpStoreId, AuthenticationUtil.getRunAsUser());
+ String currentUser = AuthenticationUtil.getRunAsUser();
+
+ List sbInfos = null;
+
+ if (wpService.isContentManager(wpStoreId, currentUser))
+ {
+ sbInfos = sandboxFactory.listAllSandboxes(wpStoreId);
+ }
+ else
+ {
+ sbInfos = new ArrayList(1);
+
+ SandboxInfo authorSandbox = getAuthorSandbox(wpStoreId, currentUser);
+
+ if (authorSandbox != null)
+ {
+ sbInfos.add(authorSandbox);
+ }
+
+ sbInfos.add(getSandbox(WCMUtil.buildStagingStoreName(wpStoreId))); // get staging sandbox
+ }
+
+ return sbInfos;
}
/* (non-Javadoc)
@@ -262,7 +284,13 @@ public class SandboxServiceImpl implements SandboxService
throw new AccessDeniedException("Only content managers may list sandboxes for '"+userName+"' (web project id: "+wpStoreId+")");
}
- return sandboxFactory.listSandboxes(wpStoreId, userName);
+ return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork>()
+ {
+ public List doWork() throws Exception
+ {
+ return listSandboxes(wpStoreId);
+ }
+ }, userName);
}
/* (non-Javadoc)
@@ -273,7 +301,7 @@ public class SandboxServiceImpl implements SandboxService
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
ParameterCheck.mandatory("sandboxType", sandboxType);
- SandboxInfo sbInfo = sandboxFactory.getSandbox(sbStoreId);
+ SandboxInfo sbInfo = getSandbox(sbStoreId);
if (sbInfo != null)
{
return sbInfo.getSandboxType().equals(sandboxType);
@@ -288,6 +316,24 @@ public class SandboxServiceImpl implements SandboxService
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
+ String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
+
+ // check user has read access to web project (ie. is a web user)
+ if (! wpService.isWebUser(wpStoreId))
+ {
+ return null;
+ }
+
+ if (! WCMUtil.isStagingStore(sbStoreId))
+ {
+ String currentUser = AuthenticationUtil.getRunAsUser();
+
+ if (! ((WCMUtil.getUserName(sbStoreId).equals(currentUser)) || (wpService.isContentManager(wpStoreId, currentUser))))
+ {
+ throw new AccessDeniedException("Only content managers may get sandbox '"+sbStoreId+"' (web project id: "+wpStoreId+")");
+ }
+ }
+
return sandboxFactory.getSandbox(sbStoreId);
}
@@ -310,11 +356,6 @@ public class SandboxServiceImpl implements SandboxService
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
ParameterCheck.mandatoryString("userName", userName);
- if (! wpService.isContentManager(wpStoreId))
- {
- throw new AccessDeniedException("Only content managers may get author sandbox for '"+userName+"' (web project id: "+wpStoreId+")");
- }
-
return getSandbox(WCMUtil.buildUserMainStoreName(WCMUtil.buildStagingStoreName(wpStoreId), userName));
}
@@ -421,6 +462,10 @@ public class SandboxServiceImpl implements SandboxService
ParameterCheck.mandatoryString("dstSandboxStoreId", dstSandboxStoreId);
ParameterCheck.mandatoryString("dstRelativePath", dstRelativePath);
+ // checks sandbox access (TODO review)
+ getSandbox(srcSandboxStoreId); // ignore result
+ getSandbox(dstSandboxStoreId); // ignore result
+
String avmSrcPath = srcSandboxStoreId + WCMUtil.AVM_STORE_SEPARATOR + srcRelativePath;
String avmDstPath = dstSandboxStoreId + WCMUtil.AVM_STORE_SEPARATOR + dstRelativePath;
@@ -567,6 +612,9 @@ public class SandboxServiceImpl implements SandboxService
final String submitLabel, final String submitComment,
final Map expirationDates, final Date launchDate, final boolean validateLinks, final boolean autoDeploy)
{
+ // checks sandbox access (TODO review)
+ getSandbox(sbStoreId); // ignore result
+
final String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
final String stagingSandboxId = WCMUtil.buildStagingStoreName(wpStoreId);
@@ -881,7 +929,7 @@ public class SandboxServiceImpl implements SandboxService
List assets = listChanged(sbStoreId, relativePath, true);
- revertListNodes(sbStoreId, assets);
+ revertListAssets(sbStoreId, assets);
}
/* (non-Javadoc)
@@ -903,16 +951,19 @@ public class SandboxServiceImpl implements SandboxService
}
}
- revertListNodes(sbStoreId, assets);
+ revertListAssets(sbStoreId, assets);
}
/* (non-Javadoc)
- * @see org.alfresco.wcm.sandbox.SandboxService#revertListNodes(java.lang.String, java.util.List)
+ * @see org.alfresco.wcm.sandbox.SandboxService#revertListAssets(java.lang.String, java.util.List)
*/
- public void revertListNodes(String sbStoreId, List assets)
+ public void revertListAssets(String sbStoreId, List assets)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
+ // checks sandbox access (TODO review)
+ getSandbox(sbStoreId); // ignore result
+
List> versionPaths = new ArrayList>(assets.size());
List tasks = null;
@@ -1072,41 +1123,6 @@ public class SandboxServiceImpl implements SandboxService
}
}
- /**
- * Recursively remove locks from a path. Walking child folders looking for files
- * to remove locks from.
- */
- /*
- private void recursivelyRemoveLocks(String wpStoreId, int version, AVMNodeDescriptor desc, String absoluteAVMPath)
- {
- if (desc.isFile() || desc.isDeletedFile())
- {
- avmLockingService.removeLock(wpStoreId, WCMUtil.getStoreRelativePath(absoluteAVMPath));
- }
- else
- {
- if (desc.isDeletedDirectory())
- {
- // lookup the previous child and get its contents
- final List history = avmService.getHistory(desc, 2);
- if (history.size() <= 1)
- {
- return;
- }
- desc = history.get(1);
- }
-
- Map list = avmService.getDirectoryListingDirect(desc, true);
- for (Map.Entry child : list.entrySet())
- {
- String name = child.getKey();
- AVMNodeDescriptor childDesc = child.getValue();
- recursivelyRemoveLocks(wpStoreId, version, childDesc, absoluteAVMPath + "/" + name);
- }
- }
- }
- */
-
/**
* Create Sandbox Transaction listener - invoked after commit
*/
diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java
index 2e5b1eb27d..78a8a866f3 100644
--- a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java
+++ b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java
@@ -1,1634 +1,1969 @@
-/*
- * 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.wcm.sandbox;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.security.permissions.AccessDeniedException;
-import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
-import org.alfresco.service.cmr.avm.AVMService;
-import org.alfresco.service.cmr.repository.ContentReader;
-import org.alfresco.service.cmr.repository.ContentWriter;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.service.transaction.TransactionService;
-import org.alfresco.util.ApplicationContextHelper;
-import org.alfresco.util.PropertyMap;
-import org.alfresco.wcm.AbstractWCMServiceImplTest;
-import org.alfresco.wcm.asset.AssetInfo;
-import org.alfresco.wcm.asset.AssetService;
-import org.alfresco.wcm.util.WCMUtil;
-import org.alfresco.wcm.webproject.WebProjectInfo;
-import org.alfresco.wcm.webproject.WebProjectService;
-
-/**
- * Sandbox Service implementation unit test
- *
- * @author janv
- */
-public class SandboxServiceImplTest extends AbstractWCMServiceImplTest
-{
- // base web project
- private static final String TEST_WEBPROJ_DNS = "testSandbox-"+TEST_RUN;
- private static final String TEST_WEBPROJ_NAME = "testSandbox Web Project Display Name - "+TEST_RUN;
- private static final String TEST_WEBPROJ_TITLE = "This is my title";
- private static final String TEST_WEBPROJ_DESCRIPTION = "This is my description";
- private static final String TEST_WEBPROJ_DEFAULT_WEBAPP = WCMUtil.DIR_ROOT;
- //private static final boolean TEST_WEBPROJ_USE_AS_TEMPLATE = true;
- private static final boolean TEST_WEBPROJ_DONT_USE_AS_TEMPLATE = false;
-
- // base sandbox
- private static final String TEST_SANDBOX = TEST_WEBPROJ_DNS;
-
-
- private static final String USER_ADMIN = "admin";
-
- private static final String TEST_USER = "testSandboxUser-"+TEST_RUN;
-
- private static final String USER_ONE = TEST_USER+"-One";
- private static final String USER_TWO = TEST_USER+"-Two";
- private static final String USER_THREE = TEST_USER+"-Three";
-
- private static final int SCALE_USERS = 5;
- private static final int SCALE_WEBPROJECTS = 2;
-
- //
- // services
- //
-
- private WebProjectService wpService;
- private SandboxService sbService;
- private AssetService assetService;
-
- // TODO: temporary - remove from here when r13170 is merged from V3.1->HEAD
- private TransactionService transactionService;
-
- private AVMService avmService; // non-locking-aware
-
- //private AVMService avmLockingAwareService;
- //private AVMService avmNonLockingAwareService;
-
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
-
- // Get the required services
- wpService = (WebProjectService)ctx.getBean("WebProjectService");
- sbService = (SandboxService)ctx.getBean("SandboxService");
- assetService = (AssetService)ctx.getBean("AssetService");
-
- avmService = (AVMService)ctx.getBean("AVMService");
-
- // TODO: temporary - remove from here when r13170 is merged from V3.1->HEAD
- transactionService = (TransactionService)ctx.getBean("TransactionService");
-
- // WCM locking
- //avmLockingAwareService = (AVMService)ctx.getBean("AVMLockingAwareService");
-
- // without WCM locking
- //avmNonLockingAwareService = (AVMService)ctx.getBean("AVMService");
-
- // By default run as Admin
- AuthenticationUtil.setFullyAuthenticatedUser(USER_ADMIN);
-
- createUser(USER_ONE);
- createUser(USER_TWO);
- createUser(USER_THREE);
- }
-
- @Override
- protected void tearDown() throws Exception
- {
- if (CLEAN)
- {
- // Switch back to Admin
- AuthenticationUtil.setFullyAuthenticatedUser(USER_ADMIN);
-
- List webProjects = wpService.listWebProjects();
- for (final WebProjectInfo wpInfo : webProjects)
- {
- if (wpInfo.getStoreId().startsWith(TEST_WEBPROJ_DNS))
- {
- // TODO: temporary - remove from here when r13170 is merged from V3.1->HEAD
-
- // note: added retry for now, due to intermittent concurrent update (during tearDown) possibly due to OrphanReaper ?
- // org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.alfresco.repo.avm.PlainFileNodeImpl#3752]
- RetryingTransactionCallback