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:
Derek Hulley
2006-02-15 13:05:25 +00:00
parent 80f8117602
commit 2f5a87fa9e
3 changed files with 93 additions and 10 deletions

View File

@@ -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;

View File

@@ -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())
{

View File

@@ -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())
{