001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019
020 package org.apache.james.mime4j.dom;
021
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.io.OutputStream;
025
026 /**
027 * Abstract implementation of a single message body; that is, a body that does
028 * not contain (directly or indirectly) any other child bodies. It also provides
029 * the parent functionality required by bodies.
030 */
031 public abstract class SingleBody implements Body {
032
033 private Entity parent = null;
034
035 /**
036 * Sole constructor.
037 */
038 protected SingleBody() {
039 }
040
041 /**
042 * @see org.apache.james.mime4j.dom.Body#getParent()
043 */
044 public Entity getParent() {
045 return parent;
046 }
047
048 /**
049 * @see org.apache.james.mime4j.dom.Body#setParent(org.apache.james.mime4j.dom.Entity)
050 */
051 public void setParent(Entity parent) {
052 this.parent = parent;
053 }
054
055 /**
056 * Gets a <code>InputStream</code> which reads the bytes of the body.
057 *
058 * @return the stream, transfer decoded
059 * @throws IOException
060 * on I/O errors.
061 */
062 public abstract InputStream getInputStream() throws IOException;
063
064 /**
065 * Writes this single body to the given stream. The default implementation copies
066 * the input stream obtained by {@link #getInputStream()} to the specified output
067 * stream. May be overwritten by a subclass to improve performance.
068 *
069 * @param out
070 * the stream to write to.
071 * @throws IOException
072 * in case of an I/O error
073 */
074 public void writeTo(OutputStream out) throws IOException {
075 if (out == null)
076 throw new IllegalArgumentException();
077
078 InputStream in = getInputStream();
079 SingleBody.copy(in, out);
080 in.close();
081 }
082
083 /**
084 * Returns a copy of this <code>SingleBody</code> (optional operation).
085 * <p>
086 * The general contract of this method is as follows:
087 * <ul>
088 * <li>Invoking {@link #getParent()} on the copy returns <code>null</code>.
089 * That means that the copy is detached from the parent entity of this
090 * <code>SingleBody</code>. The copy may get attached to a different
091 * entity later on.</li>
092 * <li>The underlying content does not have to be copied. Instead it may be
093 * shared between multiple copies of a <code>SingleBody</code>.</li>
094 * <li>If the underlying content is shared by multiple copies the
095 * implementation has to make sure that the content gets deleted when the
096 * last copy gets disposed of (and not before that).</li>
097 * </ul>
098 * <p>
099 * This implementation always throws an
100 * <code>UnsupportedOperationException</code>.
101 *
102 * @return a copy of this <code>SingleBody</code>.
103 * @throws UnsupportedOperationException
104 * if the <code>copy</code> operation is not supported by this
105 * single body.
106 */
107 public SingleBody copy() {
108 throw new UnsupportedOperationException();
109 }
110
111 /**
112 * Subclasses should override this method if they have allocated resources
113 * that need to be freed explicitly (e.g. cannot be simply reclaimed by the
114 * garbage collector).
115 *
116 * The default implementation of this method does nothing.
117 *
118 * @see org.apache.james.mime4j.dom.Disposable#dispose()
119 */
120 public void dispose() {
121 }
122
123 static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;
124
125 /**
126 * Copies the contents of one stream to the other.
127 * @param in not null
128 * @param out not null
129 * @throws IOException
130 */
131 private static void copy(final InputStream in, final OutputStream out) throws IOException {
132 final byte[] buffer = new byte[DEFAULT_ENCODING_BUFFER_SIZE];
133 int inputLength;
134 while (-1 != (inputLength = in.read(buffer))) {
135 out.write(buffer, 0, inputLength);
136 }
137 }
138
139 }