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.res.type.compress;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.OutputStream;
024
025import lucee.commons.io.res.Resource;
026import lucee.commons.io.res.ResourceProvider;
027import lucee.commons.io.res.util.ResourceSupport;
028import lucee.commons.io.res.util.ResourceUtil;
029import lucee.commons.lang.StringUtil;
030
031public final class CompressResource extends ResourceSupport {
032
033        private final CompressResourceProvider provider;
034        private final Compress zip;
035        private final String path;
036        private final String name;
037        private final String parent;
038        private final boolean caseSensitive; 
039
040        /**
041         * Constructor of the class
042         * @param provider
043         * @param zip
044         * @param path
045         * @param caseSensitive
046         */
047        CompressResource(CompressResourceProvider provider, Compress zip, String path, boolean caseSensitive) {
048                if(StringUtil.isEmpty(path)) path="/";
049                this.provider=provider;
050                this.zip=zip; 
051                this.path=path;
052                
053                if("/".equals(path)) {
054                        this.parent=null;
055                        this.name="";
056                }
057                else {
058                        String[] pn = ResourceUtil.translatePathName(path);
059                        this.parent=pn[0];
060                        this.name=pn[1];
061                }
062                
063                this.caseSensitive=caseSensitive;
064        }
065
066        /**
067         * @return return ram resource that contain the data
068         */
069        private Resource getRamResource() {
070                return zip.getRamProviderResource(path);
071        }
072
073        @Override
074        public boolean exists() {
075                try {
076                        provider.read(this);
077                } 
078                catch (IOException e) {
079                        return false;
080                }
081                return getRamResource().exists();
082        }
083
084        @Override
085        public InputStream getInputStream() throws IOException {
086                ResourceUtil.checkGetInputStreamOK(this);
087                return getRamResource().getInputStream();
088        }
089        
090        public Resource getCompressResource() {
091                return zip.getCompressFile();
092        }
093        
094        public String getCompressPath() {
095                return path;
096        }
097
098        @Override
099        public String getName() {
100                return name;
101        }
102
103        @Override
104        public String getParent() {
105                if(StringUtil.isEmpty(parent))return null;
106                return provider.getScheme().concat("://").concat(zip.getCompressFile().getPath()).concat("!").concat(parent);
107        }
108
109        @Override
110        public Resource getParentResource() {
111                if(StringUtil.isEmpty(parent))return null;
112                return new CompressResource(provider,zip,parent,caseSensitive);
113        }
114
115        @Override
116        public String getPath() {
117                return provider.getScheme().concat("://").concat(zip.getCompressFile().getPath()).concat("!").concat(path);
118        }
119
120        @Override
121        public Resource getRealResource(String realpath) {
122                realpath=ResourceUtil.merge(path, realpath);
123                if(realpath.startsWith("../"))return null;
124                return new CompressResource(provider,zip,realpath,caseSensitive);
125        }
126
127        @Override
128        public ResourceProvider getResourceProvider() {
129                return provider;
130        }
131
132        @Override
133        public boolean isAbsolute() {
134                return getRamResource().isAbsolute();
135        }
136
137        @Override
138        public boolean isDirectory() {
139                return getRamResource().isDirectory();
140        }
141
142        @Override
143        public boolean isFile() {
144                return getRamResource().isFile();
145        }
146
147        @Override
148        public boolean isReadable() {
149                return getRamResource().isReadable();
150        }
151
152        @Override
153        public boolean isWriteable() {
154                return getRamResource().isWriteable();
155        }
156
157        @Override
158        public long lastModified() {
159                return getRamResource().lastModified();
160        }
161
162        @Override
163        public long length() {
164                return getRamResource().length();
165        }
166
167        @Override
168        public Resource[] listResources() {
169                String[] names = list();
170                if(names==null) return null;
171                Resource[] children = new Resource[names.length];
172                for(int i=0;i<children.length;i++) {
173                        children[i]=new CompressResource(provider,zip,path.concat("/").concat(names[i]),caseSensitive);
174                }
175                return children;
176        }
177        
178        @Override
179        public String[] list() {
180                return getRamResource().list();
181        }
182
183        @Override
184        public void remove(boolean force) throws IOException {
185                Resource rr = getRamResource();
186                if(rr.getParent()==null) 
187                        throw new IOException("can't remove root resource ["+getPath()+"]");
188                
189                if(!rr.exists())
190                        throw new IOException("can't remove resource ["+getPath()+"],resource does not exist");
191                
192                Resource[] children = listResources();
193                if(children!=null && children.length>0) {
194                        if(!force) {
195                                throw new IOException("can't delete directory ["+getPath()+"], directory is not empty");
196                        }
197                        for(int i=0;i<children.length;i++) {
198                                children[i].remove(true);
199                        }
200                }
201                rr.remove(force);
202        }
203
204        @Override
205        public boolean setLastModified(long time) {
206                boolean lm = getRamResource().setLastModified(time);
207                zip.synchronize(provider.async);
208                return lm;
209        }
210        
211        @Override
212        public void createDirectory(boolean createParentWhenNotExists) throws IOException {
213                ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists);
214                getRamResource().createDirectory(createParentWhenNotExists);
215                zip.synchronize(provider.async);
216        }
217
218        @Override
219        public void createFile(boolean createParentWhenNotExists) throws IOException {
220                ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists);
221                getRamResource().createFile(createParentWhenNotExists);
222                zip.synchronize(provider.async);
223        }
224
225        @Override
226        public OutputStream getOutputStream() throws IOException {
227                ResourceUtil.checkGetOutputStreamOK(this);
228                //Resource res = getRamResource();
229                //Resource p = res.getParentResource();
230                //if(p!=null && !p.exists())p.mkdirs();
231                return new CompressOutputStreamSynchronizer(getRamResource().getOutputStream(),zip,provider.async);
232        }
233
234        @Override
235        public OutputStream getOutputStream(boolean append) throws IOException {
236                return new CompressOutputStreamSynchronizer(getRamResource().getOutputStream(append),zip,provider.async);
237        }
238
239        @Override
240        public int getMode() {
241                return getRamResource().getMode();
242        }
243
244        @Override
245        public void setMode(int mode) throws IOException {
246                getRamResource().setMode(mode);
247                zip.synchronize(provider.async);
248                
249        }
250
251        @Override
252        public boolean setReadable(boolean value) {
253                if(!isFile())return false;
254                getRamResource().setReadable(value);
255                zip.synchronize(provider.async);
256                return true;
257        }
258
259        @Override
260        public boolean setWritable(boolean value) {
261                if(!isFile())return false;
262                getRamResource().setWritable(value);
263                zip.synchronize(provider.async);
264                return true;
265        }
266
267}