package railo.commons.io.res.type.datasource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import railo.commons.io.IOUtil; import railo.commons.io.ModeUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.ResourceProvider; import railo.commons.io.res.type.datasource.DatasourceResourceProvider.ConnectionData; import railo.commons.io.res.util.ResourceSupport; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.StringUtil; import railo.runtime.exp.PageException; import railo.runtime.exp.PageRuntimeException; import railo.runtime.type.util.ArrayUtil; public final class DatasourceResource extends ResourceSupport { private DatasourceResourceProvider provider; private String parent; private String name; private ConnectionData data; private int fullPathHash; private int pathHash; /** * Constructor of the class * @param provider * @param data * @param path */ DatasourceResource(DatasourceResourceProvider provider, ConnectionData data,String path) { this.provider=provider; this.data=data; if("/".equals(path)) { this.parent=null; this.name=""; } else { String[] pn = ResourceUtil.translatePathName(path); this.parent=pn[0]; this.name=pn[1]; } } private int fullPathHash() { if(fullPathHash==0) fullPathHash=getInnerPath().hashCode(); return fullPathHash; } private int pathHash() { if(pathHash==0 && parent!=null) pathHash=parent.hashCode(); return pathHash; } private Attr attr() { return provider.getAttr(data,fullPathHash(),parent,name); } private boolean isRoot() { return parent==null; } @Override public void createDirectory(boolean createParentWhenNotExists) throws IOException { ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists); provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_DIRECTORY); } @Override public void createFile(boolean createParentWhenNotExists) throws IOException { ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists); provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_FILE); } @Override public void remove(boolean force) throws IOException { ResourceUtil.checkRemoveOK(this); if(isRoot()) throw new IOException("can't remove root resource ["+getPath()+"]"); Resource[] children = listResources(); if(children!=null && children.length>0) { if(!force) { throw new IOException("can't delete directory ["+getPath()+"], directory is not empty"); } for(int i=0;i<children.length;i++) { children[i].remove(true); } } provider.delete(data,fullPathHash(),parent,name); } @Override public boolean exists() { return attr().exists(); } @Override public InputStream getInputStream() throws IOException { ResourceUtil.checkGetInputStreamOK(this); return provider.getInputStream(data,fullPathHash(),parent,name); } @Override public int getMode() { return attr().getMode(); } @Override public String getName() { return name; } @Override public OutputStream getOutputStream(boolean append) throws IOException { ResourceUtil.checkGetOutputStreamOK(this); byte[] barr=null; if(append && !provider.concatSupported(data) && isFile()){ try{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtil.copy(getInputStream(), baos,true,true); barr = baos.toByteArray(); } catch(Throwable t){ } } OutputStream os = provider.getOutputStream(data,fullPathHash(),pathHash(),parent,name,append); if(!ArrayUtil.isEmpty(barr))IOUtil.copy(new ByteArrayInputStream(barr), os,true,false); return os; } @Override public String getParent() { if(isRoot()) return null; String p = (StringUtil.isEmpty(parent))?"/":parent; return provider.getScheme().concat("://").concat(data.key()).concat(ResourceUtil.translatePath(p, true, false)); } @Override public Resource getParentResource() { return getParentDatasourceResource(); } private DatasourceResource getParentDatasourceResource() { if(isRoot()) return null; return new DatasourceResource(provider,data,parent); } @Override public String getPath() { return provider.getScheme().concat("://").concat(data.key()).concat(getInnerPath()); } private String getInnerPath() { if(parent==null) return "/"; return parent.concat(name); } @Override public Resource getRealResource(String realpath) { realpath=ResourceUtil.merge(getInnerPath(), realpath); if(realpath.startsWith("../"))return null; return new DatasourceResource(provider,data,realpath); } @Override public ResourceProvider getResourceProvider() { return provider; } @Override public boolean isAbsolute() { return true; } @Override public boolean isDirectory() { return attr().isDirectory(); } @Override public boolean isFile() { return attr().isFile(); } @Override public boolean isReadable() { return ModeUtil.isReadable(getMode()); } @Override public boolean isWriteable() { return ModeUtil.isWritable(getMode()); } @Override public long lastModified() { return attr().getLastModified(); } @Override public long length() { return attr().size(); } @Override public Resource[] listResources() { if(!attr().isDirectory())return null; String path; if(parent==null) path= "/"; else path=parent.concat(name).concat("/"); Attr[] children=null; try { children = provider.getAttrs(data,path.hashCode(),path); } catch (PageException e) { throw new PageRuntimeException(e); } if(children==null) return new Resource[0]; Resource[] attrs = new Resource[children.length]; for(int i=0;i<children.length;i++) { // TODO optimieren, alle attr mitgeben attrs[i]=new DatasourceResource(provider,data,path+children[i].getName()); } return attrs; } @Override public boolean setLastModified(long time) { if(!exists()) return false; return provider.setLastModified(data,fullPathHash(),parent,name,time); } @Override public void setMode(int mode) throws IOException { if(!exists())throw new IOException("can't set mode on resource ["+this+"], resource does not exist"); provider.setMode(data,fullPathHash(),parent,name,mode); } @Override public void moveTo(Resource dest) throws IOException { super.moveTo(dest);// TODO } @Override public boolean setReadable(boolean readable) { if(!exists())return false; try { setMode(ModeUtil.setReadable(getMode(), readable)); return true; } catch (IOException e) { return false; } } @Override public boolean setWritable(boolean writable) { if(!exists())return false; try { setMode(ModeUtil.setWritable(getMode(), writable)); return true; } catch (IOException e) { return false; } } @Override public String toString() { return getPath(); } }