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 }