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    }