package railo.commons.io.res.type.compress;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import railo.commons.digest.MD5;
import railo.commons.io.CompressUtil;
import railo.commons.io.IOUtil;
import railo.commons.io.SystemUtil;
import railo.commons.io.res.Resource;
import railo.commons.io.res.ResourceProvider;
import railo.commons.io.res.type.ram.RamResourceProviderOld;
import railo.commons.io.res.util.ResourceUtil;
import railo.runtime.config.Config;
import railo.runtime.config.ConfigImpl;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.op.Caster;
public final class Compress {
public static final int FORMAT_ZIP = CompressUtil.FORMAT_ZIP;
public static final int FORMAT_TAR = CompressUtil.FORMAT_TAR;
public static final int FORMAT_TGZ = CompressUtil.FORMAT_TGZ;
public static final int FORMAT_TBZ2 = CompressUtil.FORMAT_TBZ2;
//private final static Map files=new WeakHashMap();
private final Resource ffile;
//private ResourceProvider ramProvider;
private long syn=-1;
private Resource root;
private Synchronizer synchronizer;
private long lastMod=-1;
private long lastCheck=-1;
private int format;
private int mode;
private boolean caseSensitive;
private Resource temp;
/**
* private Constructor of the class, will be invoked be getInstance
* @param file
* @param format
* @param caseSensitive
*/
public Compress(Resource file, int format, boolean caseSensitive) {
this.ffile=file;
this.format=format;
this.mode=ffile.getMode();
if(mode==0) mode=0777;
load(this.caseSensitive=caseSensitive);
}
/**
* return zip instance matching the zipfile, singelton isnatce only 1 zip for one file
* @param zipFile
* @param format
* @param caseSensitive
* @return
*/
/*public static Compress getInstance(Resource zipFile, int format, boolean caseSensitive) {
Compress compress=(Compress) files.get(zipFile.getPath());
if(compress==null) {
compress=new Compress(zipFile,format,caseSensitive);
files.put(zipFile.getPath(), compress);
}
return compress;ConfigImpl
}*/
public static Compress getInstance(Resource zipFile, int format, boolean caseSensitive) {
ConfigImpl config=(ConfigImpl) ThreadLocalPageContext.getConfig();
return config.getCompressInstance(zipFile, format, caseSensitive);
}
private synchronized void load(boolean caseSensitive) {
long actLastMod = ffile.lastModified();
lastMod=actLastMod;
lastCheck=System.currentTimeMillis();
Map args = new HashMap();
args.put("case-sensitive", Caster.toBoolean(caseSensitive));
//ramProvider = new RamResourceProviderOld().init("ram",args);
//root=ramProvider.getResource("/");
if(temp==null){
String cid="";
try {
Config config = ThreadLocalPageContext.getConfig();
if(config!=null){
cid=config.getId();
temp = config.getTempDirectory();
}
if(temp==null)temp=SystemUtil.getTempDirectory();
temp=temp.getRealResource("compress");
temp=temp.getRealResource(MD5.getDigestAsString(cid+"-"+ffile.getAbsolutePath()));
if(!temp.exists())temp.createDirectory(true);
}
catch(Throwable t){}
}
if(temp!=null) {
String name=Caster.toString(actLastMod)+":"+Caster.toString(ffile.length());
name=MD5.getDigestAsString(name,name);
root=temp.getRealResource(name);
if(actLastMod>0 && root.exists()) return;
ResourceUtil.removeChildrenEL(temp);
//if(root!=null)ResourceUtil.removeChildrenEL(root);
//String name=CreateUUID.invoke();
//root=temp.getRealResource(name);
root.mkdirs();
}
else {
ResourceProvider ramProvider = new RamResourceProviderOld().init("ram",args);
root=ramProvider.getResource("/");
}
_load();
}
private void _load() {
if(ffile.exists()) {
try {
CompressUtil.extract(format, ffile, root);
} catch (IOException e) {}
}
else {
try {
ffile.createFile(false);
}
catch (IOException e) {}
lastMod=ffile.lastModified();
}
}
public Resource getRamProviderResource(String path) {
long t=System.currentTimeMillis();
if(t>lastCheck+2000){
lastCheck=t;
t=ffile.lastModified();
if((lastMod-t)>10 || (t-lastMod)>10 || root==null || !root.exists()){
lastMod=t;
load(caseSensitive);
}
}
return root.getRealResource(path);//ramProvider.getResource(path);
}
/**
* @return the zipFile
*/
public Resource getCompressFile() {
return ffile;
}
public synchronized void synchronize(boolean async) {
if(!async) {
doSynchronize();
return;
}
syn=System.currentTimeMillis();
if(synchronizer==null || !synchronizer.isRunning()) {
synchronizer=new Synchronizer(this,100);
synchronizer.start();
}
}
private void doSynchronize() {
try {
CompressUtil.compress(format, root.listResources(), ffile, 777);
//ramProvider=null;
}
catch (IOException e) {}
}
class Synchronizer extends Thread {
private Compress zip;
private int interval;
private boolean running=true;
public Synchronizer(Compress zip, int interval) {
this.zip=zip;
this.interval=interval;
}
public void run() {
if(FORMAT_TAR==format) runTar(ffile);
if(FORMAT_TGZ==format) runTGZ(ffile);
else runZip(ffile);
}
private void runTGZ(Resource res) {
GZIPOutputStream gos=null;
InputStream tmpis=null;
Resource tmp = SystemUtil.getTempDirectory().getRealResource(System.currentTimeMillis()+"_.tgz");
try {
gos=new GZIPOutputStream(res.getOutputStream());
// wait for sync
while(true) {
sleepEL();
if(zip.syn+interval<=System.currentTimeMillis()) break;
}
// sync
tmpis = tmp.getInputStream();
CompressUtil.compressTar(root.listResources(), tmp, -1);
CompressUtil.compressGZip(tmpis, gos);
}
catch (IOException e) {}
finally {
IOUtil.closeEL(gos);
IOUtil.closeEL(tmpis);
tmp.delete();
running=false;
}
}
private void runTar(Resource res) {
TarArchiveOutputStream tos=null;
try {
tos=new TarArchiveOutputStream(res.getOutputStream());
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
// wait for sync
while(true) {
sleepEL();
if(zip.syn+interval<=System.currentTimeMillis()) break;
}
// sync
CompressUtil.compressTar(root.listResources(), tos, -1);
}
catch (IOException e) {}
finally {
IOUtil.closeEL(tos);
running=false;
}
}
private void runZip(Resource res) {
ZipOutputStream zos=null;
try {
zos=new ZipOutputStream(res.getOutputStream());
// wait for sync
while(true) {
sleepEL();
if(zip.syn+interval<=System.currentTimeMillis()) break;
}
// sync
CompressUtil.compressZip(root.listResources(), zos, null);
}
catch (IOException e) {}
finally {
IOUtil.closeEL(zos);
running=false;
}
}
private void sleepEL() {
try {
sleep(interval);
}
catch (InterruptedException e) {}
}
public boolean isRunning() {
return running;
}
}
}