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