001    /*
002     * Copyright 2004 Stephen J. McConnell.
003     * Copyright 2004 Niclas Hedhman
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.util;
020    
021    import java.io.BufferedInputStream;
022    import java.io.BufferedOutputStream;
023    import java.io.InputStream;
024    import java.io.IOException;
025    import java.io.OutputStream;
026    
027    import java.net.URL;
028    
029    import net.dpml.transit.NullArgumentException;
030    
031    import net.dpml.transit.monitor.NetworkMonitor;
032    
033    /**
034     * Utility class that provides support for stream copy operations.
035     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
036     * @version 1.1.0
037     */
038    public final class StreamUtils
039    {
040       /**
041        * Disabled constructor.
042        */
043        private StreamUtils()
044        {
045            // utility class
046        }
047    
048       /**
049        * Buffer size.
050        */
051        private static final int BUFFER_SIZE = 102400;
052    
053       /** 
054        * Copy a stream.
055        * @param src the source input stream
056        * @param dest the destination output stream
057        * @param closeStreams TRUE if the streams should be closed on completion
058        * @exception IOException if an IO error occurs
059        * @exception NullArgumentException if src or destination are null
060        */
061        public static void copyStream( InputStream src, OutputStream dest, boolean closeStreams )
062            throws IOException, NullArgumentException
063        {
064            copyStream( null, null, 0, src, dest, closeStreams );
065        }
066    
067       /** 
068        * Copy a stream.
069        * @param monitor optional network monitor to log updates
070        * @param source the source url
071        * @param expected the expected size in bytes
072        * @param src the source input stream
073        * @param dest the destination output stream
074        * @param closeStreams TRUE if the streams should be closed on completion
075        * @exception IOException if an IO error occurs
076        * @exception NullArgumentException if src or destination are null
077        */
078        public static void copyStream( NetworkMonitor monitor, URL source, int expected,
079                                InputStream src, OutputStream dest, boolean closeStreams )
080            throws IOException, NullArgumentException
081        {
082            if( src == null )
083            {
084                throw new NullArgumentException( "src" );
085            }
086    
087            if( dest == null )
088            {
089                throw new NullArgumentException( "dest" );
090            }
091    
092            int length;
093            int count = 0; // cumulative total read
094            byte[] buffer = new byte[BUFFER_SIZE];
095            if( !( dest instanceof BufferedOutputStream ) )
096            {
097                dest = new BufferedOutputStream( dest );
098            }
099            if( !( src instanceof BufferedInputStream ) )
100            {
101                src = new BufferedInputStream( src );
102            }
103    
104            try
105            {
106                if( null != monitor )
107                {
108                    monitor.notifyUpdate( source, expected, 0 );
109                }
110                while( ( length = src.read( buffer ) ) >= 0 )
111                {
112                    count = count + length;
113                    dest.write( buffer, 0, length );
114                    if( null != monitor )
115                    {
116                        monitor.notifyUpdate( source, expected, count );
117                    }
118                }
119            }
120            finally
121            {
122                if( closeStreams )
123                {
124                    try
125                    {
126                        src.close();
127                    }
128                    catch( Throwable e )
129                    {
130                        e.printStackTrace();
131                    }
132    
133                    try
134                    {
135                        dest.close();
136                    }
137                    catch( Throwable e )
138                    {
139                        e.printStackTrace();
140                    }
141                }
142                if( null != monitor )
143                {
144                    monitor.notifyCompletion( source );
145                }
146            }
147        }
148    
149       /**
150        * Compare two streams.
151        * @param in1 the first input stream
152        * @param in2 the second input stream
153        * @return the equality status
154        * @exception IOException if an IO error occurs
155        */
156        public static boolean compareStreams( InputStream in1, InputStream in2 )
157            throws IOException
158        {
159            boolean result = true;
160            do
161            {
162                int v1 = in1.read();
163                int v2 = in2.read();
164                if( v1 != v2 )
165                {
166                    return false;
167                }
168                if( v1 == -1 )
169                {
170                    break;
171                }
172            } while( true );
173            return result;
174        }
175    }