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.TarArchiveOutputStream;
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                            TarArchiveOutputStream tos=null;
232                            try {
233                                    tos=new TarArchiveOutputStream(res.getOutputStream());
234                                    tos.setLongFileMode(TarArchiveOutputStream.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    }