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            @Override
070            public String getPath() {
071                    return provider.getScheme().concat("://").concat(getInnerPath());
072            }
073            private String getInnerPath() {
074                    if(parent==null) return "/";
075                    return parent.concat(name);
076            }
077    
078            @Override
079            public String getName() {
080                    return name;
081            }
082    
083            @Override
084            public String getParent() {
085                    if(isRoot()) return null;
086                    return provider.getScheme().concat("://").concat(ResourceUtil.translatePath(parent, true, false));
087            }
088    
089            @Override
090            public boolean isReadable() {
091                    return ModeUtil.isReadable(getMode());
092            }
093    
094            @Override
095            public boolean isWriteable() {
096                    return ModeUtil.isWritable(getMode());
097            }
098    
099            @Override
100            public void remove(boolean force) throws IOException {
101                    if(isRoot()) 
102                            throw new IOException("can't remove root resource ["+getPath()+"]");
103    
104                    provider.read(this);
105                    RamResourceCore core = getCore();
106                    if(core==null)
107                            throw new IOException("can't remove resource ["+getPath()+"],resource does not exist");
108                    
109                    Resource[] children = listResources();
110                    if(children!=null && children.length>0) {
111                            if(!force) {
112                                    throw new IOException("can't delete directory ["+getPath()+"], directory is not empty");
113                            }
114                            for(int i=0;i<children.length;i++) {
115                                    children[i].remove(true);
116                            }
117                    }
118                    removeCore();
119            }
120    
121            @Override
122            public boolean exists() {
123                    try {
124                            provider.read(this);
125                    } catch (IOException e) {
126                            return true;
127                    }
128                    return getCore()!=null;
129            }
130    
131            @Override
132            public Resource getParentResource() {
133                    return getParentRamResource();
134            }
135    
136    
137            private RamResource getParentRamResource() {
138                    if(isRoot()) return null;
139                    return new RamResource(provider,parent);
140            }
141    
142            public Resource getRealResource(String realpath) {
143                    realpath=ResourceUtil.merge(getInnerPath(), realpath);
144                    if(realpath.startsWith("../"))return null;
145    
146                    return new RamResource(provider,realpath);
147            }
148    
149            @Override
150            public boolean isAbsolute() {
151                    return true;
152            }
153    
154            @Override
155            public boolean isDirectory() {
156                    return exists() && getCore().getType()==RamResourceCore.TYPE_DIRECTORY;
157            }
158    
159            @Override
160            public boolean isFile() {
161                    return exists() && getCore().getType()==RamResourceCore.TYPE_FILE;
162            }
163    
164            @Override
165            public long lastModified() {
166                    if(!exists()) return 0;
167                    return getCore().getLastModified();
168            }
169    
170            @Override
171            public long length() {
172                    if(!exists()) return 0;
173                    byte[] data= getCore().getData();
174                    if(data==null) return 0;
175                    return data.length;
176            }
177    
178            @Override
179            public String[] list() {
180                    if(!exists()) return null;
181                    RamResourceCore core = getCore();
182                    if(core.getType()!=RamResourceCore.TYPE_DIRECTORY)
183                            return null;
184                    
185                    return core.getChildNames();
186                    /*List list = core.getChildren();
187                    if(list==null && list.size()==0) return new String[0];
188                    
189                    Iterator it = list.iterator();
190                    String[] children=new String[list.size()];
191                    RamResourceCore cc;
192                    int count=0;
193                    while(it.hasNext()) {
194                            cc=(RamResourceCore) it.next();
195                            children[count++]=cc.getName();
196                    }
197                    return children;*/
198            }
199    
200            @Override
201            public Resource[] listResources() {
202                    String[] list = list();
203                    if(list==null)return null;
204                    
205                    Resource[] children=new Resource[list.length];
206                    String p=getInnerPath();
207                    if(!isRoot())p=p.concat("/");
208                    for(int i=0;i<children.length;i++) {
209                            children[i]=new RamResource(provider,p,list[i]);
210                    }
211                    return children;
212            }
213    
214            @Override
215            public boolean setLastModified(long time) {
216                    if(!exists()) return false;
217                    getCore().setLastModified(time);
218                    return true;
219            }
220    
221            @Override
222            public boolean setReadOnly() {
223                    return setWritable(false);
224            }
225    
226            @Override
227            public void createFile(boolean createParentWhenNotExists) throws IOException {
228                    ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists);
229                    provider.lock(this);
230                    try {
231                            createCore(RamResourceCore.TYPE_FILE);
232                    }
233                    finally {
234                            provider.unlock(this);
235                    }
236            }
237    
238    
239            @Override
240            public void createDirectory(boolean createParentWhenNotExists) throws IOException {
241                    ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists);
242                    provider.lock(this);
243                    try {
244                            createCore(RamResourceCore.TYPE_DIRECTORY);
245                    }
246                    finally {
247                            provider.unlock(this);
248                    }
249                    
250            }
251    
252            @Override
253            public InputStream getInputStream() throws IOException {
254                    ResourceUtil.checkGetInputStreamOK(this);
255    
256                    provider.lock(this);
257                    RamResourceCore core = getCore();
258                    
259                    byte[] data = core.getData();
260                    if(data==null)data=new byte[0];
261                    provider.unlock(this);
262                    return new ByteArrayInputStream(data);
263            }
264    
265            public OutputStream getOutputStream(boolean append) throws IOException {
266                    ResourceUtil.checkGetOutputStreamOK(this);
267                    provider.lock(this);
268                    return new RamOutputStream(this,append);
269            }
270    
271            public ContentType getContentType() {
272                    return ResourceUtil.getContentType(this);
273            }
274    
275            @Override
276            public ResourceProvider getResourceProvider() {
277                    return provider;
278            }
279            @Override
280            public String toString() {
281                    return getPath();
282            }
283            
284    
285            /**
286             * This is useed by the MemoryResource too write back data to, that are written to outputstream
287             */
288            class RamOutputStream extends ByteArrayOutputStream {
289    
290                    private RamResource res;
291                    private boolean append;
292    
293                    /**
294                     * Constructor of the class
295                     * @param res
296                     */
297                    public RamOutputStream(RamResource res, boolean append) {
298                            this.append=append;
299                            this.res=res;
300                    }
301    
302                    @Override
303                    public void close() throws IOException {
304                            try {
305                                    super.close();
306                                    RamResourceCore core = res.getCore();
307                                    if(core==null)core=res.createCore(RamResourceCore.TYPE_FILE);
308                                    
309                                    core.setData(this.toByteArray(),append);
310                            }
311                            finally {
312                                    res.getResourceProvider().unlock(res);
313                            }
314                    }
315            }
316    
317            @Override
318            public boolean setReadable(boolean value) {
319                    if(!exists())return false;
320                    try {
321                            setMode(ModeUtil.setReadable(getMode(), value));
322                            return true;
323                    } catch (IOException e) {
324                            return false;
325                    }
326                    
327            }
328            
329            @Override
330            public boolean setWritable(boolean value) {
331                    if(!exists())return false;
332                    try {
333                            setMode(ModeUtil.setWritable(getMode(), value));
334                            return true;
335                    } catch (IOException e) {
336                            return false;
337                    }
338            }
339    
340            private boolean isRoot() {
341                    return parent==null;
342            }
343            
344            public int getMode() {
345                    if(!exists())return 0;
346                    return getCore().getMode();
347            }
348            
349            public void setMode(int mode) throws IOException {
350                    if(!exists())throw new IOException("can't set mode on resource ["+this+"], resource does not exist");
351                    getCore().setMode(mode);
352            }
353            @Override
354            public boolean getAttribute(short attribute) {
355                    if(!exists())return false;
356                    return (getCore().getAttributes()&attribute)>0;
357            }
358            @Override
359            public void setAttribute(short attribute, boolean value) throws IOException {
360                    if(!exists())throw new IOException("can't get attributes on resource ["+this+"], resource does not exist");
361                    int attr = getCore().getAttributes();
362                    if(value) {
363                            if((attr&attribute)==0) attr+=attribute;
364                    }
365                    else {
366                            if((attr&attribute)>0) attr-=attribute;
367                    }
368                    getCore().setAttributes(attr);
369            }
370            
371    }