You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2008/10/04 17:49:33 UTC
svn commit: r701657 - in /james/mime4j/trunk/src:
main/java/org/apache/james/mime4j/message/
main/java/org/apache/james/mime4j/message/storage/
test/java/org/apache/james/mime4j/message/
test/java/org/apache/james/mime4j/message/storage/
Author: bago
Date: Sat Oct 4 08:49:32 2008
New Revision: 701657
URL: http://svn.apache.org/viewvc?rev=701657&view=rev
Log:
Provide a means to dispose a Message (MIME4J-72)
Patch kindly provided by Markus Wiederkehr.
Temporary commented out finalizers until more people will comment on the subject.
Modified:
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileBinaryBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileTextBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/SimpleTempStorage.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/SimpleTempStorageTest.java
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java Sat Oct 4 08:49:32 2008
@@ -29,6 +29,7 @@
*/
public abstract class AbstractBody implements Body {
private Entity parent = null;
+ protected boolean disposed = false;
/**
* @see org.apache.james.mime4j.message.Body#getParent()
@@ -41,17 +42,39 @@
* @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
*/
public void setParent(Entity parent) {
+ if (disposed)
+ throw new IllegalStateException("AbstractBody has been disposed");
+
this.parent = parent;
}
/**
- * Subclasses should override this method if they have allocated resources that need to be
- * freed explicitly (e.g. cannot be simply reclaimed by the garbage collector). The default
- * implementation of this method does nothing.
+ * Subclasses should override this method if they have allocated resources
+ * that need to be freed explicitly (e.g. cannot be simply reclaimed by the
+ * garbage collector). Subclasses that override this method should invoke
+ * super.dispose().
+ *
+ * The default implementation marks this AbstractBody as disposed.
*
* @see org.apache.james.mime4j.message.Disposable#dispose()
*/
public void dispose() {
+ if (disposed)
+ return;
+
+ disposed = true;
+
+ parent = null;
}
+ /**
+ * Ensures that the <code>dispose</code> method of this abstract body is
+ * called when there are no more references to it.
+ *
+ * Leave them out ATM (https://issues.apache.org/jira/browse/MIME4J-72?focusedCommentId=12636007#action_12636007)
+ protected void finalize() throws Throwable {
+ dispose();
+ }
+ */
+
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java Sat Oct 4 08:49:32 2008
@@ -40,6 +40,7 @@
private Header header = null;
private Body body = null;
private Entity parent = null;
+ private boolean disposed = false;
/**
* Gets the parent entity of this entity.
@@ -58,6 +59,9 @@
* this will be the root entity.
*/
public void setParent(Entity parent) {
+ if (disposed)
+ throw new IllegalStateException("Entity has been disposed");
+
this.parent = parent;
}
@@ -76,6 +80,9 @@
* @param header the header.
*/
public void setHeader(Header header) {
+ if (disposed)
+ throw new IllegalStateException("Entity has been disposed");
+
this.header = header;
}
@@ -94,6 +101,9 @@
* @param body the body.
*/
public void setBody(Body body) {
+ if (disposed)
+ throw new IllegalStateException("Entity has been disposed");
+
this.body = body;
body.setParent(this);
}
@@ -173,6 +183,9 @@
* @throws IOException
*/
public void writeTo(OutputStream out, int mode) throws IOException, MimeException {
+ if (disposed)
+ throw new IllegalStateException("Entity has been disposed");
+
getHeader().writeTo(out, mode);
out.flush();
@@ -199,10 +212,35 @@
* Disposes the body of this entity. Note that the dispose call does not get
* forwarded to the parent entity of this Entity.
*
+ * Subclasses that need to free resources should override this method and
+ * invoke super.dispose().
+ *
* @see org.apache.james.mime4j.message.Disposable#dispose()
*/
public void dispose() {
- if (body != null)
- body.dispose();
+ if (disposed)
+ return;
+
+ try {
+ if (body != null)
+ body.dispose();
+ } finally {
+ disposed = true;
+
+ header = null;
+ body = null;
+ parent = null;
+ }
+ }
+
+ /**
+ * Ensures that the <code>dispose</code> method of this entity is called
+ * when there are no more references to it.
+ *
+ * Leave them out ATM (https://issues.apache.org/jira/browse/MIME4J-72?focusedCommentId=12636007#action_12636007)
+ protected void finalize() throws Throwable {
+ dispose();
}
+ */
+
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java Sat Oct 4 08:49:32 2008
@@ -51,6 +51,7 @@
private List bodyParts = new LinkedList();
private Entity parent = null;
private String subType;
+ private boolean disposed = false;
/**
* Creates a new empty <code>Multipart</code> instance.
@@ -78,6 +79,9 @@
* @param subType the sub-type.
*/
public void setSubType(String subType) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
this.subType = subType;
}
@@ -92,6 +96,9 @@
* @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
*/
public void setParent(Entity parent) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
this.parent = parent;
for (Iterator it = bodyParts.iterator(); it.hasNext();) {
((BodyPart) it.next()).setParent(parent);
@@ -113,6 +120,9 @@
* @param epilogue the epilogue.
*/
public void setEpilogue(String epilogue) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
this.epilogue = epilogue;
}
@@ -131,6 +141,9 @@
* @param bodyParts the new list of <code>BodyPart</code> objects.
*/
public void setBodyParts(List bodyParts) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
this.bodyParts = bodyParts;
for (Iterator it = bodyParts.iterator(); it.hasNext();) {
((BodyPart) it.next()).setParent(parent);
@@ -143,6 +156,9 @@
* @param bodyPart the body part.
*/
public void addBodyPart(BodyPart bodyPart) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
bodyParts.add(bodyPart);
bodyPart.setParent(parent);
}
@@ -162,6 +178,9 @@
* @param preamble the preamble.
*/
public void setPreamble(String preamble) {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
this.preamble = preamble;
}
@@ -175,6 +194,9 @@
* @throws MimeException if case of a MIME protocol violation
*/
public void writeTo(final OutputStream out, int mode) throws IOException, MimeException {
+ if (disposed)
+ throw new IllegalStateException("Multipart has been disposed");
+
Entity e = getParent();
ContentTypeField cField = (ContentTypeField) e.getHeader().getField(
@@ -229,8 +251,31 @@
* @see org.apache.james.mime4j.message.Disposable#dispose()
*/
public void dispose() {
- for (Iterator it = bodyParts.iterator(); it.hasNext();) {
- ((BodyPart) it.next()).dispose();
+ if (disposed)
+ return;
+
+ try {
+ for (Iterator it = bodyParts.iterator(); it.hasNext();) {
+ ((BodyPart) it.next()).dispose();
+ }
+ } finally {
+ disposed = true;
+
+ preamble = null;
+ epilogue = null;
+ bodyParts = null;
+ parent = null;
+ subType = null;
}
}
+
+ /**
+ * Ensures that the <code>dispose</code> method of this multipart is
+ * called when there are no more references to it.
+ *
+ * Leave them out ATM (https://issues.apache.org/jira/browse/MIME4J-72?focusedCommentId=12636007#action_12636007)
+ protected void finalize() throws Throwable {
+ dispose();
+ }
+ */
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileBinaryBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileBinaryBody.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileBinaryBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileBinaryBody.java Sat Oct 4 08:49:32 2008
@@ -37,7 +37,6 @@
*/
class TempFileBinaryBody extends AbstractBody implements BinaryBody {
- private Entity parent = null;
private TempFile tempFile = null;
/**
@@ -57,20 +56,6 @@
}
/**
- * @see org.apache.james.mime4j.message.AbstractBody#getParent()
- */
- public Entity getParent() {
- return parent;
- }
-
- /**
- * @see org.apache.james.mime4j.message.AbstractBody#setParent(org.apache.james.mime4j.message.Entity)
- */
- public void setParent(Entity parent) {
- this.parent = parent;
- }
-
- /**
* @see org.apache.james.mime4j.message.BinaryBody#getInputStream()
*/
public InputStream getInputStream() throws IOException {
@@ -81,6 +66,9 @@
* @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream, int)
*/
public void writeTo(OutputStream out, int mode) throws IOException {
+ if (disposed)
+ throw new IllegalStateException("TempFileBinaryBody has been disposed");
+
final InputStream inputStream = getInputStream();
CodecUtil.copy(inputStream,out);
}
@@ -91,6 +79,12 @@
* @see org.apache.james.mime4j.message.Disposable#dispose()
*/
public void dispose() {
- tempFile.delete();
+ try {
+ tempFile.delete();
+ } finally {
+ tempFile = null;
+
+ super.dispose();
+ }
}
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileTextBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileTextBody.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileTextBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/TempFileTextBody.java Sat Oct 4 08:49:32 2008
@@ -104,8 +104,11 @@
* @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream, int)
*/
public void writeTo(OutputStream out, int mode) throws IOException {
+ if (disposed)
+ throw new IllegalStateException("TempFileTextBody has been disposed");
+
final InputStream inputStream = tempFile.getInputStream();
- CodecUtil.copy(inputStream,out);
+ CodecUtil.copy(inputStream, out);
}
/**
@@ -114,6 +117,13 @@
* @see org.apache.james.mime4j.message.Disposable#dispose()
*/
public void dispose() {
- tempFile.delete();
+ try {
+ tempFile.delete();
+ } finally {
+ mimeCharset = null;
+ tempFile = null;
+
+ super.dispose();
+ }
}
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/SimpleTempStorage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/SimpleTempStorage.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/SimpleTempStorage.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/SimpleTempStorage.java Sat Oct 4 08:49:32 2008
@@ -27,7 +27,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Random;
+import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -182,9 +185,11 @@
}
- private class SimpleTempFile implements TempFile {
+ private static class SimpleTempFile implements TempFile {
private File file = null;
+ private static final Set filesToDelete = new HashSet();
+
private SimpleTempFile(File file) {
this.file = file;
this.file.deleteOnExit();
@@ -212,10 +217,30 @@
}
/**
- * Do nothing
+ * @see org.apache.james.mime4j.message.storage.TempFile#delete()
*/
public void delete() {
- // Not implementated
+ // deleting a file might not immediately succeed if there are still
+ // streams left open (especially under Windows). so we keep track of
+ // the files that have to be deleted and try to delete all these
+ // files each time this method gets invoked.
+
+ // a better but more complicated solution would be to start a
+ // separate thread that tries to delete the files periodically.
+
+ synchronized (filesToDelete) {
+ if (file != null) {
+ filesToDelete.add(file);
+ file = null;
+ }
+
+ for (Iterator iterator = filesToDelete.iterator(); iterator
+ .hasNext();) {
+ File file = (File) iterator.next();
+ if (file.delete())
+ iterator.remove();
+ }
+ }
}
/**
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java Sat Oct 4 08:49:32 2008
@@ -22,13 +22,16 @@
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.util.List;
import junit.framework.TestCase;
import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.field.Field;
import org.apache.james.mime4j.util.MessageUtils;
@@ -163,6 +166,47 @@
assertTrue("header added", lines.contains(testheader));
}
+ public void testDisposeGetsPropagatedToBody() throws Exception {
+ DummyBody body1 = new DummyBody();
+ BodyPart part1 = new BodyPart();
+ part1.setHeader(headerEmpty);
+ part1.setBody(body1);
+
+ DummyBody body2 = new DummyBody();
+ BodyPart part2 = new BodyPart();
+ part2.setHeader(headerEmpty);
+ part2.setBody(body2);
+
+ Multipart mp = new Multipart("mixed");
+ mp.addBodyPart(part1);
+ mp.addBodyPart(part2);
+
+ Message m = new Message();
+ m.setHeader(headerMultipartMixed);
+ m.setBody(mp);
+
+ assertFalse(body1.disposed);
+ assertFalse(body2.disposed);
+
+ m.dispose();
+
+ assertTrue(body1.disposed);
+ assertTrue(body2.disposed);
+ }
+
+ public void testDisposedMessageThrowsException()
+ throws Exception {
+ byte[] inputByte = getRawMessageAsByteArray();
+ Message m = new Message(new ByteArrayInputStream(inputByte));
+ m.dispose();
+
+ try {
+ m.writeTo(new ByteArrayOutputStream(), MessageUtils.LENIENT);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ }
+
private byte[] getRawMessageAsByteArray() {
StringBuffer header = new StringBuffer();
StringBuffer body = new StringBuffer();
@@ -182,4 +226,19 @@
return complete.toString().getBytes();
}
+ private static final class DummyBody extends AbstractBody {
+
+ public boolean disposed = false;
+
+ public void writeTo(OutputStream out, int mode) throws IOException,
+ MimeException {
+ out.write("dummy".getBytes("US-ASCII"));
+ }
+
+ public void dispose() {
+ disposed = true;
+ }
+
+ }
+
}
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/SimpleTempStorageTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/SimpleTempStorageTest.java?rev=701657&r1=701656&r2=701657&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/SimpleTempStorageTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/SimpleTempStorageTest.java Sat Oct 4 08:49:32 2008
@@ -115,5 +115,18 @@
fileName.matches("^test_prefix[0-9]+\\.suffix$"));
assertTrue("Temp file doesn't exist",
new File(file.getAbsolutePath()).exists());
- }
+ }
+
+ public void testDeleteTempFile() throws IOException {
+ SimpleTempStorage man = new SimpleTempStorage();
+ TempPath path = man.getRootTempPath().createTempPath();
+ TempFile tempFile = path.createTempFile("test_prefix", ".suffix");
+
+ File backingFile = new File(tempFile.getAbsolutePath());
+ assertTrue(backingFile.exists());
+
+ tempFile.delete();
+ assertFalse(backingFile.exists());
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org