001    package railo.commons.io.res.type.ram;
002    
003    import java.io.ByteArrayInputStream;
004    import java.io.ByteArrayOutputStream;
005    import java.io.IOException;
006    import java.io.InputStream;
007    import java.io.OutputStream;
008    
009    import railo.commons.io.ModeUtil;
010    import railo.commons.io.res.ContentType;
011    import railo.commons.io.res.Resource;
012    import railo.commons.io.res.ResourceProvider;
013    import railo.commons.io.res.util.ResourceSupport;
014    import railo.commons.io.res.util.ResourceUtil;
015    import railo.commons.lang.StringUtil;
016    
017    
018    /**
019     * a ram resource
020     */
021    public final class RamResource extends ResourceSupport {
022            
023            private final RamResourceProviderOld provider;
024            
025            private final String parent;
026            private final String name;
027            private RamResourceCore _core;
028    
029            RamResource(RamResourceProviderOld provider, String path) {
030                    this.provider=provider;
031                    if(path.equals("/") || StringUtil.isEmpty(path)) {
032                    //if(path.equals("/")) {
033                            this.parent=null;
034                            this.name="";
035                    }
036                    else {
037                            String[] pn = ResourceUtil.translatePathName(path);
038                            this.parent=pn[0];
039                            this.name=pn[1];
040                    }
041                    
042            }
043            
044            private RamResource(RamResourceProviderOld provider, String parent,String name) {
045                    this.provider=provider;
046                    this.parent=parent ;
047                    this.name=name;
048            }
049            
050            RamResourceCore getCore() {
051                    if(_core==null || _core.getType()==0) {
052                            _core=provider.getCore(getInnerPath());
053                    }
054                    return _core;
055            }
056            
057    
058            void removeCore() {
059                    if(_core==null)return;
060                    _core.remove();
061                    _core=null;
062            }
063            
064            private RamResourceCore createCore(int type) throws IOException {
065                    return _core=provider.createCore(getInnerPath(),type);
066            }
067            
068    
069            /**
070             * @see res.Resource#getPath()
071             */
072            public String getPath() {
073                    return provider.getScheme().concat("://").concat(getInnerPath());
074            }
075            private String getInnerPath() {
076                    if(parent==null) return "/";
077                    return parent.concat(name);
078            }
079    
080            /**
081             * @see res.Resource#getFullName()
082             */
083            public String getName() {
084                    return name;
085            }
086    
087            /**
088             * @see res.Resource#getParent()
089             */
090            public String getParent() {
091                    if(isRoot()) return null;
092                    return provider.getScheme().concat("://").concat(ResourceUtil.translatePath(parent, true, false));
093            }
094    
095            /**
096             * @see res.Resource#isReadable()
097             */
098            public boolean isReadable() {
099                    return ModeUtil.isReadable(getMode());
100            }
101    
102            /**
103             * @see res.Resource#isWriteable()
104             */
105            public boolean isWriteable() {
106                    return ModeUtil.isWritable(getMode());
107            }
108    
109            /**
110             * @see res.Resource#removeE(boolean)
111             */
112            public void remove(boolean force) throws IOException {
113                    if(isRoot()) 
114                            throw new IOException("can't remove root resource ["+getPath()+"]");
115    
116                    provider.read(this);
117                    RamResourceCore core = getCore();
118                    if(core==null)
119                            throw new IOException("can't remove resource ["+getPath()+"],resource does not exists");
120                    
121                    Resource[] children = listResources();
122                    if(children!=null && children.length>0) {
123                            if(!force) {
124                                    throw new IOException("can't delete directory ["+getPath()+"], directory is not empty");
125                            }
126                            for(int i=0;i<children.length;i++) {
127                                    children[i].remove(true);
128                            }
129                    }
130                    removeCore();
131            }
132    
133            /**
134             * @see res.Resource#exists()
135             */
136            public boolean exists() {
137                    try {
138                            provider.read(this);
139                    } catch (IOException e) {
140                            return true;
141                    }
142                    return getCore()!=null;
143            }
144    
145            /**
146             * @see res.Resource#getParentResource()
147             */
148            public Resource getParentResource() {
149                    return getParentRamResource();
150            }
151    
152    
153            private RamResource getParentRamResource() {
154                    if(isRoot()) return null;
155                    return new RamResource(provider,parent);
156            }
157    
158            public Resource getRealResource(String realpath) {
159                    realpath=ResourceUtil.merge(getInnerPath(), realpath);
160                    if(realpath.startsWith("../"))return null;
161    
162                    return new RamResource(provider,realpath);
163            }
164    
165            /**
166             * @see res.Resource#isAbsolute()
167             */
168            public boolean isAbsolute() {
169                    return true;
170            }
171    
172            /**
173             * @see res.Resource#isDirectory()
174             */
175            public boolean isDirectory() {
176                    return exists() && getCore().getType()==RamResourceCore.TYPE_DIRECTORY;
177            }
178    
179            /**
180             * @see res.Resource#isFile()
181             */
182            public boolean isFile() {
183                    return exists() && getCore().getType()==RamResourceCore.TYPE_FILE;
184            }
185    
186            /**
187             * @see res.Resource#lastModified()
188             */
189            public long lastModified() {
190                    if(!exists()) return 0;
191                    return getCore().getLastModified();
192            }
193    
194            /**
195             * @see res.Resource#length()
196             */
197            public long length() {
198                    if(!exists()) return 0;
199                    byte[] data= getCore().getData();
200                    if(data==null) return 0;
201                    return data.length;
202            }
203    
204            /**
205             * @see res.Resource#list()
206             */
207            public String[] list() {
208                    if(!exists()) return null;
209                    RamResourceCore core = getCore();
210                    if(core.getType()!=RamResourceCore.TYPE_DIRECTORY)
211                            return null;
212                    
213                    return core.getChildNames();
214                    /*List list = core.getChildren();
215                    if(list==null && list.size()==0) return new String[0];
216                    
217                    Iterator it = list.iterator();
218                    String[] children=new String[list.size()];
219                    RamResourceCore cc;
220                    int count=0;
221                    while(it.hasNext()) {
222                            cc=(RamResourceCore) it.next();
223                            children[count++]=cc.getName();
224                    }
225                    return children;*/
226            }
227    
228            /**
229             * @see res.Resource#listResources()
230             */
231            public Resource[] listResources() {
232                    String[] list = list();
233                    if(list==null)return null;
234                    
235                    Resource[] children=new Resource[list.length];
236                    String p=getInnerPath();
237                    if(!isRoot())p=p.concat("/");
238                    for(int i=0;i<children.length;i++) {
239                            children[i]=new RamResource(provider,p,list[i]);
240                    }
241                    return children;
242            }
243    
244            /**
245             * @see res.Resource#setLastModified(long)
246             */
247            public boolean setLastModified(long time) {
248                    if(!exists()) return false;
249                    getCore().setLastModified(time);
250                    return true;
251            }
252    
253            /**
254             * @see res.Resource#setReadOnly()
255             */
256            public boolean setReadOnly() {
257                    return setWritable(false);
258            }
259    
260            /**
261             * @throws IOException 
262             * @see res.Resource#createFile(boolean)
263             */
264            public void createFile(boolean createParentWhenNotExists) throws IOException {
265                    ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists);
266                    provider.lock(this);
267                    try {
268                            createCore(RamResourceCore.TYPE_FILE);
269                    }
270                    finally {
271                            provider.unlock(this);
272                    }
273            }
274    
275    
276            /**
277             * @see res.Resource#createDirectory(boolean)
278             */
279            public void createDirectory(boolean createParentWhenNotExists) throws IOException {
280                    ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists);
281                    provider.lock(this);
282                    try {
283                            createCore(RamResourceCore.TYPE_DIRECTORY);
284                    }
285                    finally {
286                            provider.unlock(this);
287                    }
288                    
289            }
290    
291            /**
292             * @see res.Resource#getInputStream()
293             */
294            public InputStream getInputStream() throws IOException {
295                    ResourceUtil.checkGetInputStreamOK(this);
296    
297                    provider.lock(this);
298                    RamResourceCore core = getCore();
299                    
300                    byte[] data = core.getData();
301                    if(data==null)data=new byte[0];
302                    provider.unlock(this);
303                    return new ByteArrayInputStream(data);
304            }
305    
306            public OutputStream getOutputStream(boolean append) throws IOException {
307                    ResourceUtil.checkGetOutputStreamOK(this);
308                    provider.lock(this);
309                    return new RamOutputStream(this,append);
310            }
311    
312            /**
313             *
314             * @see railo.commons.io.res.Resource#getContentType()
315             */
316            public ContentType getContentType() {
317                    return ResourceUtil.getContentType(this);
318            }
319    
320            /**
321             * @see res.Resource#getResourceProvider()
322             */
323            public ResourceProvider getResourceProvider() {
324                    return provider;
325            }
326            /**
327             * @see java.lang.Object#toString()
328             */
329            public String toString() {
330                    return getPath();
331            }
332            
333    
334            /**
335             * This is useed by the MemoryResource too write back data to, that are written to outputstream
336             */
337            class RamOutputStream extends ByteArrayOutputStream {
338    
339                    private RamResource res;
340                    private boolean append;
341    
342                    /**
343                     * Constructor of the class
344                     * @param res
345                     */
346                    public RamOutputStream(RamResource res, boolean append) {
347                            this.append=append;
348                            this.res=res;
349                    }
350    
351                    /**
352                     * @see java.io.ByteArrayOutputStream#close()
353                     */
354                    public void close() throws IOException {
355                            try {
356                                    super.close();
357                                    RamResourceCore core = res.getCore();
358                                    if(core==null)core=res.createCore(RamResourceCore.TYPE_FILE);
359                                    
360                                    core.setData(this.toByteArray(),append);
361                            }
362                            finally {
363                                    res.getResourceProvider().unlock(res);
364                            }
365                    }
366            }
367    
368            /**
369             * @see railo.commons.io.res.Resource#setReadable(boolean)
370             */
371            public boolean setReadable(boolean value) {
372                    if(!exists())return false;
373                    try {
374                            setMode(ModeUtil.setReadable(getMode(), value));
375                            return true;
376                    } catch (IOException e) {
377                            return false;
378                    }
379                    
380            }
381            
382            /**
383             * @see railo.commons.io.res.Resource#setWritable(boolean)
384             */
385            public boolean setWritable(boolean value) {
386                    if(!exists())return false;
387                    try {
388                            setMode(ModeUtil.setWritable(getMode(), value));
389                            return true;
390                    } catch (IOException e) {
391                            return false;
392                    }
393            }
394    
395            private boolean isRoot() {
396                    return parent==null;
397            }
398            
399            public int getMode() {
400                    if(!exists())return 0;
401                    return getCore().getMode();
402            }
403            
404            public void setMode(int mode) throws IOException {
405                    if(!exists())throw new IOException("can't set mode on resource ["+this+"], resource does not exists");
406                    getCore().setMode(mode);
407            }
408            /**
409             *
410             * @see railo.commons.io.res.util.ResourceSupport#getAttribute(short)
411             */
412            public boolean getAttribute(short attribute) {
413                    if(!exists())return false;
414                    return (getCore().getAttributes()&attribute)>0;
415            }
416            /**
417             *
418             * @see railo.commons.io.res.util.ResourceSupport#setAttribute(short, boolean)
419             */
420            public void setAttribute(short attribute, boolean value) throws IOException {
421                    if(!exists())throw new IOException("can't get attributes on resource ["+this+"], resource does not exists");
422                    int attr = getCore().getAttributes();
423                    if(value) {
424                            if((attr&attribute)==0) attr+=attribute;
425                    }
426                    else {
427                            if((attr&attribute)>0) attr-=attribute;
428                    }
429                    getCore().setAttributes(attr);
430            }
431            
432    }