001/* 002 * #%L 003 * Netarchivesuite - common 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023 024package dk.netarkivet.common.utils; 025 026import java.io.FileInputStream; 027import java.io.FileOutputStream; 028import java.io.IOException; 029import java.io.InputStream; 030import java.io.OutputStream; 031import java.nio.channels.FileChannel; 032 033import javax.servlet.jsp.JspWriter; 034 035import org.dom4j.Document; 036import org.dom4j.io.OutputFormat; 037import org.dom4j.io.XMLWriter; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import dk.netarkivet.common.Constants; 042import dk.netarkivet.common.exceptions.ArgumentNotValid; 043import dk.netarkivet.common.exceptions.IOFailure; 044 045/** 046 * Utilities for handling streams. 047 */ 048public class StreamUtils { 049 050 /** logger for this class. */ 051 private static final Logger log = LoggerFactory.getLogger(StreamUtils.class); 052 053 /** Constant for UTF-8. */ 054 private static final String UTF8_CHARSET = "UTF-8"; 055 056 /** 057 * Will copy everything from input stream to jsp writer, closing input stream afterwards. Charset UTF-8 is assumed. 058 * 059 * @param in Inputstream to copy from 060 * @param out JspWriter to copy to 061 * @throws ArgumentNotValid if either parameter is null 062 * @throws IOFailure if a read or write error happens during copy 063 */ 064 public static void copyInputStreamToJspWriter(InputStream in, JspWriter out) { 065 ArgumentNotValid.checkNotNull(in, "InputStream in"); 066 ArgumentNotValid.checkNotNull(out, "JspWriter out"); 067 068 byte[] buf = new byte[Constants.IO_BUFFER_SIZE]; 069 int read = 0; 070 try { 071 try { 072 while ((read = in.read(buf)) != -1) { 073 out.write(new String(buf, UTF8_CHARSET), 0, read); 074 } 075 } finally { 076 in.close(); 077 } 078 } catch (IOException e) { 079 String errMsg = "Trouble copying inputstream " + in + " to JspWriter " + out; 080 log.warn(errMsg, e); 081 throw new IOFailure(errMsg, e); 082 } 083 } 084 085 /** 086 * Will copy everything from input stream to output stream, closing input stream afterwards. 087 * 088 * @param in Inputstream to copy from 089 * @param out Outputstream to copy to 090 * @throws ArgumentNotValid if either parameter is null 091 * @throws IOFailure if a read or write error happens during copy 092 */ 093 public static void copyInputStreamToOutputStream(InputStream in, OutputStream out) { 094 ArgumentNotValid.checkNotNull(in, "InputStream in"); 095 ArgumentNotValid.checkNotNull(out, "OutputStream out"); 096 097 try { 098 try { 099 if (in instanceof FileInputStream && out instanceof FileOutputStream) { 100 FileChannel inChannel = ((FileInputStream) in).getChannel(); 101 FileChannel outChannel = ((FileOutputStream) out).getChannel(); 102 long transferred = 0; 103 final long fileLength = inChannel.size(); 104 do { 105 transferred += inChannel.transferTo(transferred, 106 Math.min(Constants.IO_CHUNK_SIZE, fileLength - transferred), outChannel); 107 } while (transferred < fileLength); 108 } else { 109 byte[] buf = new byte[Constants.IO_BUFFER_SIZE]; 110 int bytesRead; 111 while ((bytesRead = in.read(buf)) != -1) { 112 out.write(buf, 0, bytesRead); 113 } 114 } 115 out.flush(); 116 } finally { 117 in.close(); 118 } 119 } catch (IOException e) { 120 String errMsg = "Trouble copying inputstream " + in + " to outputstream " + out; 121 log.warn(errMsg, e); 122 throw new IOFailure(errMsg, e); 123 } 124 } 125 126 /** 127 * Write document tree to stream. Note, the stream is flushed, but not closed. 128 * 129 * @param doc the document tree to save. 130 * @param os the stream to write xml to 131 * @throws IOFailure On trouble writing XML to stream. 132 */ 133 public static void writeXmlToStream(Document doc, OutputStream os) { 134 ArgumentNotValid.checkNotNull(doc, "Document doc"); 135 ArgumentNotValid.checkNotNull(doc, "OutputStream os"); 136 XMLWriter xwriter = null; 137 try { 138 try { 139 OutputFormat format = OutputFormat.createPrettyPrint(); 140 format.setEncoding(UTF8_CHARSET); 141 xwriter = new XMLWriter(os, format); 142 xwriter.write(doc); 143 } finally { 144 if (xwriter != null) { 145 xwriter.close(); 146 } 147 os.flush(); 148 } 149 } catch (IOException e) { 150 String errMsg = "Unable to write XML to stream"; 151 log.warn(errMsg, e); 152 throw new IOFailure(errMsg, e); 153 } 154 } 155 156 /** 157 * Reads an input stream and returns it as a string. 158 * 159 * @param in The input stream. 160 * @return The string content of the input stream in the UTF8-charset. 161 * @throws ArgumentNotValid If the input stream is null. 162 * @throws IOFailure If an IOException is caught while reading the inputstream. 163 */ 164 public static String getInputStreamAsString(InputStream in) throws ArgumentNotValid, IOFailure { 165 ArgumentNotValid.checkNotNull(in, "InputStream in"); 166 167 StringBuilder res = new StringBuilder(); 168 byte[] buf = new byte[Constants.IO_BUFFER_SIZE]; 169 int read = 0; 170 try { 171 try { 172 while ((read = in.read(buf)) != -1) { 173 res.append(new String(buf, UTF8_CHARSET), 0, read); 174 } 175 } finally { 176 in.close(); 177 } 178 } catch (IOException e) { 179 String errMsg = "Trouble reading inputstream '" + in + "'"; 180 log.warn(errMsg, e); 181 throw new IOFailure(errMsg, e); 182 } 183 184 return res.toString(); 185 } 186 187 /** 188 * Convert inputStream to byte array. 189 * 190 * @param data inputstream 191 * @param dataLength length of inputstream (must be larger than 0) 192 * @return byte[] containing data in inputstream 193 */ 194 public static byte[] inputStreamToBytes(InputStream data, int dataLength) { 195 ArgumentNotValid.checkNotNull(data, "data"); 196 ArgumentNotValid.checkNotNegative(dataLength, "dataLength"); 197 byte[] contents = new byte[dataLength]; 198 try { 199 int read = data.read(contents, 0, dataLength); 200 if (dataLength != read) { 201 log.debug("Only read {} bytes out of the {} bytes requested", read, dataLength); 202 } 203 } catch (IOException e) { 204 throw new IOFailure("Unable to convert inputstream to byte array", e); 205 } 206 return contents; 207 } 208 209}