001 package railo.commons.io.res.type.compress; 002 003 import java.io.IOException; 004 import java.io.InputStream; 005 import java.util.HashMap; 006 import java.util.Map; 007 import java.util.zip.GZIPOutputStream; 008 import java.util.zip.ZipOutputStream; 009 010 import org.apache.commons.compress.archivers.tar.TarOutputStream; 011 012 import railo.commons.digest.MD5; 013 import railo.commons.io.CompressUtil; 014 import railo.commons.io.IOUtil; 015 import railo.commons.io.SystemUtil; 016 import railo.commons.io.res.Resource; 017 import railo.commons.io.res.ResourceProvider; 018 import railo.commons.io.res.type.ram.RamResourceProviderOld; 019 import railo.commons.io.res.util.ResourceUtil; 020 import railo.runtime.config.Config; 021 import railo.runtime.config.ConfigImpl; 022 import railo.runtime.engine.ThreadLocalPageContext; 023 import railo.runtime.op.Caster; 024 025 public final class Compress { 026 027 public static final int FORMAT_ZIP = CompressUtil.FORMAT_ZIP; 028 public static final int FORMAT_TAR = CompressUtil.FORMAT_TAR; 029 public static final int FORMAT_TGZ = CompressUtil.FORMAT_TGZ; 030 public static final int FORMAT_TBZ2 = CompressUtil.FORMAT_TBZ2; 031 032 033 //private final static Map files=new WeakHashMap(); 034 035 private final Resource ffile; 036 //private ResourceProvider ramProvider; 037 private long syn=-1; 038 private Resource root; 039 private Synchronizer synchronizer; 040 private long lastMod=-1; 041 private long lastCheck=-1; 042 043 private int format; 044 private int mode; 045 private boolean caseSensitive; 046 private Resource temp; 047 048 /** 049 * private Constructor of the class, will be invoked be getInstance 050 * @param file 051 * @param format 052 * @param caseSensitive 053 */ 054 public Compress(Resource file, int format, boolean caseSensitive) { 055 this.ffile=file; 056 this.format=format; 057 this.mode=ffile.getMode(); 058 if(mode==0) mode=0777; 059 load(this.caseSensitive=caseSensitive); 060 } 061 062 /** 063 * return zip instance matching the zipfile, singelton isnatce only 1 zip for one file 064 * @param zipFile 065 * @param format 066 * @param caseSensitive 067 * @return 068 */ 069 /*public static Compress getInstance(Resource zipFile, int format, boolean caseSensitive) { 070 Compress compress=(Compress) files.get(zipFile.getPath()); 071 if(compress==null) { 072 compress=new Compress(zipFile,format,caseSensitive); 073 files.put(zipFile.getPath(), compress); 074 } 075 return compress;ConfigImpl 076 }*/ 077 public static Compress getInstance(Resource zipFile, int format, boolean caseSensitive) { 078 ConfigImpl config=(ConfigImpl) ThreadLocalPageContext.getConfig(); 079 return config.getCompressInstance(zipFile, format, caseSensitive); 080 } 081 082 083 private synchronized void load(boolean caseSensitive) { 084 long actLastMod = ffile.lastModified(); 085 lastMod=actLastMod; 086 lastCheck=System.currentTimeMillis(); 087 Map args = new HashMap(); 088 args.put("case-sensitive", Caster.toBoolean(caseSensitive)); 089 //ramProvider = new RamResourceProviderOld().init("ram",args); 090 //root=ramProvider.getResource("/"); 091 092 if(temp==null){ 093 String cid=""; 094 try { 095 Config config = ThreadLocalPageContext.getConfig(); 096 if(config!=null){ 097 cid=config.getId(); 098 temp = config.getTempDirectory(); 099 } 100 if(temp==null)temp=SystemUtil.getTempDirectory(); 101 102 temp=temp.getRealResource("compress"); 103 temp=temp.getRealResource(MD5.getDigestAsString(cid+"-"+ffile.getAbsolutePath())); 104 if(!temp.exists())temp.createDirectory(true); 105 106 } 107 catch(Throwable t){} 108 } 109 110 111 if(temp!=null) { 112 String name=Caster.toString(actLastMod)+":"+Caster.toString(ffile.length()); 113 name=MD5.getDigestAsString(name,name); 114 root=temp.getRealResource(name); 115 if(actLastMod>0 && root.exists()) return; 116 117 118 ResourceUtil.removeChildrenEL(temp); 119 //if(root!=null)ResourceUtil.removeChildrenEL(root); 120 //String name=CreateUUID.invoke(); 121 //root=temp.getRealResource(name); 122 root.mkdirs(); 123 } 124 else { 125 ResourceProvider ramProvider = new RamResourceProviderOld().init("ram",args); 126 root=ramProvider.getResource("/"); 127 } 128 _load(); 129 } 130 131 132 133 private void _load() { 134 if(ffile.exists()) { 135 try { 136 CompressUtil.extract(format, ffile, root); 137 } catch (IOException e) {} 138 } 139 else { 140 try { 141 ffile.createFile(false); 142 } 143 catch (IOException e) {} 144 lastMod=ffile.lastModified(); 145 } 146 } 147 148 public Resource getRamProviderResource(String path) { 149 long t=System.currentTimeMillis(); 150 if(t>lastCheck+2000){ 151 152 lastCheck=t; 153 t=ffile.lastModified(); 154 if((lastMod-t)>10 || (t-lastMod)>10 || root==null || !root.exists()){ 155 lastMod=t; 156 load(caseSensitive); 157 } 158 } 159 return root.getRealResource(path);//ramProvider.getResource(path); 160 } 161 162 /** 163 * @return the zipFile 164 */ 165 public Resource getCompressFile() { 166 return ffile; 167 } 168 169 public synchronized void synchronize(boolean async) { 170 if(!async) { 171 doSynchronize(); 172 return; 173 } 174 syn=System.currentTimeMillis(); 175 if(synchronizer==null || !synchronizer.isRunning()) { 176 synchronizer=new Synchronizer(this,100); 177 synchronizer.start(); 178 } 179 } 180 181 private void doSynchronize() { 182 try { 183 CompressUtil.compress(format, root.listResources(), ffile, 777); 184 //ramProvider=null; 185 } 186 catch (IOException e) {} 187 } 188 189 class Synchronizer extends Thread { 190 private Compress zip; 191 private int interval; 192 private boolean running=true; 193 194 public Synchronizer(Compress zip, int interval) { 195 this.zip=zip; 196 this.interval=interval; 197 } 198 199 public void run() { 200 if(FORMAT_TAR==format) runTar(ffile); 201 if(FORMAT_TGZ==format) runTGZ(ffile); 202 else runZip(ffile); 203 204 } 205 206 private void runTGZ(Resource res) { 207 GZIPOutputStream gos=null; 208 InputStream tmpis=null; 209 Resource tmp = SystemUtil.getTempDirectory().getRealResource(System.currentTimeMillis()+"_.tgz"); 210 try { 211 gos=new GZIPOutputStream(res.getOutputStream()); 212 // wait for sync 213 while(true) { 214 sleepEL(); 215 if(zip.syn+interval<=System.currentTimeMillis()) break; 216 } 217 // sync 218 tmpis = tmp.getInputStream(); 219 CompressUtil.compressTar(root.listResources(), tmp, -1); 220 CompressUtil.compressGZip(tmpis, gos); 221 } 222 catch (IOException e) {} 223 finally { 224 IOUtil.closeEL(gos); 225 IOUtil.closeEL(tmpis); 226 tmp.delete(); 227 running=false; 228 } 229 } 230 private void runTar(Resource res) { 231 TarOutputStream tos=null; 232 try { 233 tos=new TarOutputStream(res.getOutputStream()); 234 tos.setLongFileMode(TarOutputStream.LONGFILE_GNU); 235 // wait for sync 236 while(true) { 237 sleepEL(); 238 if(zip.syn+interval<=System.currentTimeMillis()) break; 239 } 240 // sync 241 CompressUtil.compressTar(root.listResources(), tos, -1); 242 } 243 catch (IOException e) {} 244 finally { 245 IOUtil.closeEL(tos); 246 running=false; 247 } 248 } 249 250 private void runZip(Resource res) { 251 ZipOutputStream zos=null; 252 try { 253 zos=new ZipOutputStream(res.getOutputStream()); 254 // wait for sync 255 while(true) { 256 sleepEL(); 257 if(zip.syn+interval<=System.currentTimeMillis()) break; 258 } 259 // sync 260 CompressUtil.compressZip(root.listResources(), zos, null); 261 } 262 catch (IOException e) {} 263 finally { 264 IOUtil.closeEL(zos); 265 running=false; 266 } 267 } 268 269 private void sleepEL() { 270 try { 271 sleep(interval); 272 } 273 catch (InterruptedException e) {} 274 } 275 276 public boolean isRunning() { 277 return running; 278 } 279 } 280 }