mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-07 18:25:23 +00:00
19546: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19432: Merged V3.1 to V3.2 19427: Merged V3.0 to V3.1 19423: Merged V2.2 to V3.0 19391: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19419: V2.2 Build Fix 19421: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19463: Merged V3.1 to V3.2 19459: Merged V3.0 to V3.1 19457: Merged V2.2 to V3.0 19449: Addition Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19493 Merged V3.1 to V3.2 19471: Build fix after changes for ALF-2076 were merged forward. Index checker correctly understands INDETERMINATE state of indexed transactions 19547: (RECORD ONLY) Incremented version label 19555: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19552: Merged V3.1 to V3.2 19551: Further fix after changes for ALF-2076 were merged forward. Final fix to check for InIndex.No 19566: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19539: Merged HEAD to V3.2 19538: ALF-2076: Build fix - fix build speed 19802: (RECORD ONLY) ALF-2382, ALF-2383: Merged V3.2 to PATCHES/V3.2.r 19647: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19624: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19623: ALF-1890: Correction to previous checkin to allow defaulting of request body charset 19617: ALF-1890: Improvements to make ALL WebDAV methods retryable - Solution from PutMethod promoted to request wrapper that will handle ALL calls to getInputStream and getReader 19614: ALF-1890: Merged V2.2 to V3.2 17709: Merged DEV_TEMPORARY to V2.2 17700: ETWOTWO-1393: concurrent writes to webdav lead to data loss (0kb resulting file) 19613: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 19157: ALF-1890: concurrent writes to webdav lead to data loss (0kb resulting file) 19803: ALF-558: File servers (CIFS / FTP / NFS) can now handle concurrent write operations on Alfresco repository - ContentDiskDriver / AVMDiskDriver now use retrying transactions for write operations - Disable EagerContentStoreCleaner on ContentDiskDriver / AVMDiskDriver closeFile() operations so that they may be retried after rollback (Sony zero byte problem) - Allow manual association of AVM ContentData with nodes so that closeFile() may be retried - Propagation of new argument through AVM interfaces 19804: (RECORD ONLY) Merged PATCHES/V3.2.0 to PATCHES/V3.2.r Merged HEAD to V3.2.0 19786: Refactor of previous test fix. I have pushed down the OOo-specific parts of the change from AbstractContentTransformerTest to OpenOfficeContentTransformerTest leaving an extension point in the base class should other transformations need to be excluded in the future. 19785: Fix for failing test OpenOfficeContentTransformerTest.testAllConversions. Various OOo-related transformations are returned as available but fail on our test server with OOo on it. Pending further work on these failings, I am disabling those transformations in test code whilst leaving them available in the product code. This is because in the wild a different OOo version may succeed with these transformations. I had previously explicitly disabled 3 transformations in the product and I am moving that restriction from product to test code for the same reason. 19707: Return value from isTransformationBlocked was inverted. Fixed now. 19705: Refinement of previous check-in re OOo transformations. I have pulled up the code that handles blocked transformations into a superclass so that the JodConverter-based transformer worker can inherit the same list of blocked transformations. To reiterate, blocked transformations are those that the OOo integration code believes should work but which are broken in practice. These are blocked by the transformers and will always be unavailable regardless of the OOo connection state. 19702: Fix for HEAD builds running on panda build server. OOo was recently installed on panda which has activated various OOo-related transformations/extractions in the test code. It appears that OOo does not support some transformations from Office 97 to Office 2007. Specifically doc to docx and xls to xlsx. These transformations have now been marked as unavailable. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20004 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
394 lines
12 KiB
Java
394 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
package org.alfresco.filesys.alfresco;
|
|
|
|
import java.util.concurrent.Callable;
|
|
|
|
import javax.transaction.Status;
|
|
import javax.transaction.UserTransaction;
|
|
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.jlan.server.SrvSession;
|
|
import org.alfresco.jlan.server.core.DeviceContext;
|
|
import org.alfresco.jlan.server.core.DeviceContextException;
|
|
import org.alfresco.jlan.server.filesys.IOControlNotImplementedException;
|
|
import org.alfresco.jlan.server.filesys.IOCtlInterface;
|
|
import org.alfresco.jlan.server.filesys.NetworkFile;
|
|
import org.alfresco.jlan.server.filesys.TransactionalFilesystemInterface;
|
|
import org.alfresco.jlan.server.filesys.TreeConnection;
|
|
import org.alfresco.jlan.smb.SMBException;
|
|
import org.alfresco.jlan.smb.SMBStatus;
|
|
import org.alfresco.jlan.util.DataBuffer;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|
import org.alfresco.service.ServiceRegistry;
|
|
import org.alfresco.service.transaction.TransactionService;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* Alfresco Disk Driver Base Class
|
|
*
|
|
* <p>Provides common code to the Alfresco filesystem implementations.
|
|
*
|
|
* @author gkspencer
|
|
*/
|
|
public abstract class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesystemInterface, ExtendedDiskInterface {
|
|
|
|
// Logging
|
|
|
|
private static final Log logger = LogFactory.getLog(AlfrescoDiskDriver.class);
|
|
|
|
// Service registry for desktop actions
|
|
|
|
private ServiceRegistry m_serviceRegistry;
|
|
|
|
// Transaction service
|
|
|
|
private TransactionService m_transactionService;
|
|
|
|
// Remember whether the current thread is already in a retrying transaction
|
|
|
|
private ThreadLocal<Boolean> m_inRetryingTransaction = new ThreadLocal<Boolean>();
|
|
|
|
/**
|
|
* Return the service registry
|
|
*
|
|
* @return ServiceRegistry
|
|
*/
|
|
public final ServiceRegistry getServiceRegistry()
|
|
{
|
|
return m_serviceRegistry;
|
|
}
|
|
|
|
/**
|
|
* Return the transaction service
|
|
*
|
|
* @return TransactionService
|
|
*/
|
|
public final TransactionService getTransactionService()
|
|
{
|
|
return m_transactionService;
|
|
}
|
|
|
|
/**
|
|
* Set the service registry
|
|
*
|
|
* @param serviceRegistry
|
|
*/
|
|
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
|
{
|
|
m_serviceRegistry = serviceRegistry;
|
|
}
|
|
|
|
/**
|
|
* @param transactionService the transaction service
|
|
*/
|
|
public void setTransactionService(TransactionService transactionService)
|
|
{
|
|
m_transactionService = transactionService;
|
|
}
|
|
|
|
/**
|
|
* Process a filesystem I/O control request
|
|
*
|
|
* @param sess Server session
|
|
* @param tree Tree connection.
|
|
* @param ctrlCode I/O control code
|
|
* @param fid File id
|
|
* @param dataBuf I/O control specific input data
|
|
* @param isFSCtrl true if this is a filesystem control, or false for a device control
|
|
* @param filter if bit0 is set indicates that the control applies to the share root handle
|
|
* @return DataBuffer
|
|
* @exception IOControlNotImplementedException
|
|
* @exception SMBException
|
|
*/
|
|
public DataBuffer processIOControl(SrvSession sess, TreeConnection tree, int ctrlCode, int fid, DataBuffer dataBuf,
|
|
boolean isFSCtrl, int filter)
|
|
throws IOControlNotImplementedException, SMBException
|
|
{
|
|
// Validate the file id
|
|
|
|
NetworkFile netFile = tree.findFile(fid);
|
|
if ( netFile == null || netFile.isDirectory() == false)
|
|
throw new SMBException(SMBStatus.NTErr, SMBStatus.NTInvalidParameter);
|
|
|
|
// Check if the I/O control handler is enabled
|
|
|
|
AlfrescoContext ctx = (AlfrescoContext) tree.getContext();
|
|
if ( ctx.hasIOHandler())
|
|
return ctx.getIOHandler().processIOControl( sess, tree, ctrlCode, fid, dataBuf, isFSCtrl, filter);
|
|
else
|
|
throw new IOControlNotImplementedException();
|
|
}
|
|
|
|
/**
|
|
* Begin a read-only transaction
|
|
*
|
|
* @param sess SrvSession
|
|
*/
|
|
public void beginReadTransaction(SrvSession sess) {
|
|
beginTransaction( sess, true);
|
|
}
|
|
|
|
/**
|
|
* Begin a writeable transaction
|
|
*
|
|
* @param sess SrvSession
|
|
*/
|
|
public void beginWriteTransaction(SrvSession sess) {
|
|
beginTransaction( sess, false);
|
|
}
|
|
|
|
/**
|
|
* Perform a retryable operation in a write transaction
|
|
*
|
|
* @param sess
|
|
* the server session
|
|
* @param callback
|
|
* callback for the retryable operation
|
|
* @return the result of the operation
|
|
*/
|
|
public <T> T doInWriteTransaction(SrvSession sess, final Callable<T> callback)
|
|
{
|
|
Boolean wasInRetryingTransaction = m_inRetryingTransaction.get();
|
|
try
|
|
{
|
|
boolean hadTransaction = sess.hasTransaction();
|
|
if (hadTransaction)
|
|
{
|
|
sess.endTransaction();
|
|
}
|
|
m_inRetryingTransaction.set(Boolean.TRUE);
|
|
T result = m_transactionService.getRetryingTransactionHelper().doInTransaction(
|
|
new RetryingTransactionHelper.RetryingTransactionCallback<T>()
|
|
{
|
|
|
|
public T execute() throws Throwable
|
|
{
|
|
return callback.call();
|
|
}
|
|
});
|
|
if (hadTransaction)
|
|
{
|
|
beginReadTransaction(sess);
|
|
}
|
|
return result;
|
|
}
|
|
finally
|
|
{
|
|
m_inRetryingTransaction.set(wasInRetryingTransaction);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* End an active transaction
|
|
*
|
|
* @param sess SrvSession
|
|
* @param tx Object
|
|
*/
|
|
public void endTransaction(SrvSession sess, Object tx) {
|
|
|
|
// Check that the transaction object is valid
|
|
|
|
if ( tx == null)
|
|
return;
|
|
|
|
// Get the filesystem transaction
|
|
|
|
FilesysTransaction filesysTx = (FilesysTransaction) tx;
|
|
|
|
// Check if there is an active transaction
|
|
|
|
if ( filesysTx != null && filesysTx.hasTransaction())
|
|
{
|
|
// Get the active transaction
|
|
|
|
UserTransaction ftx = filesysTx.getTransaction();
|
|
|
|
try
|
|
{
|
|
// Commit or rollback the transaction
|
|
|
|
if ( ftx.getStatus() == Status.STATUS_MARKED_ROLLBACK ||
|
|
ftx.getStatus() == Status.STATUS_ROLLEDBACK ||
|
|
ftx.getStatus() == Status.STATUS_ROLLING_BACK)
|
|
{
|
|
// Transaction is marked for rollback
|
|
|
|
ftx.rollback();
|
|
|
|
// DEBUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("End transaction (rollback)");
|
|
}
|
|
else
|
|
{
|
|
// Commit the transaction
|
|
|
|
ftx.commit();
|
|
|
|
// DEBUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("End transaction (commit)");
|
|
}
|
|
}
|
|
catch ( Exception ex)
|
|
{
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("Failed to end transaction, " + ex.getMessage());
|
|
// throw new AlfrescoRuntimeException("Failed to end transaction", ex);
|
|
}
|
|
finally
|
|
{
|
|
// Clear the current transaction
|
|
|
|
sess.clearTransaction();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create and start a transaction, if not already active
|
|
*
|
|
* @param sess SrvSession
|
|
* @param readOnly boolean
|
|
* @exception AlfrescoRuntimeException
|
|
*/
|
|
private final void beginTransaction( SrvSession sess, boolean readOnly)
|
|
throws AlfrescoRuntimeException
|
|
{
|
|
// Do nothing if we are already in a retrying transaction
|
|
Boolean inRetryingTransaction = m_inRetryingTransaction.get();
|
|
|
|
if (inRetryingTransaction != null && inRetryingTransaction)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Initialize the per session thread local that holds the transaction
|
|
|
|
sess.initializeTransactionObject();
|
|
|
|
// Get the filesystem transaction
|
|
|
|
FilesysTransaction filesysTx = (FilesysTransaction) sess.getTransactionObject().get();
|
|
if ( filesysTx == null)
|
|
{
|
|
filesysTx = new FilesysTransaction();
|
|
sess.getTransactionObject().set( filesysTx);
|
|
}
|
|
|
|
// If there is an active transaction check that it is the required type
|
|
|
|
if ( filesysTx.hasTransaction())
|
|
{
|
|
// Get the active transaction
|
|
|
|
UserTransaction tx = filesysTx.getTransaction();
|
|
|
|
// Check if the current transaction is marked for rollback
|
|
|
|
try
|
|
{
|
|
if ( tx.getStatus() == Status.STATUS_MARKED_ROLLBACK ||
|
|
tx.getStatus() == Status.STATUS_ROLLEDBACK ||
|
|
tx.getStatus() == Status.STATUS_ROLLING_BACK)
|
|
{
|
|
// Rollback the current transaction
|
|
|
|
tx.rollback();
|
|
}
|
|
}
|
|
catch ( Exception ex)
|
|
{
|
|
}
|
|
|
|
// Check if the transaction is a write transaction, if write has been requested
|
|
|
|
if ( readOnly == false && filesysTx.isReadOnly() == true)
|
|
{
|
|
// Commit the read-only transaction
|
|
|
|
try
|
|
{
|
|
tx.commit();
|
|
}
|
|
catch ( Exception ex)
|
|
{
|
|
throw new AlfrescoRuntimeException("Failed to commit read-only transaction, " + ex.getMessage());
|
|
}
|
|
finally
|
|
{
|
|
// Clear the active transaction
|
|
|
|
filesysTx.clearTransaction();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create the transaction
|
|
|
|
if ( filesysTx.hasTransaction() == false)
|
|
{
|
|
try
|
|
{
|
|
// Create a new transaction
|
|
|
|
UserTransaction userTrans = m_transactionService.getUserTransaction(readOnly);
|
|
userTrans.begin();
|
|
|
|
// Store the transaction
|
|
|
|
filesysTx.setTransaction( userTrans, readOnly);
|
|
|
|
// DEBUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("Created transaction readOnly=" + readOnly);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new AlfrescoRuntimeException("Failed to create transaction, " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
// Store the transaction callback
|
|
|
|
sess.setTransaction( this);
|
|
}
|
|
|
|
/**
|
|
* Registers a device context object for this instance
|
|
* of the shared device. The same DeviceInterface implementation may be used for multiple
|
|
* shares. In this base class, we initialize all desktop actions.
|
|
*
|
|
* @param ctx the context
|
|
* @exception DeviceContextException
|
|
*/
|
|
public void registerContext(DeviceContext ctx) throws DeviceContextException
|
|
{
|
|
if (ctx instanceof AlfrescoContext)
|
|
{
|
|
((AlfrescoContext) ctx).initialize(this);
|
|
}
|
|
}
|
|
}
|