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.util.List;
|
||||
|
||||
import org.alfresco.error.StackTraceUtil;
|
||||
import org.alfresco.repo.transaction.TransactionUtil;
|
||||
import org.alfresco.service.cmr.repository.ContentAccessor;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
@@ -44,6 +45,16 @@ import org.springframework.aop.AfterReturningAdvice;
|
||||
public abstract class AbstractContentAccessor implements ContentAccessor
|
||||
{
|
||||
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 */
|
||||
private TransactionService transactionService;
|
||||
@@ -67,6 +78,37 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
||||
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()
|
||||
{
|
||||
ContentData property = new ContentData(contentUrl, mimetype, getSize(), encoding);
|
||||
@@ -93,18 +135,29 @@ public abstract class AbstractContentAccessor implements ContentAccessor
|
||||
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);
|
||||
sb.append("ContentAccessor")
|
||||
.append("[ contentUrl=").append(getContentUrl())
|
||||
.append(", mimetype=").append(getMimetype())
|
||||
.append(", size=").append(getSize())
|
||||
.append(", encoding=").append(getEncoding())
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
// trace debug
|
||||
if (loggerTrace.isDebugEnabled())
|
||||
{
|
||||
Exception e = new Exception();
|
||||
e.fillInStackTrace();
|
||||
traceLoggerChannelAssignTrace = e.getStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
return contentUrl;
|
||||
|
@@ -69,7 +69,7 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl
|
||||
|
||||
listeners = new ArrayList<ContentStreamListener>(2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the listener after checking that the output stream isn't already in
|
||||
* 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.
|
||||
* <p>
|
||||
@@ -204,6 +217,8 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl
|
||||
ReadableByteChannel directChannel = getDirectReadableChannel();
|
||||
channel = getCallbackReadableChannel(directChannel, listeners);
|
||||
|
||||
// notify that the channel was opened
|
||||
super.channelOpened();
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
|
@@ -155,6 +155,19 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
|
||||
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.
|
||||
@@ -218,6 +231,8 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
|
||||
WritableByteChannel directChannel = getDirectWritableChannel();
|
||||
channel = getCallbackWritableChannel(directChannel, listeners);
|
||||
|
||||
// notify that the channel was opened
|
||||
super.channelOpened();
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
|
Reference in New Issue
Block a user