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 /** 073 * @see railo.commons.io.res.Resource#createDirectory(boolean) 074 */ 075 public void createDirectory(boolean createParentWhenNotExists) throws IOException { 076 ResourceUtil.checkCreateDirectoryOK(this,createParentWhenNotExists); 077 provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_DIRECTORY); 078 079 } 080 081 /** 082 * @see railo.commons.io.res.Resource#createFile(boolean) 083 */ 084 public void createFile(boolean createParentWhenNotExists) throws IOException { 085 ResourceUtil.checkCreateFileOK(this,createParentWhenNotExists); 086 provider.create(data,fullPathHash(),pathHash(),parent,name,Attr.TYPE_FILE); 087 } 088 089 /** 090 * @see railo.commons.io.res.Resource#remove(boolean) 091 */ 092 public void remove(boolean force) throws IOException { 093 ResourceUtil.checkRemoveOK(this); 094 if(isRoot()) 095 throw new IOException("can't remove root resource ["+getPath()+"]"); 096 097 098 Resource[] children = listResources(); 099 if(children!=null && children.length>0) { 100 if(!force) { 101 throw new IOException("can't delete directory ["+getPath()+"], directory is not empty"); 102 } 103 for(int i=0;i<children.length;i++) { 104 children[i].remove(true); 105 } 106 } 107 provider.delete(data,fullPathHash(),parent,name); 108 } 109 110 /** 111 * @see railo.commons.io.res.Resource#exists() 112 */ 113 public boolean exists() { 114 return attr().exists(); 115 } 116 117 /** 118 * @see railo.commons.io.res.Resource#getInputStream() 119 */ 120 public InputStream getInputStream() throws IOException { 121 ResourceUtil.checkGetInputStreamOK(this); 122 return provider.getInputStream(data,fullPathHash(),parent,name); 123 } 124 125 /** 126 * @see railo.commons.io.res.Resource#getMode() 127 */ 128 public int getMode() { 129 return attr().getMode(); 130 } 131 132 /** 133 * @see res.Resource#getFullName() 134 */ 135 public String getName() { 136 return name; 137 } 138 139 /** 140 * @see railo.commons.io.res.Resource#getOutputStream(boolean) 141 */ 142 public OutputStream getOutputStream(boolean append) throws IOException { 143 ResourceUtil.checkGetOutputStreamOK(this); 144 byte[] barr=null; 145 146 if(append && !provider.concatSupported(data) && isFile()){ 147 try{ 148 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 149 IOUtil.copy(getInputStream(), baos,true,true); 150 barr = baos.toByteArray(); 151 } 152 catch(Throwable t){ 153 154 } 155 } 156 157 OutputStream os = provider.getOutputStream(data,fullPathHash(),pathHash(),parent,name,append); 158 if(!ArrayUtil.isEmpty(barr))IOUtil.copy(new ByteArrayInputStream(barr), os,true,false); 159 return os; 160 } 161 162 /** 163 * @see railo.commons.io.res.Resource#getParent() 164 */ 165 public String getParent() { 166 if(isRoot()) return null; 167 String p = (StringUtil.isEmpty(parent))?"/":parent; 168 return provider.getScheme().concat("://").concat(data.key()).concat(ResourceUtil.translatePath(p, true, false)); 169 170 } 171 172 /** 173 * @see railo.commons.io.res.Resource#getParentResource() 174 */ 175 public Resource getParentResource() { 176 return getParentDatasourceResource(); 177 } 178 private DatasourceResource getParentDatasourceResource() { 179 if(isRoot()) return null; 180 return new DatasourceResource(provider,data,parent); 181 } 182 183 /** 184 * @see res.Resource#getPath() 185 */ 186 public String getPath() { 187 return provider.getScheme().concat("://").concat(data.key()).concat(getInnerPath()); 188 } 189 private String getInnerPath() { 190 if(parent==null) return "/"; 191 return parent.concat(name); 192 } 193 194 /** 195 * @see railo.commons.io.res.Resource#getRealResource(java.lang.String) 196 */ 197 public Resource getRealResource(String realpath) { 198 realpath=ResourceUtil.merge(getInnerPath(), realpath); 199 if(realpath.startsWith("../"))return null; 200 201 return new DatasourceResource(provider,data,realpath); 202 } 203 204 /** 205 * @see railo.commons.io.res.Resource#getResourceProvider() 206 */ 207 public ResourceProvider getResourceProvider() { 208 return provider; 209 } 210 211 /** 212 * @see railo.commons.io.res.Resource#isAbsolute() 213 */ 214 public boolean isAbsolute() { 215 return true; 216 } 217 218 /** 219 * @see railo.commons.io.res.Resource#isDirectory() 220 */ 221 public boolean isDirectory() { 222 return attr().isDirectory(); 223 } 224 225 /** 226 * @see railo.commons.io.res.Resource#isFile() 227 */ 228 public boolean isFile() { 229 return attr().isFile(); 230 } 231 232 /** 233 * @see railo.commons.io.res.Resource#isReadable() 234 */ 235 public boolean isReadable() { 236 return ModeUtil.isReadable(getMode()); 237 } 238 239 /** 240 * @see railo.commons.io.res.Resource#isWriteable() 241 */ 242 public boolean isWriteable() { 243 return ModeUtil.isWritable(getMode()); 244 } 245 246 /** 247 * @see railo.commons.io.res.Resource#lastModified() 248 */ 249 public long lastModified() { 250 return attr().getLastModified(); 251 } 252 253 /** 254 * @see railo.commons.io.res.Resource#length() 255 */ 256 public long length() { 257 return attr().size(); 258 } 259 260 /** 261 * @see railo.commons.io.res.Resource#listResources() 262 */ 263 public Resource[] listResources() { 264 if(!attr().isDirectory())return null; 265 266 String path; 267 if(parent==null) path= "/"; 268 else path=parent.concat(name).concat("/"); 269 270 271 Attr[] children=null; 272 try { 273 children = provider.getAttrs(data,path.hashCode(),path); 274 } catch (PageException e) { 275 throw new PageRuntimeException(e); 276 } 277 if(children==null) return new Resource[0]; 278 Resource[] attrs = new Resource[children.length]; 279 for(int i=0;i<children.length;i++) { 280 // TODO optimieren, alle attr mitgeben 281 attrs[i]=new DatasourceResource(provider,data,path+children[i].getName()); 282 } 283 return attrs; 284 } 285 286 /** 287 * @see railo.commons.io.res.Resource#setLastModified(long) 288 */ 289 public boolean setLastModified(long time) { 290 if(!exists()) return false; 291 return provider.setLastModified(data,fullPathHash(),parent,name,time); 292 } 293 294 /** 295 * @see railo.commons.io.res.Resource#setMode(int) 296 */ 297 public void setMode(int mode) throws IOException { 298 if(!exists())throw new IOException("can't set mode on resource ["+this+"], resource does not exists"); 299 provider.setMode(data,fullPathHash(),parent,name,mode); 300 } 301 302 303 /** 304 * @see railo.commons.io.res.util.ResourceSupport#moveTo(railo.commons.io.res.Resource) 305 */ 306 public void moveTo(Resource dest) throws IOException { 307 super.moveTo(dest);// TODO 308 } 309 310 311 /** 312 * @see railo.commons.io.res.Resource#setReadable(boolean) 313 */ 314 public boolean setReadable(boolean readable) { 315 if(!exists())return false; 316 try { 317 setMode(ModeUtil.setReadable(getMode(), readable)); 318 return true; 319 } catch (IOException e) { 320 return false; 321 } 322 } 323 324 /** 325 * @see railo.commons.io.res.Resource#setWritable(boolean) 326 */ 327 public boolean setWritable(boolean writable) { 328 if(!exists())return false; 329 try { 330 setMode(ModeUtil.setWritable(getMode(), writable)); 331 return true; 332 } catch (IOException e) { 333 return false; 334 } 335 } 336 337 /** 338 * @see java.lang.Object#toString() 339 */ 340 public String toString() { 341 return getPath(); 342 } 343 344 }