mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud)
68223: Merged V4.2-BUG-FIX (4.2.3) to HEAD-BUG-FIX (4.3/Cloud) 67994: Merged V4.2.2 (4.2.2) to V4.2-BUG-FIX (4.2.3) 67783: Merged DEV to V4.2.2-PATHCES (4.2.2) 67645: MNT-10679: BM-0012: Run v420b1494_01: Exception from executeScript - Catch SocketException and report in log that client has cut off communication. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@68471 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -20,6 +20,7 @@ package org.alfresco.repo.web.scripts;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
@@ -371,145 +373,167 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
|
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
final Description description = script.getDescription();
|
try
|
||||||
if (description.getRequiredTransaction() == RequiredTransaction.none)
|
|
||||||
{
|
{
|
||||||
script.execute(scriptReq, scriptRes);
|
final Description description = script.getDescription();
|
||||||
}
|
if (description.getRequiredTransaction() == RequiredTransaction.none)
|
||||||
else
|
|
||||||
{
|
|
||||||
final BufferedRequest bufferedReq;
|
|
||||||
final BufferedResponse bufferedRes;
|
|
||||||
RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
|
|
||||||
if (trxParams.getCapability() == TransactionCapability.readwrite)
|
|
||||||
{
|
{
|
||||||
if (trxParams.getBufferSize() > 0)
|
script.execute(scriptReq, scriptRes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final BufferedRequest bufferedReq;
|
||||||
|
final BufferedResponse bufferedRes;
|
||||||
|
RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
|
||||||
|
if (trxParams.getCapability() == TransactionCapability.readwrite)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (trxParams.getBufferSize() > 0)
|
||||||
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
|
||||||
|
|
||||||
// create buffered request and response that allow transaction retrying
|
// create buffered request and response that allow transaction retrying
|
||||||
bufferedReq = new BufferedRequest(scriptReq, streamFactory);
|
bufferedReq = new BufferedRequest(scriptReq, streamFactory);
|
||||||
bufferedRes = new BufferedResponse(scriptRes, trxParams.getBufferSize());
|
bufferedRes = new BufferedResponse(scriptRes, trxParams.getBufferSize());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
|
||||||
|
bufferedReq = null;
|
||||||
|
bufferedRes = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
|
|
||||||
bufferedReq = null;
|
bufferedReq = null;
|
||||||
bufferedRes = null;
|
bufferedRes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encapsulate script within transaction
|
||||||
|
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>()
|
||||||
|
{
|
||||||
|
public Object execute() throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + ","
|
||||||
|
+ description.getRequiredTransactionParameters().getCapability());
|
||||||
|
|
||||||
|
if (bufferedRes == null)
|
||||||
|
{
|
||||||
|
script.execute(scriptReq, scriptRes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reset the request and response in case of a transaction retry
|
||||||
|
bufferedReq.reset();
|
||||||
|
bufferedRes.reset();
|
||||||
|
script.execute(bufferedReq, bufferedRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
|
||||||
|
// Note: user transaction shouldn't be null, but just in case inside this exception handler
|
||||||
|
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
||||||
|
if (userTrx != null)
|
||||||
|
{
|
||||||
|
logger.debug("Transaction status: " + userTrx.getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
||||||
|
if (userTrx != null)
|
||||||
|
{
|
||||||
|
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Marking web script transaction for rollback");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
userTrx.setRollbackOnly();
|
||||||
|
}
|
||||||
|
catch(Throwable re)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-throw original exception for retry
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + ","
|
||||||
|
+ description.getRequiredTransactionParameters().getCapability());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
|
||||||
|
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
|
||||||
|
|
||||||
|
// log a warning if we detect a GET webscript being run in a readwrite transaction, GET calls should
|
||||||
|
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
|
||||||
|
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(description.getMethod()))
|
||||||
|
{
|
||||||
|
logger.debug("Webscript with URL '" + scriptReq.getURL() +
|
||||||
|
"' is a GET request but it's descriptor has declared a readwrite transaction is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
transactionService.getRetryingTransactionHelper().doInTransaction(work, readonly, requiresNew);
|
||||||
|
}
|
||||||
|
catch (TooBusyException e)
|
||||||
|
{
|
||||||
|
// Map TooBusyException to a 503 status code
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Get rid of any temporary files
|
||||||
|
if (bufferedReq != null)
|
||||||
|
{
|
||||||
|
bufferedReq.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a response is always flushed after successful execution
|
||||||
|
if (bufferedRes != null)
|
||||||
|
{
|
||||||
|
bufferedRes.writeResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
Throwable socketException = ExceptionStackUtil.getCause(ioe, SocketException.class);
|
||||||
|
if (socketException != null && socketException.getMessage().contains("Broken pipe"))
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.warn("Client has cut off communication", ioe);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.info("Client has cut off communication");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bufferedReq = null;
|
throw ioe;
|
||||||
bufferedRes = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// encapsulate script within transaction
|
|
||||||
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>()
|
|
||||||
{
|
|
||||||
public Object execute() throws Exception
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + ","
|
|
||||||
+ description.getRequiredTransactionParameters().getCapability());
|
|
||||||
|
|
||||||
if (bufferedRes == null)
|
|
||||||
{
|
|
||||||
script.execute(scriptReq, scriptRes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Reset the request and response in case of a transaction retry
|
|
||||||
bufferedReq.reset();
|
|
||||||
bufferedRes.reset();
|
|
||||||
script.execute(bufferedReq, bufferedRes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
|
|
||||||
// Note: user transaction shouldn't be null, but just in case inside this exception handler
|
|
||||||
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
|
||||||
if (userTrx != null)
|
|
||||||
{
|
|
||||||
logger.debug("Transaction status: " + userTrx.getStatus());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
|
||||||
if (userTrx != null)
|
|
||||||
{
|
|
||||||
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Marking web script transaction for rollback");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
userTrx.setRollbackOnly();
|
|
||||||
}
|
|
||||||
catch(Throwable re)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// re-throw original exception for retry
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + ","
|
|
||||||
+ description.getRequiredTransactionParameters().getCapability());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
|
|
||||||
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
|
|
||||||
|
|
||||||
// log a warning if we detect a GET webscript being run in a readwrite transaction, GET calls should
|
|
||||||
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
|
|
||||||
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(description.getMethod()))
|
|
||||||
{
|
|
||||||
logger.debug("Webscript with URL '" + scriptReq.getURL() +
|
|
||||||
"' is a GET request but it's descriptor has declared a readwrite transaction is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
transactionService.getRetryingTransactionHelper().doInTransaction(work, readonly, requiresNew);
|
|
||||||
}
|
|
||||||
catch (TooBusyException e)
|
|
||||||
{
|
|
||||||
// Map TooBusyException to a 503 status code
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Get rid of any temporary files
|
|
||||||
if (bufferedReq != null)
|
|
||||||
{
|
|
||||||
bufferedReq.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure a response is always flushed after successful execution
|
|
||||||
if (bufferedRes != null)
|
|
||||||
{
|
|
||||||
bufferedRes.writeResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user