mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Added trace debugging categories to catch unclosed IO Channels and unclosed UserTransactions
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2382 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -26,6 +26,7 @@ import java.nio.channels.ReadableByteChannel;
|
|||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.error.StackTraceUtil;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil;
|
import org.alfresco.repo.transaction.TransactionUtil;
|
||||||
import org.alfresco.service.cmr.repository.ContentAccessor;
|
import org.alfresco.service.cmr.repository.ContentAccessor;
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
@@ -44,6 +45,16 @@ import org.springframework.aop.AfterReturningAdvice;
|
|||||||
public abstract class AbstractContentAccessor implements ContentAccessor
|
public abstract class AbstractContentAccessor implements ContentAccessor
|
||||||
{
|
{
|
||||||
private static Log logger = LogFactory.getLog(AbstractContentAccessor.class);
|
private static Log logger = LogFactory.getLog(AbstractContentAccessor.class);
|
||||||
|
private static final Log loggerTrace = LogFactory.getLog(AbstractContentAccessor.class.getName() + ".trace");
|
||||||
|
static
|
||||||
|
{
|
||||||
|
if (loggerTrace.isDebugEnabled())
|
||||||
|
{
|
||||||
|
loggerTrace.warn("Trace channel assignment logging is on and will affect performance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StackTraceElement[] traceLoggerChannelAssignTrace;
|
||||||
|
|
||||||
/** when set, ensures that listeners are executed within a transaction */
|
/** when set, ensures that listeners are executed within a transaction */
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
@@ -67,6 +78,37 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
encoding = "UTF-8";
|
encoding = "UTF-8";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable
|
||||||
|
{
|
||||||
|
if (loggerTrace.isDebugEnabled() && traceLoggerChannelAssignTrace != null)
|
||||||
|
{
|
||||||
|
// check that the channel is closed if it was used
|
||||||
|
if (isChannelOpen())
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(1024);
|
||||||
|
StackTraceUtil.buildStackTrace(
|
||||||
|
"UserTransaction being garbage collected without a commit() or rollback().",
|
||||||
|
traceLoggerChannelAssignTrace,
|
||||||
|
sb,
|
||||||
|
-1);
|
||||||
|
loggerTrace.error(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(100);
|
||||||
|
sb.append("ContentAccessor")
|
||||||
|
.append("[ contentUrl=").append(getContentUrl())
|
||||||
|
.append(", mimetype=").append(getMimetype())
|
||||||
|
.append(", size=").append(getSize())
|
||||||
|
.append(", encoding=").append(getEncoding())
|
||||||
|
.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public ContentData getContentData()
|
public ContentData getContentData()
|
||||||
{
|
{
|
||||||
ContentData property = new ContentData(contentUrl, mimetype, getSize(), encoding);
|
ContentData property = new ContentData(contentUrl, mimetype, getSize(), encoding);
|
||||||
@@ -93,18 +135,29 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
|||||||
this.transactionService = transactionService;
|
this.transactionService = transactionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
/**
|
||||||
|
* Derived classes can call this method to ensure that necessary trace logging is performed
|
||||||
|
* when the IO Channel is opened.
|
||||||
|
*/
|
||||||
|
protected final void channelOpened()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder(100);
|
// trace debug
|
||||||
sb.append("ContentAccessor")
|
if (loggerTrace.isDebugEnabled())
|
||||||
.append("[ contentUrl=").append(getContentUrl())
|
{
|
||||||
.append(", mimetype=").append(getMimetype())
|
Exception e = new Exception();
|
||||||
.append(", size=").append(getSize())
|
e.fillInStackTrace();
|
||||||
.append(", encoding=").append(getEncoding())
|
traceLoggerChannelAssignTrace = e.getStackTrace();
|
||||||
.append("]");
|
}
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived classes must implement this to help determine if the underlying
|
||||||
|
* IO Channel is still open.
|
||||||
|
*
|
||||||
|
* @return Returns true if the underlying IO Channel is open
|
||||||
|
*/
|
||||||
|
protected abstract boolean isChannelOpen();
|
||||||
|
|
||||||
public String getContentUrl()
|
public String getContentUrl()
|
||||||
{
|
{
|
||||||
return contentUrl;
|
return contentUrl;
|
||||||
|
@@ -69,7 +69,7 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl
|
|||||||
|
|
||||||
listeners = new ArrayList<ContentStreamListener>(2);
|
listeners = new ArrayList<ContentStreamListener>(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the listener after checking that the output stream isn't already in
|
* Adds the listener after checking that the output stream isn't already in
|
||||||
* use.
|
* use.
|
||||||
@@ -141,6 +141,19 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** helper implementation for base class */
|
||||||
|
protected boolean isChannelOpen()
|
||||||
|
{
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
return channel.isOpen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides low-level access to read content from the repository.
|
* Provides low-level access to read content from the repository.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -204,6 +217,8 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl
|
|||||||
ReadableByteChannel directChannel = getDirectReadableChannel();
|
ReadableByteChannel directChannel = getDirectReadableChannel();
|
||||||
channel = getCallbackReadableChannel(directChannel, listeners);
|
channel = getCallbackReadableChannel(directChannel, listeners);
|
||||||
|
|
||||||
|
// notify that the channel was opened
|
||||||
|
super.channelOpened();
|
||||||
// done
|
// done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
|
@@ -155,6 +155,19 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** helper implementation for base class */
|
||||||
|
protected boolean isChannelOpen()
|
||||||
|
{
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
return channel.isOpen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides low-level access to write content to the repository.
|
* Provides low-level access to write content to the repository.
|
||||||
@@ -218,6 +231,8 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
|
|||||||
WritableByteChannel directChannel = getDirectWritableChannel();
|
WritableByteChannel directChannel = getDirectWritableChannel();
|
||||||
channel = getCallbackWritableChannel(directChannel, listeners);
|
channel = getCallbackWritableChannel(directChannel, listeners);
|
||||||
|
|
||||||
|
// notify that the channel was opened
|
||||||
|
super.channelOpened();
|
||||||
// done
|
// done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user