001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.commons.io; 020 021import java.io.ByteArrayInputStream; 022import java.io.File; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026 027import lucee.commons.io.res.Resource; 028import lucee.commons.io.res.util.ResourceUtil; 029import lucee.runtime.engine.ThreadLocalPageContext; 030 031public final class TemporaryStream extends OutputStream { 032 033 private static final int MAX_MEMORY = 1024*1024; 034 private static int index=1; 035 private static Resource tempFile; 036 037 private Resource persis; 038 private long count=0; 039 private OutputStream os; 040 public boolean memoryMode=true; 041 public boolean available=false; 042 043 /** 044 * Constructor of the class 045 */ 046 public TemporaryStream() { 047 do { 048 this.persis=getTempDirectory().getRealResource("temporary-stream-"+(index++)); 049 } 050 while(persis.exists()); 051 os=new java.io.ByteArrayOutputStream(); 052 } 053 054 @Override 055 public void write(int b) throws IOException { 056 count++; 057 check(); 058 os.write(b); 059 } 060 061 @Override 062 public void write(byte[] b, int off, int len) throws IOException { 063 count+=len; 064 check(); 065 os.write(b, off, len); 066 } 067 068 @Override 069 public void write(byte[] b) throws IOException { 070 count+=b.length; 071 check(); 072 os.write(b); 073 } 074 075 private void check() throws IOException { 076 if(memoryMode && count>=MAX_MEMORY && os instanceof java.io.ByteArrayOutputStream) { 077 memoryMode=false; 078 OutputStream nos = persis.getOutputStream(); 079 nos.write(((java.io.ByteArrayOutputStream)os).toByteArray()); 080 os=nos; 081 } 082 } 083 084 085 @Override 086 public void close() throws IOException { 087 os.close(); 088 available=true; 089 } 090 091 @Override 092 public void flush() throws IOException { 093 os.flush(); 094 } 095 096 public InputStream getInputStream() throws IOException { 097 return new InpuStreamWrap(this); 098 } 099 100 class InpuStreamWrap extends InputStream { 101 102 private TemporaryStream ts; 103 private InputStream is; 104 105 public InpuStreamWrap(TemporaryStream ts) throws IOException { 106 this.ts=ts; 107 if(ts.os instanceof java.io.ByteArrayOutputStream) { 108 is=new ByteArrayInputStream(((java.io.ByteArrayOutputStream)ts.os).toByteArray()); 109 } 110 else if(ts.available) { 111 ts.available=false; 112 try { 113 is=ts.persis.getInputStream(); 114 } catch (IOException e) { 115 ts.persis.delete(); 116 throw e; 117 } 118 } 119 else 120 throw new IOException("InputStream no longer available"); 121 } 122 123 @Override 124 public int read() throws IOException { 125 return is.read(); 126 } 127 128 @Override 129 public int available() throws IOException { 130 return is.available(); 131 } 132 133 @Override 134 public void close() throws IOException { 135 ts.persis.delete(); 136 is.close(); 137 } 138 139 @Override 140 public synchronized void mark(int readlimit) { 141 is.mark(readlimit); 142 } 143 144 @Override 145 public boolean markSupported() { 146 return is.markSupported(); 147 } 148 149 @Override 150 public int read(byte[] b, int off, int len) throws IOException { 151 return is.read(b, off, len); 152 } 153 154 @Override 155 public int read(byte[] b) throws IOException { 156 return is.read(b); 157 } 158 159 @Override 160 public synchronized void reset() throws IOException { 161 is.reset(); 162 } 163 164 @Override 165 public long skip(long n) throws IOException { 166 return is.skip(n); 167 } 168 } 169 170 public long length() { 171 return count; 172 } 173 174 public static Resource getTempDirectory() { 175 if(tempFile!=null) return tempFile; 176 String tmpStr = System.getProperty("java.io.tmpdir"); 177 if(tmpStr!=null) { 178 179 tempFile=ResourceUtil.toResourceNotExisting(ThreadLocalPageContext.get(), tmpStr); 180 //tempFile=CFMLEngineFactory.getInstance().getCastUtil().toResource(tmpStr,null); 181 182 if(tempFile!=null && tempFile.exists()) { 183 tempFile=getCanonicalResourceEL(tempFile); 184 return tempFile; 185 } 186 } 187 File tmp =null; 188 try { 189 tmp = File.createTempFile("a","a"); 190 tempFile=ResourceUtil.toResourceNotExisting(ThreadLocalPageContext.get(), tmp.getParent()); 191 //tempFile=CFMLEngineFactory.getInstance().getCastUtil().toResource(tmp.getParent(),null); 192 tempFile=getCanonicalResourceEL(tempFile); 193 } 194 catch(IOException ioe) {} 195 finally { 196 if(tmp!=null)tmp.delete(); 197 } 198 return tempFile; 199 } 200 201 private static Resource getCanonicalResourceEL(Resource res) { 202 try { 203 return res.getCanonicalResource(); 204 } catch (IOException e) { 205 return res.getAbsoluteResource(); 206 } 207 } 208}