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