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 020package org.apache.james.mime4j.dom; 021 022import java.io.IOException; 023import java.io.InputStream; 024import 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 */ 031public 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}