001 package railo.transformer.bytecode.statement; 002 003 import java.util.ArrayList; 004 import java.util.HashMap; 005 import java.util.List; 006 import java.util.Map; 007 008 import org.objectweb.asm.ClassWriter; 009 import org.objectweb.asm.Opcodes; 010 import org.objectweb.asm.Type; 011 import org.objectweb.asm.commons.GeneratorAdapter; 012 import org.objectweb.asm.commons.Method; 013 014 import railo.commons.lang.CFTypes; 015 import railo.commons.lang.StringUtil; 016 import railo.runtime.Component; 017 import railo.runtime.exp.TemplateException; 018 import railo.runtime.type.FunctionArgument; 019 import railo.runtime.type.FunctionArgumentImpl; 020 import railo.runtime.type.FunctionArgumentLight; 021 import railo.runtime.type.util.ComponentUtil; 022 import railo.transformer.bytecode.Body; 023 import railo.transformer.bytecode.BytecodeContext; 024 import railo.transformer.bytecode.BytecodeException; 025 import railo.transformer.bytecode.Page; 026 import railo.transformer.bytecode.cast.CastBoolean; 027 import railo.transformer.bytecode.cast.CastString; 028 import railo.transformer.bytecode.expression.ExprBoolean; 029 import railo.transformer.bytecode.expression.ExprString; 030 import railo.transformer.bytecode.expression.Expression; 031 import railo.transformer.bytecode.expression.var.Variable; 032 import railo.transformer.bytecode.literal.LitBoolean; 033 import railo.transformer.bytecode.literal.LitInteger; 034 import railo.transformer.bytecode.literal.LitString; 035 import railo.transformer.bytecode.statement.tag.Attribute; 036 import railo.transformer.bytecode.util.ASMConstants; 037 import railo.transformer.bytecode.util.ASMUtil; 038 import railo.transformer.bytecode.util.ExpressionUtil; 039 import railo.transformer.bytecode.util.Types; 040 041 public final class Function extends StatementBase implements Opcodes, IFunction,HasBody { 042 043 044 045 // Scope variablesScope() 046 private static final Method VARIABLE_SCOPE = new Method( 047 "variablesScope", 048 Types.VARIABLES, 049 new Type[]{} 050 ); 051 052 053 // Object set(String,Object) 054 private static final Method SET_STR = new Method( 055 "set", 056 Types.OBJECT, 057 new Type[]{Types.STRING,Types.OBJECT} 058 ); 059 060 private static final Method SET_KEY = new Method( 061 "set", 062 Types.OBJECT, 063 new Type[]{Types.COLLECTION_KEY,Types.OBJECT} 064 ); 065 066 private static final Method REG_UDF_STR = new Method( 067 "registerUDF", 068 Types.VOID, 069 new Type[]{Types.STRING,Types.UDF_PROPERTIES} 070 ); 071 072 073 private static final Method REG_UDF_KEY = new Method( 074 "registerUDF", 075 Types.VOID, 076 new Type[]{Types.COLLECTION_KEY,Types.UDF_PROPERTIES} 077 ); 078 079 080 081 private static final ExprString ANY = LitString.toExprString("any"); 082 //private static final ExprString PUBLIC = LitString.toExprString("public"); 083 //private static final ExprString EMPTY = LitString.toExprString(""); 084 085 086 private static final Type UDF_PROPERTIES = Type.getType(railo.runtime.type.UDFProperties.class); 087 088 // <init>(Page,FunctionArgument[],int String,String,boolean); 089 private static final Type FUNCTION_ARGUMENT = Type.getType(FunctionArgument.class); 090 private static final Type FUNCTION_ARGUMENT_IMPL = Type.getType(FunctionArgumentImpl.class); 091 private static final Type FUNCTION_ARGUMENT_LIGHT = Type.getType(FunctionArgumentLight.class); 092 private static final Type FUNCTION_ARGUMENT_ARRAY = Type.getType(FunctionArgument[].class); 093 094 private static final Method INIT_UDF_IMPL_PROP = new Method( 095 "<init>", 096 Types.VOID, 097 new Type[]{ 098 Types.UDF_PROPERTIES 099 } 100 ); 101 102 103 private static final Method INIT_UDF_PROPERTIES_STRTYPE = new Method( 104 "<init>", 105 Types.VOID, 106 new Type[]{ 107 Types.PAGE_SOURCE, 108 FUNCTION_ARGUMENT_ARRAY, 109 Types.INT_VALUE, 110 Types.STRING, 111 Types.STRING, 112 Types.STRING, 113 Types.BOOLEAN_VALUE, 114 Types.BOOLEAN_VALUE, 115 Types.INT_VALUE, 116 Types.STRING, 117 Types.STRING, 118 Types.STRING, 119 Types.BOOLEAN, 120 Types.BOOLEAN, 121 Page.STRUCT_IMPL 122 } 123 ); 124 private static final Method INIT_UDF_PROPERTIES_SHORTTYPE = new Method( 125 "<init>", 126 Types.VOID, 127 new Type[]{ 128 Types.PAGE_SOURCE, 129 FUNCTION_ARGUMENT_ARRAY, 130 Types.INT_VALUE, 131 Types.STRING, 132 Types.SHORT_VALUE, 133 Types.STRING, 134 Types.BOOLEAN_VALUE, 135 Types.BOOLEAN_VALUE, 136 Types.INT_VALUE, 137 Types.STRING, 138 Types.STRING, 139 Types.STRING, 140 Types.BOOLEAN, 141 Types.BOOLEAN, 142 Page.STRUCT_IMPL 143 } 144 ); 145 146 147 // FunctionArgumentImpl(String name,String type,boolean required,int defaultType,String dspName,String hint,StructImpl meta) 148 private static final Method INIT_FAI_STRING = new Method( 149 "<init>", 150 Types.VOID, 151 new Type[]{Types.STRING, Types.STRING,Types.SHORT_VALUE,Types.BOOLEAN_VALUE,Types.INT_VALUE,Types.BOOLEAN_VALUE,Types.STRING,Types.STRING,Page.STRUCT_IMPL} 152 ); 153 private static final Method INIT_FAI_KEY1 = new Method( 154 "<init>", 155 Types.VOID, 156 new Type[]{ 157 Types.COLLECTION_KEY} 158 ); 159 private static final Method INIT_FAI_KEY3 = new Method( 160 "<init>", 161 Types.VOID, 162 new Type[]{ 163 Types.COLLECTION_KEY, 164 Types.STRING, 165 Types.SHORT_VALUE} 166 ); 167 private static final Method INIT_FAI_KEY4 = new Method( 168 "<init>", 169 Types.VOID, 170 new Type[]{ 171 Types.COLLECTION_KEY, 172 Types.STRING, 173 Types.SHORT_VALUE, 174 Types.BOOLEAN_VALUE} 175 ); 176 private static final Method INIT_FAI_KEY5 = new Method( 177 "<init>", 178 Types.VOID, 179 new Type[]{ 180 Types.COLLECTION_KEY, 181 Types.STRING, 182 Types.SHORT_VALUE, 183 Types.BOOLEAN_VALUE, 184 Types.INT_VALUE} 185 ); 186 private static final Method INIT_FAI_KEY6 = new Method( 187 "<init>", 188 Types.VOID, 189 new Type[]{ 190 Types.COLLECTION_KEY, 191 Types.STRING, 192 Types.SHORT_VALUE, 193 Types.BOOLEAN_VALUE, 194 Types.INT_VALUE, 195 Types.BOOLEAN_VALUE} 196 ); 197 private static final Method INIT_FAI_KEY7 = new Method( 198 "<init>", 199 Types.VOID, 200 new Type[]{ 201 Types.COLLECTION_KEY, 202 Types.STRING, 203 Types.SHORT_VALUE, 204 Types.BOOLEAN_VALUE, 205 Types.INT_VALUE, 206 Types.BOOLEAN_VALUE, 207 Types.STRING} 208 ); 209 private static final Method INIT_FAI_KEY8 = new Method( 210 "<init>", 211 Types.VOID, 212 new Type[]{ 213 Types.COLLECTION_KEY, 214 Types.STRING, 215 Types.SHORT_VALUE, 216 Types.BOOLEAN_VALUE, 217 Types.INT_VALUE, 218 Types.BOOLEAN_VALUE, 219 Types.STRING, 220 Types.STRING} 221 ); 222 private static final Method INIT_FAI_KEY9 = new Method( 223 "<init>", 224 Types.VOID, 225 new Type[]{ 226 Types.COLLECTION_KEY, 227 Types.STRING, 228 Types.SHORT_VALUE, 229 Types.BOOLEAN_VALUE, 230 Types.INT_VALUE, 231 Types.BOOLEAN_VALUE, 232 Types.STRING, 233 Types.STRING, 234 Page.STRUCT_IMPL} 235 ); 236 private static final Method[] INIT_FAI_KEY=new Method[]{ 237 INIT_FAI_KEY1,INIT_FAI_KEY3,INIT_FAI_KEY4,INIT_FAI_KEY5,INIT_FAI_KEY6,INIT_FAI_KEY7,INIT_FAI_KEY8,INIT_FAI_KEY9 238 }; 239 private static final Method[] INIT_FAI_KEY_LIGHT=new Method[]{ 240 INIT_FAI_KEY1,INIT_FAI_KEY3 241 }; 242 243 244 private ExprString name; 245 private ExprString returnType=ANY; 246 private ExprBoolean output=LitBoolean.TRUE; 247 private ExprBoolean abstr=LitBoolean.FALSE; 248 private int access=Component.ACCESS_PUBLIC; 249 private ExprString displayName=LitString.EMPTY; 250 private ExprString hint=LitString.EMPTY; 251 private Body body; 252 private List<Argument> arguments=new ArrayList<Argument>(); 253 private Map<String,Attribute> metadata; 254 private ExprString returnFormat; 255 private ExprString description; 256 private ExprBoolean secureJson; 257 private ExprBoolean verifyClient; 258 259 public Function(String name,int access,String returnType,Body body,int startline,int endline) { 260 super(startline,endline); 261 this.name=LitString.toExprString(name, -1); 262 this.access=access; 263 if(!StringUtil.isEmpty(returnType))this.returnType=LitString.toExprString(returnType); 264 265 this.body=body; 266 body.setParent(this); 267 268 269 } 270 271 public Function(Expression name,Expression returnType,Expression returnFormat,Expression output,Expression abstr, 272 int access,Expression displayName,Expression description,Expression hint,Expression secureJson, 273 Expression verifyClient,Body body,int startline,int endline) { 274 super(startline,endline); 275 this.name=CastString.toExprString(name); 276 this.returnType=CastString.toExprString(returnType); 277 this.returnFormat=returnFormat!=null?CastString.toExprString(returnFormat):null; 278 this.output=CastBoolean.toExprBoolean(output); 279 this.abstr=CastBoolean.toExprBoolean(abstr); 280 this.access=access; 281 this.description=description!=null?CastString.toExprString(description):null; 282 this.displayName=CastString.toExprString(displayName); 283 this.hint=CastString.toExprString(hint); 284 this.secureJson=secureJson!=null?CastBoolean.toExprBoolean(secureJson):null; 285 this.verifyClient=verifyClient!=null?CastBoolean.toExprBoolean(verifyClient):null; 286 //checkNameConflict(this.name); 287 288 289 this.body=body; 290 body.setParent(this); 291 292 } 293 294 295 /*private static void checkNameConflict(ExprString expr) { 296 if(expr instanceof LitString){ 297 String name=((LitString)expr).getString(); 298 if() 299 } 300 }*/ 301 302 /** 303 * @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int) 304 */ 305 public void writeOut(BytecodeContext bc, int type) throws BytecodeException { 306 ExpressionUtil.visitLine(bc, getStartLine()); 307 _writeOut(bc,type); 308 ExpressionUtil.visitLine(bc, getEndLine()); 309 } 310 311 /** 312 * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(railo.transformer.bytecode.BytecodeContext) 313 */ 314 public void _writeOut(BytecodeContext bc) throws BytecodeException { 315 _writeOut(bc,PAGE_TYPE_REGULAR); 316 } 317 318 public void _writeOut(BytecodeContext bc, int pageType) throws BytecodeException { 319 320 GeneratorAdapter adapter = bc.getAdapter(); 321 Page page = ASMUtil.getAncestorPage(this); 322 int index=page.addFunction(this); 323 324 // c.set(<name>,udf); 325 if(pageType==PAGE_TYPE_INTERFACE) { 326 adapter.loadArg(0); 327 } 328 else if(pageType==PAGE_TYPE_COMPONENT) { 329 adapter.loadArg(1); 330 } 331 // pc.variablesScope().set(<name>,udf); 332 else { 333 adapter.loadArg(0); 334 adapter.invokeVirtual(Types.PAGE_CONTEXT, VARIABLE_SCOPE); 335 } 336 boolean hasKey = Variable.registerKey(bc,name,true); 337 //name.writeOut(bc, Expression.MODE_REF); 338 339 // CHANGES 340 //loadUDF(bc,index); 341 //loadUDFProperties(bc,index); 342 //createUDF(bc,index); 343 344 if(pageType==PAGE_TYPE_COMPONENT) { 345 loadUDF(bc,index,true); 346 adapter.invokeVirtual(Types.COMPONENT_IMPL, hasKey?REG_UDF_KEY:REG_UDF_STR); 347 } 348 else if(pageType==PAGE_TYPE_INTERFACE) { 349 loadUDF(bc,index,true); 350 adapter.invokeVirtual(Types.INTERFACE_IMPL, hasKey?REG_UDF_KEY:REG_UDF_STR); 351 } 352 else { 353 loadUDF(bc, index); 354 adapter.invokeInterface(Types.VARIABLES, hasKey?SET_KEY:SET_STR); 355 adapter.pop(); 356 } 357 } 358 359 public void loadUDF(BytecodeContext bc, int index, boolean onlyProps) throws BytecodeException { 360 BytecodeContext constr = bc.getConstructor(); 361 ClassWriter cw = bc.getClassWriter(); 362 //String type = Type.getType(UDFProperties.class).toString(); 363 String type = onlyProps?Types.UDF_PROPERTIES.toString():Types.UDF_IMPL.toString(); 364 String str="u"+index; 365 GeneratorAdapter cga = constr.getAdapter(); 366 GeneratorAdapter ga = bc.getAdapter(); 367 368 // store 369 cga.visitVarInsn(ALOAD, 0); 370 cga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", onlyProps?Types.UDF_PROPERTIES_ARRAY.toString():Types.UDF_IMPL_ARRAY.toString()); 371 cga.push(index); 372 createUDFProperties(constr,index,onlyProps); 373 //cga.visitInsn(DUP_X2); 374 cga.visitInsn(AASTORE); 375 376 // get 377 ga.visitVarInsn(ALOAD, 0); 378 ga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", onlyProps?Types.UDF_PROPERTIES_ARRAY.toString():Types.UDF_IMPL_ARRAY.toString()); 379 ga.push(index); 380 ga.visitInsn(AALOAD); 381 } 382 383 384 385 public void createUDFProperties(BytecodeContext bc, int index, boolean onlyProps) throws BytecodeException { 386 GeneratorAdapter adapter=bc.getAdapter(); 387 if(!onlyProps) { 388 adapter.newInstance(Types.UDF_IMPL); 389 adapter.dup(); 390 } 391 adapter.newInstance(UDF_PROPERTIES); 392 adapter.dup(); 393 adapter.visitVarInsn(ALOAD, 1); 394 // page 395 //adapter.loadLocal(0); 396 //adapter.loadThis(); 397 398 // arguments 399 createArguments(bc); 400 // index 401 adapter.push(index); 402 // name 403 ExpressionUtil.writeOutSilent(name,bc, Expression.MODE_REF); 404 // return type 405 short type=ExpressionUtil.toShortType(returnType,CFTypes.TYPE_UNKNOW); 406 if(type==CFTypes.TYPE_UNKNOW) ExpressionUtil.writeOutSilent(returnType,bc, Expression.MODE_REF); 407 else adapter.push(type); 408 // return format 409 if(returnFormat!=null)ExpressionUtil.writeOutSilent(returnFormat,bc, Expression.MODE_REF); 410 else ASMConstants.NULL(adapter); 411 // output 412 ExpressionUtil.writeOutSilent(output,bc, Expression.MODE_VALUE); 413 // abstract 414 ExpressionUtil.writeOutSilent(abstr,bc, Expression.MODE_VALUE); 415 // access 416 writeOutAccess(bc, access); 417 // displayName 418 ExpressionUtil.writeOutSilent(displayName,bc, Expression.MODE_REF);// displayName; 419 // description 420 if(description!=null)ExpressionUtil.writeOutSilent(description,bc, Expression.MODE_REF);// displayName; 421 else adapter.push(""); 422 // hint 423 ExpressionUtil.writeOutSilent(hint,bc, Expression.MODE_REF);// hint; 424 // secureJson 425 if(secureJson!=null)ExpressionUtil.writeOutSilent(secureJson,bc, Expression.MODE_REF); 426 else ASMConstants.NULL(adapter); 427 // verify client 428 if(verifyClient!=null)ExpressionUtil.writeOutSilent(verifyClient,bc, Expression.MODE_REF); 429 else ASMConstants.NULL(adapter); 430 // meta 431 Page.createMetaDataStruct(bc,metadata,null); 432 433 adapter.invokeConstructor(UDF_PROPERTIES, type==-1?INIT_UDF_PROPERTIES_STRTYPE:INIT_UDF_PROPERTIES_SHORTTYPE); 434 if(!onlyProps)adapter.invokeConstructor(Types.UDF_IMPL, INIT_UDF_IMPL_PROP); 435 436 } 437 438 public void loadUDF(BytecodeContext bc, int index) throws BytecodeException { 439 // new UDF(...) 440 GeneratorAdapter adapter=bc.getAdapter(); 441 adapter.newInstance(Types.UDF_IMPL); 442 adapter.dup(); 443 444 loadUDF(bc, index,true); 445 446 adapter.invokeConstructor(Types.UDF_IMPL, INIT_UDF_IMPL_PROP); 447 } 448 449 450 451 /*private void loadArguments(BytecodeContext bc, int index) throws BytecodeException { 452 BytecodeContext constr = bc.getStaticConstructor(); 453 String type = Type.getType(FunctionArgument[].class).toString(); 454 String fa="fa_"+index; 455 FieldVisitor fv = constr.getClassWriter().visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, 456 fa, type, null, null); 457 fv.visitEnd(); 458 createArguments(constr); 459 constr.getAdapter().visitFieldInsn(Opcodes.PUTSTATIC, constr.getClassName(), fa, type); 460 461 bc.getAdapter().visitFieldInsn(Opcodes.GETSTATIC, constr.getClassName(), fa, type); 462 //createArguments(bc, adapter); 463 464 465 }*/ 466 467 private void createArguments(BytecodeContext bc) throws BytecodeException { 468 GeneratorAdapter ga = bc.getAdapter(); 469 ga.push(arguments.size()); 470 ga.newArray(FUNCTION_ARGUMENT); 471 Argument arg; 472 for (int i = 0; i < arguments.size(); i++) { 473 arg=(Argument) arguments.get(i); 474 475 boolean canHaveKey = Variable.canRegisterKey(arg.getName()); 476 477 // CHECK if default values 478 // type 479 ExprString _strType = arg.getType(); 480 short _type=CFTypes.TYPE_UNKNOW; 481 if(_strType instanceof LitString){ 482 _type=CFTypes.toShortStrict(((LitString)_strType).getString(),CFTypes.TYPE_UNKNOW); 483 } 484 boolean useType=!canHaveKey || _type!=CFTypes.TYPE_ANY; 485 //boolean useStrType=useType && (_type==CFTypes.TYPE_UNDEFINED || _type==CFTypes.TYPE_UNKNOW || CFTypes.toString(_type, null)==null); 486 487 // required 488 ExprBoolean _req = arg.getRequired(); 489 boolean useReq=!canHaveKey || toBoolean(_req,null)!=Boolean.FALSE; 490 491 // default-type 492 Expression _def = arg.getDefaultValueType(); 493 boolean useDef=!canHaveKey || toInt(_def,-1)!=FunctionArgument.DEFAULT_TYPE_NULL; 494 495 // pass by reference 496 ExprBoolean _pass = arg.isPassByReference(); 497 boolean usePass=!canHaveKey || toBoolean(_pass,null)!=Boolean.TRUE; 498 499 // display-hint 500 ExprString _dsp = arg.getDisplayName(); 501 boolean useDsp=!canHaveKey || !isLiteralEmptyString(_dsp); 502 503 // hint 504 ExprString _hint = arg.getHint(); 505 boolean useHint=!canHaveKey || !isLiteralEmptyString(_hint); 506 507 // meta 508 Map _meta = arg.getMetaData(); 509 boolean useMeta=!canHaveKey || (_meta!=null && !_meta.isEmpty()); 510 int functionIndex=7; 511 if(!useMeta) { 512 functionIndex--; 513 if(!useHint) { 514 functionIndex--; 515 if(!useDsp){ 516 functionIndex--; 517 if(!usePass) { 518 functionIndex--; 519 if(!useDef) { 520 functionIndex--; 521 if(!useReq) { 522 functionIndex--; 523 if(!useType){ 524 functionIndex--; 525 } 526 } 527 } 528 } 529 } 530 } 531 } 532 // write out arguments 533 ga.dup(); 534 ga.push(i); 535 536 // new FunctionArgument(...) 537 ga.newInstance(canHaveKey && functionIndex<INIT_FAI_KEY_LIGHT.length?FUNCTION_ARGUMENT_LIGHT:FUNCTION_ARGUMENT_IMPL); 538 ga.dup(); 539 boolean hasKey = Variable.registerKey(bc,arg.getName(),false); 540 541 // type 542 if(functionIndex>=INIT_FAI_KEY.length-7) { 543 _strType.writeOut(bc, Expression.MODE_REF); 544 bc.getAdapter().push(_type); 545 } 546 // required 547 if(functionIndex>=INIT_FAI_KEY.length-6)_req.writeOut(bc, Expression.MODE_VALUE); 548 // default value 549 if(functionIndex>=INIT_FAI_KEY.length-5)_def.writeOut(bc, Expression.MODE_VALUE); 550 // pass by reference 551 if(functionIndex>=INIT_FAI_KEY.length-4)_pass.writeOut(bc, Expression.MODE_VALUE); 552 // display-name 553 if(functionIndex>=INIT_FAI_KEY.length-3)_dsp.writeOut(bc, Expression.MODE_REF); 554 // hint 555 if(functionIndex>=INIT_FAI_KEY.length-2)_hint.writeOut(bc, Expression.MODE_REF); 556 //meta 557 if(functionIndex==INIT_FAI_KEY.length-1)Page.createMetaDataStruct(bc,_meta,null); 558 559 if(hasKey && functionIndex<INIT_FAI_KEY_LIGHT.length) 560 ga.invokeConstructor(FUNCTION_ARGUMENT_LIGHT, INIT_FAI_KEY[functionIndex]); 561 else 562 ga.invokeConstructor(FUNCTION_ARGUMENT_IMPL, hasKey?INIT_FAI_KEY[functionIndex]:INIT_FAI_STRING); 563 564 ga.visitInsn(Opcodes.AASTORE); 565 } 566 } 567 568 private int toInt(Expression expr, int defaultValue) { 569 if(expr instanceof LitInteger) { 570 return ((LitInteger)expr).getInteger().intValue(); 571 } 572 return defaultValue; 573 } 574 575 private Boolean toBoolean(ExprBoolean expr, Boolean defaultValue) { 576 if(expr instanceof LitBoolean) { 577 return ((LitBoolean)expr).getBooleanValue()?Boolean.TRUE:Boolean.FALSE; 578 } 579 return defaultValue; 580 } 581 582 private boolean isLiteralEmptyString(ExprString expr) { 583 if(expr instanceof LitString) { 584 return StringUtil.isEmpty(((LitString)expr).getString()); 585 } 586 return false; 587 } 588 589 private void writeOutAccess(BytecodeContext bc,ExprString expr) { 590 591 // write short type 592 if(expr instanceof LitString){ 593 int access=ComponentUtil.toIntAccess(((LitString)expr).getString(),Component.ACCESS_PUBLIC); 594 bc.getAdapter().push(access); 595 } 596 else bc.getAdapter().push(Component.ACCESS_PUBLIC); 597 } 598 private void writeOutAccess(BytecodeContext bc,int access) { 599 bc.getAdapter().push(access); 600 } 601 602 public void addArgument(String name, String type, boolean required, Expression defaultValue) { 603 addArgument( 604 LitString.toExprString(name), 605 LitString.toExprString(type), 606 LitBoolean.toExprBoolean(required), 607 defaultValue, 608 LitBoolean.TRUE, 609 LitString.EMPTY, 610 LitString.EMPTY,null); 611 } 612 613 public void addArgument(Expression name, Expression type, Expression required, Expression defaultValue,ExprBoolean passByReference, 614 Expression displayName, Expression hint,Map meta) { 615 arguments.add(new Argument(name,type,required,defaultValue,passByReference,displayName,hint,meta)); 616 } 617 618 /** 619 * @return the arguments 620 */ 621 public List getArguments() { 622 return arguments; 623 } 624 625 /** 626 * @return the body 627 */ 628 public Body getBody() { 629 return body; 630 } 631 632 public void setMetaData(Map<String,Attribute> metadata) { 633 this.metadata=metadata; 634 } 635 636 public void setHint(String hint){ 637 this.hint=LitString.toExprString(hint); 638 } 639 640 public void addAttribute(Attribute attr) throws TemplateException { 641 String name=attr.getName().toLowerCase(); 642 // name 643 if("name".equals(name)) { 644 throw new BytecodeException("name cannot be defined twice",getLine()); 645 //this.name=CastString.toExprString(attr.getValue()); 646 } 647 else if("returntype".equals(name)) { 648 this.returnType=toLitString(name,attr.getValue()); 649 } 650 else if("access".equals(name)) { 651 652 LitString ls = toLitString(name,attr.getValue()); 653 String strAccess = ls.getString(); 654 int acc = ComponentUtil.toIntAccess(strAccess,-1); 655 if(acc==-1) 656 throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getLine()); 657 access=acc; 658 659 } 660 661 else if("output".equals(name)) this.output=toLitBoolean(name,attr.getValue()); 662 else if("abstract".equals(name)) this.abstr=toLitBoolean(name,attr.getValue()); 663 else if("displayname".equals(name)) this.displayName=toLitString(name,attr.getValue()); 664 else if("hint".equals(name)) this.hint=toLitString(name,attr.getValue()); 665 else if("description".equals(name)) this.description=toLitString(name,attr.getValue()); 666 else if("returnformat".equals(name))this.returnFormat=toLitString(name,attr.getValue()); 667 else if("securejson".equals(name)) this.secureJson=toLitBoolean(name,attr.getValue()); 668 else if("verifyclient".equals(name)) this.verifyClient=toLitBoolean(name,attr.getValue()); 669 else { 670 toLitString(name,attr.getValue());// needed for testing 671 if(metadata==null)metadata=new HashMap(); 672 metadata.put(attr.getName(), attr); 673 } 674 } 675 676 private LitString toLitString(String name, Expression value) throws BytecodeException { 677 ExprString es = CastString.toExprString(value); 678 if(!(es instanceof LitString)) 679 throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getLine()); 680 return (LitString) es; 681 } 682 683 private LitBoolean toLitBoolean(String name, Expression value) throws BytecodeException { 684 ExprBoolean eb = CastBoolean.toExprBoolean(value); 685 if(!(eb instanceof LitBoolean)) 686 throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getLine()); 687 return (LitBoolean) eb; 688 } 689 690 }