001 package railo.runtime.type.util; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.IOException; 005 import java.lang.reflect.Field; 006 import java.util.ArrayList; 007 import java.util.Arrays; 008 009 import org.apache.axis.AxisFault; 010 import org.objectweb.asm.ClassWriter; 011 import org.objectweb.asm.Label; 012 import org.objectweb.asm.Opcodes; 013 import org.objectweb.asm.Type; 014 import org.objectweb.asm.commons.GeneratorAdapter; 015 import org.objectweb.asm.commons.Method; 016 017 import railo.commons.digest.MD5; 018 import railo.commons.io.IOUtil; 019 import railo.commons.io.res.Resource; 020 import railo.commons.io.res.util.ResourceUtil; 021 import railo.commons.lang.ClassUtil; 022 import railo.commons.lang.PhysicalClassLoader; 023 import railo.commons.lang.StringUtil; 024 import railo.commons.lang.types.RefBoolean; 025 import railo.runtime.Component; 026 import railo.runtime.ComponentPro; 027 import railo.runtime.ComponentWrap; 028 import railo.runtime.Mapping; 029 import railo.runtime.Page; 030 import railo.runtime.PageContext; 031 import railo.runtime.PageContextImpl; 032 import railo.runtime.PageSource; 033 import railo.runtime.PageSourceImpl; 034 import railo.runtime.component.Property; 035 import railo.runtime.config.Config; 036 import railo.runtime.engine.ThreadLocalPageContext; 037 import railo.runtime.exp.ExpressionException; 038 import railo.runtime.exp.PageException; 039 import railo.runtime.net.rpc.AxisCaster; 040 import railo.runtime.net.rpc.Pojo; 041 import railo.runtime.net.rpc.server.ComponentController; 042 import railo.runtime.net.rpc.server.RPCServer; 043 import railo.runtime.op.Caster; 044 import railo.runtime.type.Array; 045 import railo.runtime.type.ArrayImpl; 046 import railo.runtime.type.Collection; 047 import railo.runtime.type.Collection.Key; 048 import railo.runtime.type.FunctionArgument; 049 import railo.runtime.type.KeyImpl; 050 import railo.runtime.type.Struct; 051 import railo.runtime.type.StructImpl; 052 import railo.runtime.type.UDF; 053 import railo.runtime.type.UDFPropertiesImpl; 054 import railo.runtime.type.cfc.ComponentAccess; 055 import railo.transformer.bytecode.BytecodeContext; 056 import railo.transformer.bytecode.literal.LitString; 057 import railo.transformer.bytecode.util.ASMProperty; 058 import railo.transformer.bytecode.util.ASMUtil; 059 import railo.transformer.bytecode.util.Types; 060 import railo.transformer.bytecode.visitor.ArrayVisitor; 061 // TODO doc 062 public final class ComponentUtil { 063 064 065 private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()"); 066 private static final Type COMPONENT_CONTROLLER = Type.getType(ComponentController.class); 067 private static final Method INVOKE = new Method("invoke",Types.OBJECT,new Type[]{Types.STRING,Types.OBJECT_ARRAY}); 068 private static final Collection.Key FIELD_TYPE = KeyConstants._fieldtype; 069 070 //private static final Method INVOKE_PROPERTY = new Method("invoke",Types.OBJECT,new Type[]{Types.STRING,Types.OBJECT_ARRAY}); 071 072 /** 073 * generate a ComponentJavaAccess (CJA) class from a component 074 * a CJA is a dynamic genarted java class that has all method defined inside a component as java methods. 075 * 076 * This is used to generated server side Webservices. 077 * @param component 078 * @param isNew 079 * @return 080 * @throws PageException 081 */ 082 public static Class getComponentJavaAccess(PageContext pc,ComponentAccess component, RefBoolean isNew,boolean create,boolean writeLog, boolean supressWSbeforeArg) throws PageException { 083 isNew.setValue(false); 084 String classNameOriginal=component.getPageSource().getFullClassName(); 085 String className=getClassname(component).concat("_wrap"); 086 String real=className.replace('.','/'); 087 String realOriginal=classNameOriginal.replace('.','/'); 088 Mapping mapping = component.getPageSource().getMapping(); 089 PhysicalClassLoader cl=null; 090 try { 091 cl = (PhysicalClassLoader) ((PageContextImpl)pc).getRPCClassLoader(false); 092 } catch (IOException e) { 093 throw Caster.toPageException(e); 094 } 095 Resource classFile = cl.getDirectory().getRealResource(real.concat(".class")); 096 Resource classFileOriginal = mapping.getClassRootDirectory().getRealResource(realOriginal.concat(".class")); 097 098 // LOAD CLASS 099 //print.out(className); 100 // check last Mod 101 if(classFile.lastModified()>=classFileOriginal.lastModified()) { 102 try { 103 Class clazz=cl.loadClass(className); 104 if(clazz!=null && !hasChangesOfChildren(classFile.lastModified(),clazz))return registerTypeMapping(clazz); 105 } 106 catch(Throwable t){} 107 } 108 if(!create) return null; 109 isNew.setValue(true); 110 //print.out("new"); 111 // CREATE CLASS 112 ClassWriter cw = ASMUtil.getClassWriter(); 113 //ClassWriter cw = new ClassWriter(true); 114 cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, real, null, "java/lang/Object", null); 115 116 //GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC,Page.STATIC_CONSTRUCTOR,null,null,cw); 117 BytecodeContext statConstr = null;//new BytecodeContext(null,null,null,cw,real,ga,Page.STATIC_CONSTRUCTOR); 118 119 ///ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC,Page.CONSTRUCTOR,null,null,cw); 120 BytecodeContext constr = null;//new BytecodeContext(null,null,null,cw,real,ga,Page.CONSTRUCTOR); 121 122 123 // field component 124 //FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, "c", "Lrailo/runtime/ComponentImpl;", null, null); 125 //fv.visitEnd(); 126 127 java.util.List<LitString> _keys=new ArrayList<LitString>(); 128 129 // remote methods 130 Collection.Key[] keys = component.keys(Component.ACCESS_REMOTE); 131 int max; 132 for(int i=0;i<keys.length;i++){ 133 max=-1; 134 while((max=createMethod(statConstr,constr,_keys,cw,real,component.get(keys[i]),max, writeLog,supressWSbeforeArg))!=-1){ 135 break;// for overload remove this 136 } 137 } 138 139 // Constructor 140 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw); 141 adapter.loadThis(); 142 adapter.invokeConstructor(Types.OBJECT, CONSTRUCTOR_OBJECT); 143 railo.transformer.bytecode.Page.registerFields(new BytecodeContext(statConstr,constr,getPage(statConstr,constr),null,_keys,cw,real,adapter,CONSTRUCTOR_OBJECT,writeLog,supressWSbeforeArg), _keys); 144 adapter.returnValue(); 145 adapter.endMethod(); 146 147 148 cw.visitEnd(); 149 byte[] barr = cw.toByteArray(); 150 151 try { 152 ResourceUtil.touch(classFile); 153 IOUtil.copy(new ByteArrayInputStream(barr), classFile,true); 154 155 cl = (PhysicalClassLoader) ((PageContextImpl)pc).getRPCClassLoader(true); 156 157 return registerTypeMapping(cl.loadClass(className, barr)); 158 } 159 catch(Throwable t) { 160 throw Caster.toPageException(t); 161 } 162 } 163 164 private static railo.transformer.bytecode.Page getPage(BytecodeContext bc1, BytecodeContext bc2) { 165 railo.transformer.bytecode.Page page=null; 166 if(bc1!=null)page=bc1.getPage(); 167 if(page==null && bc2!=null)page=bc2.getPage(); 168 return page; 169 } 170 171 /** 172 * check if one of the children is changed 173 * @param component 174 * @param clazz 175 * @return return true if children has changed 176 */ 177 private static boolean hasChangesOfChildren(long last, Class clazz) { 178 179 boolean b= hasChangesOfChildren(last,ThreadLocalPageContext.get(),clazz); 180 return b; 181 } 182 183 /** 184 * check if one of the children is changed 185 * @param component 186 * @param pc 187 * @param clazz 188 * @return return true if children has changed 189 */ 190 private static boolean hasChangesOfChildren(long last,PageContext pc, Class clazz) { 191 192 java.lang.reflect.Method[] methods = clazz.getMethods(); 193 java.lang.reflect.Method method; 194 Class[] params; 195 for(int i=0;i<methods.length;i++){ 196 method=methods[i]; 197 if(method.getDeclaringClass()==clazz){ 198 if(_hasChangesOfChildren(pc, last,method.getReturnType())) return true; 199 params = method.getParameterTypes(); 200 for(int y=0;y<params.length;y++){ 201 if(_hasChangesOfChildren(pc, last, params[y])) return true; 202 } 203 } 204 } 205 return false; 206 } 207 208 private static boolean _hasChangesOfChildren(PageContext pc, long last, Class clazz) { 209 clazz=ClassUtil.toComponentType(clazz); 210 java.lang.reflect.Method m = getComplexTypeMethod(clazz); 211 if(m==null) return false; 212 try { 213 String path=Caster.toString(m.invoke(null, new Object[0])); 214 Resource res = ResourceUtil.toResourceExisting(pc, path); 215 if(last<res.lastModified()) { 216 return true; 217 } 218 } 219 catch (Exception e) { 220 return true; 221 } 222 // possible that a child of the Cmplex Object is also a complex object 223 return hasChangesOfChildren(last, pc, clazz); 224 } 225 226 private static boolean isComplexType(Class clazz) { 227 return getComplexTypeMethod(clazz)!=null; 228 229 } 230 private static java.lang.reflect.Method getComplexTypeMethod(Class clazz) { 231 try { 232 return clazz.getMethod("_srcName", new Class[0]); 233 } 234 catch (Exception e) { 235 return null; 236 } 237 } 238 239 /** 240 * search in methods of a class for complex types 241 * @param clazz 242 * @return 243 */ 244 private static Class registerTypeMapping(Class clazz) throws AxisFault { 245 PageContext pc = ThreadLocalPageContext.get(); 246 RPCServer server=RPCServer.getInstance(pc.getId(),pc.getServletContext()); 247 return registerTypeMapping(server, clazz); 248 } 249 /** 250 * search in methods of a class for complex types 251 * @param server 252 * @param clazz 253 * @return 254 */ 255 private static Class registerTypeMapping(RPCServer server, Class clazz) { 256 java.lang.reflect.Method[] methods = clazz.getMethods(); 257 java.lang.reflect.Method method; 258 Class[] params; 259 for(int i=0;i<methods.length;i++){ 260 method=methods[i]; 261 if(method.getDeclaringClass()==clazz){ 262 _registerTypeMapping(server, method.getReturnType()); 263 params = method.getParameterTypes(); 264 for(int y=0;y<params.length;y++){ 265 _registerTypeMapping(server, params[y]); 266 } 267 } 268 } 269 return clazz; 270 } 271 272 /** 273 * register ComplexType 274 * @param server 275 * @param clazz 276 */ 277 private static void _registerTypeMapping(RPCServer server, Class clazz) { 278 if(clazz==null) return; 279 280 if(!isComplexType(clazz)) { 281 if(clazz.isArray()) { 282 _registerTypeMapping(server, clazz.getComponentType()); 283 } 284 return; 285 } 286 server.registerTypeMapping(clazz); 287 registerTypeMapping(server,clazz); 288 } 289 290 public static String getClassname(Component component) { 291 PageSource ps = component.getPageSource(); 292 String path=ps.getDisplayPath();// Must remove webroot 293 Config config = ps.getMapping().getConfig(); 294 String root = config.getRootDirectory().getAbsolutePath(); 295 if(path.startsWith(root)) 296 path=path.substring(root.length()); 297 298 path=path.replace('\\', '/').toLowerCase(); 299 path=ListUtil.trim(path, "/"); 300 String[] arr = ListUtil.listToStringArray(path, '/'); 301 302 StringBuffer rtn=new StringBuffer(); 303 for(int i=0;i<arr.length;i++) { 304 if(i+1==arr.length) { 305 rtn.append(StringUtil.toVariableName(StringUtil.replaceLast(arr[i],".cfc",""))); 306 } 307 else { 308 rtn.append(StringUtil.toVariableName(arr[i])); 309 rtn.append('.'); 310 } 311 } 312 return rtn.toString(); 313 } 314 315 /* 316 * includes the application context javasettings 317 * @param pc 318 * @param className 319 * @param properties 320 * @return 321 * @throws PageException 322 */ 323 public static Object getClientComponentPropertiesObject(PageContext pc, String className, ASMProperty[] properties) throws PageException { 324 try { 325 return _getClientComponentPropertiesObject(pc,pc.getConfig(), className, properties); 326 } catch (Exception e) { 327 throw Caster.toPageException(e); 328 } 329 } 330 /* 331 * does not include the application context javasettings 332 * @param pc 333 * @param className 334 * @param properties 335 * @return 336 * @throws PageException 337 */ 338 public static Object getClientComponentPropertiesObject(Config config, String className, ASMProperty[] properties) throws PageException { 339 try { 340 return _getClientComponentPropertiesObject(null,config, className, properties); 341 } catch (Exception e) { 342 throw Caster.toPageException(e); 343 } 344 } 345 346 347 348 private static Object _getClientComponentPropertiesObject(PageContext pc, Config secondChanceConfig, String className, ASMProperty[] properties) throws PageException, IOException, ClassNotFoundException { 349 String real=className.replace('.','/'); 350 351 PhysicalClassLoader cl; 352 if(pc==null)cl = (PhysicalClassLoader)secondChanceConfig.getRPCClassLoader(false); 353 else cl = (PhysicalClassLoader)((PageContextImpl)pc).getRPCClassLoader(false); 354 355 Resource rootDir = cl.getDirectory(); 356 Resource classFile = rootDir.getRealResource(real.concat(".class")); 357 358 if(classFile.exists()) { 359 try { 360 Class clazz = cl.loadClass(className); 361 Field field = clazz.getField("_md5_"); 362 if(ASMUtil.createMD5(properties).equals(field.get(null))){ 363 //if(equalInterface(properties,clazz)) { 364 return ClassUtil.loadInstance(clazz); 365 } 366 } 367 catch(Exception e) { 368 369 } 370 } 371 // create file 372 byte[] barr = ASMUtil.createPojo(real, properties,Object.class,new Class[]{Pojo.class},null); 373 boolean exist=classFile.exists(); 374 ResourceUtil.touch(classFile); 375 IOUtil.copy(new ByteArrayInputStream(barr), classFile,true); 376 377 if(pc==null)cl = (PhysicalClassLoader)secondChanceConfig.getRPCClassLoader(exist); 378 else cl = (PhysicalClassLoader)((PageContextImpl)pc).getRPCClassLoader(exist); 379 380 return ClassUtil.loadInstance(cl.loadClass(className)); 381 382 } 383 384 385 386 public static Class getServerComponentPropertiesClass(PageContext pc,Component component) throws PageException { 387 try { 388 return _getServerComponentPropertiesClass(pc,component); 389 } 390 catch (Exception e) { 391 throw Caster.toPageException(e); 392 } 393 } 394 395 private static Class _getServerComponentPropertiesClass(PageContext pc,Component component) throws PageException, IOException, ClassNotFoundException { 396 String className=getClassname(component);//StringUtil.replaceLast(classNameOriginal,"$cfc",""); 397 String real=className.replace('.','/'); 398 399 Mapping mapping = component.getPageSource().getMapping(); 400 PhysicalClassLoader cl = (PhysicalClassLoader)((PageContextImpl)pc).getRPCClassLoader(false); 401 402 Resource classFile = cl.getDirectory().getRealResource(real.concat(".class")); 403 404 String classNameOriginal=component.getPageSource().getFullClassName(); 405 String realOriginal=classNameOriginal.replace('.','/'); 406 Resource classFileOriginal = mapping.getClassRootDirectory().getRealResource(realOriginal.concat(".class")); 407 408 // load existing class 409 if(classFile.lastModified()>=classFileOriginal.lastModified()) { 410 try { 411 Class clazz=cl.loadClass(className); 412 if(clazz!=null && !hasChangesOfChildren(classFile.lastModified(), clazz))return clazz;//ClassUtil.loadInstance(clazz); 413 } 414 catch(Throwable t){} 415 } 416 417 // create file 418 byte[] barr = ASMUtil.createPojo(real, ASMUtil.toASMProperties( 419 ComponentUtil.getProperties(component, false, true, false, false)),Object.class,new Class[]{Pojo.class},component.getPageSource().getDisplayPath()); 420 ResourceUtil.touch(classFile); 421 IOUtil.copy(new ByteArrayInputStream(barr), classFile,true); 422 cl = (PhysicalClassLoader)((PageContextImpl)pc).getRPCClassLoader(true); 423 return cl.loadClass(className); //ClassUtil.loadInstance(cl.loadClass(className)); 424 } 425 426 private static int createMethod(BytecodeContext statConstr,BytecodeContext constr, java.util.List<LitString> keys,ClassWriter cw,String className, Object member,int max,boolean writeLog, boolean supressWSbeforeArg) throws PageException { 427 428 boolean hasOptionalArgs=false; 429 430 if(member instanceof UDF) { 431 UDF udf = (UDF) member; 432 FunctionArgument[] args = udf.getFunctionArguments(); 433 Type[] types=new Type[max<0?args.length:max]; 434 for(int y=0;y<types.length;y++){ 435 types[y]=toType(args[y].getTypeAsString(),true);//Type.getType(Caster.cfTypeToClass(args[y].getTypeAsString())); 436 if(!args[y].isRequired())hasOptionalArgs=true; 437 } 438 Type rtnType=toType(udf.getReturnTypeAsString(),true); 439 Method method = new Method( 440 udf.getFunctionName(), 441 rtnType, 442 types 443 ); 444 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL , method, null, null, cw); 445 BytecodeContext bc = new BytecodeContext(statConstr,constr,getPage(statConstr,constr),null,keys,cw,className,adapter,method,writeLog,supressWSbeforeArg); 446 Label start=adapter.newLabel(); 447 adapter.visitLabel(start); 448 449 //ComponentController.invoke(name, args); 450 // name 451 adapter.push(udf.getFunctionName()); 452 453 // args 454 ArrayVisitor av=new ArrayVisitor(); 455 av.visitBegin(adapter,Types.OBJECT,types.length); 456 for(int y=0;y<types.length;y++){ 457 av.visitBeginItem(adapter, y); 458 adapter.loadArg(y); 459 av.visitEndItem(bc.getAdapter()); 460 } 461 av.visitEnd(); 462 adapter.invokeStatic(COMPONENT_CONTROLLER, INVOKE); 463 adapter.checkCast(rtnType); 464 465 //ASMConstants.NULL(adapter); 466 adapter.returnValue(); 467 Label end=adapter.newLabel(); 468 adapter.visitLabel(end); 469 470 for(int y=0;y<types.length;y++){ 471 adapter.visitLocalVariable(args[y].getName().getString(), types[y].getDescriptor(), null, start, end, y+1); 472 } 473 adapter.endMethod(); 474 475 if(hasOptionalArgs) { 476 if(max==-1)max=args.length-1; 477 else max--; 478 return max; 479 } 480 } 481 return -1; 482 } 483 484 485 486 private static Type toType(String cfType, boolean axistype) throws PageException { 487 Class clazz=Caster.cfTypeToClass(cfType); 488 if(axistype)clazz=AxisCaster.toAxisTypeClass(clazz); 489 return Type.getType(clazz); 490 491 } 492 493 494 495 public static String md5(Component c) throws IOException, ExpressionException { 496 ComponentWrap cw = ComponentWrap.toComponentWrap(Component.ACCESS_PRIVATE,c); 497 Key[] keys = cw.keys(); 498 Arrays.sort(keys); 499 500 StringBuffer _interface=new StringBuffer(); 501 502 Object member; 503 UDF udf; 504 FunctionArgument[] args; 505 FunctionArgument arg; 506 for(int y=0;y<keys.length;y++) { 507 member = cw.get(keys[y],null); 508 if(member instanceof UDF) { 509 udf=(UDF) member; 510 //print.out(udf.); 511 _interface.append(udf.getAccess()); 512 _interface.append(udf.getOutput()); 513 _interface.append(udf.getFunctionName()); 514 _interface.append(udf.getReturnTypeAsString()); 515 args = udf.getFunctionArguments(); 516 for(int i=0;i<args.length;i++){ 517 arg=args[i]; 518 _interface.append(arg.isRequired()); 519 _interface.append(arg.getName()); 520 _interface.append(arg.getTypeAsString()); 521 } 522 } 523 } 524 return MD5.getDigestAsString(_interface.toString().toLowerCase()); 525 } 526 527 528 /** 529 * cast a strong access definition to the int type 530 * @param access access type 531 * @return int access type 532 * @throws ExpressionException 533 */ 534 public static int toIntAccess(String access) throws ExpressionException { 535 access=StringUtil.toLowerCase(access.trim()); 536 if(access.equals("package"))return Component.ACCESS_PACKAGE; 537 else if(access.equals("private"))return Component.ACCESS_PRIVATE; 538 else if(access.equals("public"))return Component.ACCESS_PUBLIC; 539 else if(access.equals("remote"))return Component.ACCESS_REMOTE; 540 throw new ExpressionException("invalid access type ["+access+"], access types are remote, public, package, private"); 541 542 } 543 544 public static int toIntAccess(String access, int defaultValue) { 545 access=StringUtil.toLowerCase(access.trim()); 546 if(access.equals("package"))return Component.ACCESS_PACKAGE; 547 else if(access.equals("private"))return Component.ACCESS_PRIVATE; 548 else if(access.equals("public"))return Component.ACCESS_PUBLIC; 549 else if(access.equals("remote"))return Component.ACCESS_REMOTE; 550 return defaultValue; 551 } 552 553 /** 554 * cast int type to string type 555 * @param access 556 * @return String access type 557 * @throws ExpressionException 558 */ 559 public static String toStringAccess(int access) throws ExpressionException { 560 String res = toStringAccess(access,null); 561 if(res!=null) return res; 562 throw new ExpressionException("invalid access type ["+access+"], access types are Component.ACCESS_PACKAGE, Component.ACCESS_PRIVATE, Component.ACCESS_PUBLIC, Component.ACCESS_REMOTE"); 563 } 564 565 public static String toStringAccess(int access,String defaultValue) { 566 switch(access) { 567 case Component.ACCESS_PACKAGE: return "package"; 568 case Component.ACCESS_PRIVATE: return "private"; 569 case Component.ACCESS_PUBLIC: return "public"; 570 case Component.ACCESS_REMOTE: return "remote"; 571 } 572 return defaultValue; 573 } 574 575 public static ExpressionException notFunction(Component c,Collection.Key key, Object member,int access) { 576 if(member==null) { 577 String strAccess = toStringAccess(access,""); 578 579 Collection.Key[] other; 580 if(c instanceof ComponentAccess) 581 other=((ComponentAccess)c).keys(access); 582 else 583 other=CollectionUtil.keys(c); 584 585 if(other.length==0) 586 return new ExpressionException( 587 "component ["+c.getCallName()+"] has no "+strAccess+" function with name ["+key+"]"); 588 589 return new ExpressionException( 590 "component ["+c.getCallName()+"] has no "+strAccess+" function with name ["+key+"]", 591 "accessible functions are ["+ListUtil.arrayToList(other,",")+"]"); 592 } 593 return new ExpressionException("member ["+key+"] of component ["+c.getCallName()+"] is not a function", "Member is of type ["+Caster.toTypeName(member)+"]"); 594 } 595 596 public static Property[] getProperties(Component c,boolean onlyPeristent, boolean includeBaseProperties, boolean preferBaseProperties, boolean inheritedMappedSuperClassOnly) { 597 if(c instanceof ComponentPro) 598 return ((ComponentPro)c).getProperties(onlyPeristent, includeBaseProperties,preferBaseProperties,preferBaseProperties); 599 return c.getProperties(onlyPeristent); 600 } 601 602 public static Property[] getIDProperties(Component c,boolean onlyPeristent, boolean includeBaseProperties) { 603 Property[] props = getProperties(c,onlyPeristent,includeBaseProperties,false,false); 604 java.util.List<Property> tmp=new ArrayList<Property>(); 605 for(int i=0;i<props.length;i++){ 606 if("id".equalsIgnoreCase(Caster.toString(props[i].getDynamicAttributes().get(FIELD_TYPE,null),""))) 607 tmp.add(props[i]); 608 } 609 return tmp.toArray(new Property[tmp.size()]); 610 } 611 612 public static ComponentAccess toComponentAccess(Component comp) throws ExpressionException { 613 ComponentAccess ca = toComponentAccess(comp, null); 614 if(ca!=null) return ca; 615 throw new ExpressionException("can't cast class ["+Caster.toClassName(comp)+"] to a class of type ComponentAccess"); 616 } 617 618 public static ComponentAccess toComponentAccess(Component comp, ComponentAccess defaultValue) { 619 if(comp instanceof ComponentAccess) return (ComponentAccess) comp; 620 if(comp instanceof ComponentWrap) return ((ComponentWrap) comp).getComponentAccess(); 621 return defaultValue; 622 } 623 624 625 626 public static Component toComponent(Object obj) throws ExpressionException { 627 if(obj instanceof Component) return (Component) obj; 628 throw new ExpressionException("can't cast class ["+Caster.toClassName(obj)+"] to a class of type Component"); 629 } 630 631 632 633 public static PageSource getPageSource(Component cfc) { 634 // TODO Auto-generated method stub 635 try { 636 return toComponent(cfc).getPageSource(); 637 } catch (ExpressionException e) { 638 return null; 639 } 640 } 641 642 public static ComponentAccess getActiveComponent(PageContext pc, ComponentAccess current) { 643 if(pc.getActiveComponent()==null) return current; 644 if(pc.getActiveUDF()!=null && (pc.getActiveComponent()).getPageSource()==(pc.getActiveUDF().getOwnerComponent()).getPageSource()){ 645 646 return (ComponentAccess) pc.getActiveUDF().getOwnerComponent(); 647 } 648 return (ComponentAccess) pc.getActiveComponent();//+++ 649 650 651 } 652 653 public static long getCompileTime(PageContext pc, PageSource ps,long defaultValue) { 654 try { 655 return getCompileTime(pc, ps); 656 } catch (Throwable t) { 657 return defaultValue; 658 } 659 } 660 661 public static long getCompileTime(PageContext pc, PageSource ps) throws PageException { 662 return getPage(pc,ps).getCompileTime(); 663 } 664 665 public static Page getPage(PageContext pc, PageSource ps) throws PageException { 666 PageSourceImpl psi = (PageSourceImpl)ps; 667 668 Page p = psi.getPage(); 669 if(p!=null){ 670 //print.o("getPage(existing):"+ps.getDisplayPath()+":"+psi.hashCode()+":"+p.hashCode()); 671 return p; 672 } 673 pc=ThreadLocalPageContext.get(pc); 674 return psi.loadPage(pc); 675 } 676 677 public static Struct getPropertiesAsStruct(ComponentAccess ca, boolean onlyPersistent) { 678 Property[] props = ca.getProperties(onlyPersistent); 679 Struct sct=new StructImpl(); 680 if(props!=null)for(int i=0;i<props.length;i++){ 681 sct.setEL(KeyImpl.getInstance(props[i].getName()), props[i]); 682 } 683 return sct; 684 } 685 public static Struct getMetaData(PageContext pc,UDFPropertiesImpl udf) throws PageException { 686 StructImpl func=new StructImpl(); 687 pc=ThreadLocalPageContext.get(pc); 688 // TODO func.set("roles", value); 689 // TODO func.set("userMetadata", value); neo unterst゚tzt irgendwelche a 690 // meta data 691 Struct meta = udf.meta; 692 if(meta!=null) StructUtil.copy(meta, func, true); 693 694 func.setEL(KeyConstants._closure, Boolean.FALSE); 695 696 func.set(KeyConstants._access,ComponentUtil.toStringAccess(udf.getAccess())); 697 String hint=udf.hint; 698 if(!StringUtil.isEmpty(hint))func.set(KeyConstants._hint,hint); 699 String displayname=udf.displayName; 700 if(!StringUtil.isEmpty(displayname))func.set(KeyConstants._displayname,displayname); 701 func.set(KeyConstants._name,udf.functionName); 702 func.set(KeyConstants._output,Caster.toBoolean(udf.output)); 703 func.set(KeyConstants._returntype, udf.strReturnType); 704 func.set(KeyConstants._description, udf.description); 705 706 func.set(KeyConstants._owner, udf.pageSource.getDisplayPath()); 707 708 709 int format = udf.returnFormat; 710 if(format==UDF.RETURN_FORMAT_WDDX) func.set(KeyConstants._returnFormat, "wddx"); 711 else if(format==UDF.RETURN_FORMAT_PLAIN) func.set(KeyConstants._returnFormat, "plain"); 712 else if(format==UDF.RETURN_FORMAT_JSON) func.set(KeyConstants._returnFormat, "json"); 713 else if(format==UDF.RETURN_FORMAT_SERIALIZE)func.set(KeyConstants._returnFormat, "cfml"); 714 715 716 FunctionArgument[] args = udf.arguments; 717 Array params=new ArrayImpl(); 718 //Object defaultValue; 719 Struct m; 720 //Object defaultValue; 721 for(int y=0;y<args.length;y++) { 722 StructImpl param=new StructImpl(); 723 param.set(KeyConstants._name,args[y].getName().getString()); 724 param.set(KeyConstants._required,Caster.toBoolean(args[y].isRequired())); 725 param.set(KeyConstants._type,args[y].getTypeAsString()); 726 displayname=args[y].getDisplayName(); 727 if(!StringUtil.isEmpty(displayname)) param.set(KeyConstants._displayname,displayname); 728 729 int defType = args[y].getDefaultType(); 730 if(defType==FunctionArgument.DEFAULT_TYPE_RUNTIME_EXPRESSION){ 731 param.set(KeyConstants._default, "[runtime expression]"); 732 } 733 else if(defType==FunctionArgument.DEFAULT_TYPE_LITERAL){ 734 param.set(KeyConstants._default, 735 UDFUtil.getDefaultValue(pc, udf.pageSource, udf.index, y, null)); 736 } 737 738 hint=args[y].getHint(); 739 if(!StringUtil.isEmpty(hint))param.set(KeyConstants._hint,hint); 740 // TODO func.set("userMetadata", value); neo unterst゚tzt irgendwelche attr, die dann hier ausgebenen werden blレdsinn 741 742 // meta data 743 m=args[y].getMetaData(); 744 if(m!=null) StructUtil.copy(m, param, true); 745 746 params.append(param); 747 } 748 func.set(KeyConstants._parameters,params); 749 return func; 750 } 751 752 753 }