001    package railo.commons.io.res.type.datasource;
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.IOUtil;
010    import railo.commons.io.ModeUtil;
011    import railo.commons.io.res.Resource;
012    import railo.commons.io.res.ResourceProvider;
013    import railo.commons.io.res.type.datasource.DatasourceResourceProvider.ConnectionData;
014    import railo.commons.io.res.util.ResourceSupport;
015    import railo.commons.io.res.util.ResourceUtil;
016    import railo.commons.lang.StringUtil;
017    import railo.runtime.exp.PageException;
018    import railo.runtime.exp.PageRuntimeException;
019    import railo.runtime.type.util.ArrayUtil;
020    
021    public final class DatasourceResource extends ResourceSupport {
022    
023            
024    
025            private DatasourceResourceProvider provider;
026            private String parent;
027            private String name;
028            private ConnectionData data;
029            private int fullPathHash;
030            private int pathHash;
031            
032            /**
033             * Constructor of the class
034             * @param provider
035             * @param data
036             * @param path
037             */
038            DatasourceResource(DatasourceResourceProvider provider, ConnectionData data,String path) {
039                    this.provider=provider;
040                    this.data=data;
041                    if("/".equals(path)) {
042                            this.parent=null;
043                            this.name="";
044                    }
045                    else {
046                            String[] pn = ResourceUtil.translatePathName(path);
047                            this.parent=pn[0];
048                            this.name=pn[1];
049                    }
050            }
051    
052    
053            private int fullPathHash() {
054                    if(fullPathHash==0) fullPathHash=getInnerPath().hashCode();
055                    return fullPathHash;
056            }
057            
058            private int pathHash() {
059                    if(pathHash==0 && parent!=null) pathHash=parent.hashCode();
060                    return pathHash;
061            }
062    
063            private Attr attr() {
064                    return provider.getAttr(data,fullPathHash(),parent,name);
065            }
066    
067    
068            private boolean isRoot() {
069                    return parent==null;
070            }
071            
072            @Override
073            public void createDirectory(boolean createParentWhenNotExists) throws IOException {
074                    ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists);
075                    provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_DIRECTORY);
076                    
077            }
078    
079            @Override
080            public void createFile(boolean createParentWhenNotExists) throws IOException {
081                    ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists);
082                    provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_FILE);
083            }
084            
085            @Override
086            public void remove(boolean force) throws IOException {
087                    ResourceUtil.checkRemoveOK(this);
088                    if(isRoot()) 
089                            throw new IOException("can't remove root resource ["+getPath()+"]");
090    
091                    
092                    Resource[] children = listResources();
093                    if(children!=null && children.length>0) {
094                            if(!force) {
095                                    throw new IOException("can't delete directory ["+getPath()+"], directory is not empty");
096                            }
097                            for(int i=0;i<children.length;i++) {
098                                    children[i].remove(true);
099                            }
100                    }
101                    provider.delete(data,fullPathHash(),parent,name);
102            }
103    
104            @Override
105            public boolean exists() {
106                    return attr().exists();
107            }
108    
109            @Override
110            public InputStream getInputStream() throws IOException {
111                    ResourceUtil.checkGetInputStreamOK(this);
112                    return provider.getInputStream(data,fullPathHash(),parent,name);
113            }
114    
115            @Override
116            public int getMode() {
117                    return attr().getMode();
118            }
119    
120            @Override
121            public String getName() {
122                    return name;
123            }
124    
125            @Override
126            public OutputStream getOutputStream(boolean append) throws IOException {
127                    ResourceUtil.checkGetOutputStreamOK(this);
128                    byte[] barr=null;
129                    
130                    if(append && !provider.concatSupported(data) && isFile()){
131                            try{
132                                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
133                                    IOUtil.copy(getInputStream(), baos,true,true);
134                                    barr = baos.toByteArray();
135                            }
136                            catch(Throwable t){
137                                    
138                            }
139                    }
140                    
141                    OutputStream os = provider.getOutputStream(data,fullPathHash(),pathHash(),parent,name,append);
142                    if(!ArrayUtil.isEmpty(barr))IOUtil.copy(new ByteArrayInputStream(barr), os,true,false);
143                    return os;
144            }
145    
146            @Override
147            public String getParent() {
148                    if(isRoot()) return null;
149                    String p = (StringUtil.isEmpty(parent))?"/":parent;
150                    return provider.getScheme().concat("://").concat(data.key()).concat(ResourceUtil.translatePath(p, true, false));
151                    
152            }
153    
154            @Override
155            public Resource getParentResource() {
156                    return getParentDatasourceResource();
157            }
158            private DatasourceResource getParentDatasourceResource() {
159                    if(isRoot()) return null;
160                    return new DatasourceResource(provider,data,parent);
161            }
162    
163            @Override
164            public String getPath() {
165                    return provider.getScheme().concat("://").concat(data.key()).concat(getInnerPath());
166            }
167            private String getInnerPath() {
168                    if(parent==null) return "/";
169                    return parent.concat(name);
170            }
171    
172            @Override
173            public Resource getRealResource(String realpath) {
174                    realpath=ResourceUtil.merge(getInnerPath(), realpath);
175                    if(realpath.startsWith("../"))return null;
176    
177                    return new DatasourceResource(provider,data,realpath);
178            }
179    
180            @Override
181            public ResourceProvider getResourceProvider() {
182                    return provider;
183            }
184    
185            @Override
186            public boolean isAbsolute() {
187                    return true;
188            }
189    
190            @Override
191            public boolean isDirectory() {
192                    return attr().isDirectory();
193            }
194            
195            @Override
196            public boolean isFile() {
197                    return attr().isFile();
198            }
199    
200            @Override
201            public boolean isReadable() {
202                    return ModeUtil.isReadable(getMode());
203            }
204    
205            @Override
206            public boolean isWriteable() {
207                    return ModeUtil.isWritable(getMode());
208            }
209    
210            @Override
211            public long lastModified() {
212                    return attr().getLastModified();
213            }
214    
215            @Override
216            public long length() {
217                    return attr().size();
218            }
219    
220            @Override
221            public Resource[] listResources() {
222                    if(!attr().isDirectory())return null;
223                    
224                    String path;
225                    if(parent==null) path= "/";
226                    else path=parent.concat(name).concat("/");
227                    
228                    
229                    Attr[] children=null;
230                    try {
231                            children = provider.getAttrs(data,path.hashCode(),path);
232                    } catch (PageException e) {
233                            throw new PageRuntimeException(e);
234                    }
235                    if(children==null) return new Resource[0];
236                    Resource[] attrs = new Resource[children.length];
237                    for(int i=0;i<children.length;i++) {
238                            // TODO optimieren, alle attr mitgeben
239                            attrs[i]=new DatasourceResource(provider,data,path+children[i].getName());
240                    }
241                    return attrs;
242            }
243    
244            @Override
245            public boolean setLastModified(long time) {
246                    if(!exists()) return false;
247                    return provider.setLastModified(data,fullPathHash(),parent,name,time);
248            }
249    
250            @Override
251            public void setMode(int mode) throws IOException {
252                    if(!exists())throw new IOException("can't set mode on resource ["+this+"], resource does not exist");
253                    provider.setMode(data,fullPathHash(),parent,name,mode);
254            }
255    
256    
257            @Override
258            public void moveTo(Resource dest) throws IOException {
259                    super.moveTo(dest);// TODO
260            }
261            
262            
263            @Override
264            public boolean setReadable(boolean readable) {
265                    if(!exists())return false;
266                    try {
267                            setMode(ModeUtil.setReadable(getMode(), readable));
268                            return true;
269                    } catch (IOException e) {
270                            return false;
271                    }
272            }
273    
274            @Override
275            public boolean setWritable(boolean writable) {
276                    if(!exists())return false;
277                    try {
278                            setMode(ModeUtil.setWritable(getMode(), writable));
279                            return true;
280                    } catch (IOException e) {
281                            return false;
282                    }
283            }
284            
285            @Override
286            public String toString() {
287                    return getPath();
288            }
289    
290    }