001 package railo.transformer.bytecode.util; 002 003 import java.io.IOException; 004 import java.io.PrintWriter; 005 import java.util.Iterator; 006 import java.util.List; 007 008 import org.objectweb.asm.ClassWriter; 009 import org.objectweb.asm.FieldVisitor; 010 import org.objectweb.asm.Label; 011 import org.objectweb.asm.MethodVisitor; 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.aprint; 018 import railo.commons.digest.MD5; 019 import railo.commons.lang.StringUtil; 020 import railo.commons.lang.SystemOut; 021 import railo.runtime.component.Property; 022 import railo.runtime.engine.ThreadLocalPageContext; 023 import railo.runtime.exp.PageException; 024 import railo.runtime.net.rpc.AxisCaster; 025 import railo.runtime.op.Caster; 026 import railo.transformer.bytecode.Body; 027 import railo.transformer.bytecode.BytecodeException; 028 import railo.transformer.bytecode.Literal; 029 import railo.transformer.bytecode.Page; 030 import railo.transformer.bytecode.ScriptBody; 031 import railo.transformer.bytecode.Statement; 032 import railo.transformer.bytecode.cast.CastBoolean; 033 import railo.transformer.bytecode.cast.CastDouble; 034 import railo.transformer.bytecode.cast.CastString; 035 import railo.transformer.bytecode.expression.ExprDouble; 036 import railo.transformer.bytecode.expression.ExprString; 037 import railo.transformer.bytecode.expression.Expression; 038 import railo.transformer.bytecode.expression.var.Variable; 039 import railo.transformer.bytecode.expression.var.VariableString; 040 import railo.transformer.bytecode.literal.LitBoolean; 041 import railo.transformer.bytecode.literal.LitDouble; 042 import railo.transformer.bytecode.literal.LitString; 043 import railo.transformer.bytecode.statement.FlowControl; 044 import railo.transformer.bytecode.statement.PrintOut; 045 import railo.transformer.bytecode.statement.TryCatchFinally; 046 import railo.transformer.bytecode.statement.tag.Attribute; 047 import railo.transformer.bytecode.statement.tag.Tag; 048 import railo.transformer.bytecode.statement.tag.TagComponent; 049 import railo.transformer.bytecode.statement.tag.TagTry; 050 import railo.transformer.cfml.evaluator.EvaluatorException; 051 052 public final class ASMUtil { 053 054 private static final int VERSION_2=1; 055 private static final int VERSION_3=2; 056 057 public static final short TYPE_ALL=0; 058 public static final short TYPE_BOOLEAN=1; 059 public static final short TYPE_NUMERIC=2; 060 public static final short TYPE_STRING=4; 061 062 063 064 065 private static int version=0; 066 067 private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()"); 068 private static final String VERSION_MESSAGE = "you use a invalid version of the ASM Jar, please update your jar files"; 069 private static long id=0; 070 071 /** 072 * Gibt zur�ck ob das direkt �bergeordnete Tag mit dem �bergebenen Full-Name (Namespace und Name) existiert. 073 * @param el Startelement, von wo aus gesucht werden soll. 074 * @param fullName Name des gesuchten Tags. 075 * @return Existiert ein solches Tag oder nicht. 076 */ 077 public static boolean hasAncestorTag(Tag tag, String fullName) { 078 return getAncestorTag(tag, fullName)!=null; 079 } 080 081 082 /** 083 * Gibt das �bergeordnete CFXD Tag Element zur�ck, falls dies nicht existiert wird null zur�ckgegeben. 084 * @param el Element von dem das parent Element zur�ckgegeben werden soll. 085 * @return �bergeordnete CFXD Tag Element 086 */ 087 public static Tag getParentTag(Tag tag) { 088 Statement p=tag.getParent(); 089 if(p==null)return null; 090 p=p.getParent(); 091 if(p instanceof Tag) return (Tag) p; 092 return null; 093 } 094 095 public static boolean isParentTag(Tag tag,String fullName) { 096 Tag p = getParentTag(tag); 097 if(p==null) return false; 098 return p.getFullname().equalsIgnoreCase(fullName); 099 100 } 101 public static boolean isParentTag(Tag tag,Class clazz) { 102 Tag p = getParentTag(tag); 103 if(p==null) return false; 104 return p.getClass()==clazz; 105 106 } 107 108 /** 109 * has ancestor LoopStatement 110 * @param stat 111 * @return 112 */ 113 public static boolean hasAncestorLoopStatement(Statement stat) { 114 return getAncestorFlowControlStatement(stat)!=null; 115 } 116 117 /** 118 * get ancestor LoopStatement 119 * @param stat 120 * @param ingoreScript 121 * @return 122 */ 123 public static FlowControl getAncestorFlowControlStatement(Statement stat) { 124 Statement parent = stat; 125 while(true) { 126 parent=parent.getParent(); 127 if(parent==null)return null; 128 if(parent instanceof FlowControl) { 129 if(parent instanceof ScriptBody){ 130 FlowControl scriptBodyParent = getAncestorFlowControlStatement(parent); 131 if(scriptBodyParent!=null) return scriptBodyParent; 132 return (FlowControl)parent; 133 } 134 135 136 return (FlowControl) parent; 137 } 138 } 139 } 140 141 public static boolean hasAncestorTryStatement(Statement stat) { 142 return getAncestorTryStatement(stat)!=null; 143 } 144 145 public static Statement getAncestorTryStatement(Statement stat) { 146 Statement parent = stat; 147 while(true) { 148 parent=parent.getParent(); 149 if(parent==null)return null; 150 151 if(parent instanceof TagTry) { 152 return parent; 153 } 154 else if(parent instanceof TryCatchFinally) { 155 return parent; 156 } 157 } 158 } 159 160 161 162 163 /** 164 * Gibt ein �bergeordnetes Tag mit dem �bergebenen Full-Name (Namespace und Name) zur�ck, 165 * falls ein solches existiert, andernfalls wird null zur�ckgegeben. 166 * @param el Startelement, von wo aus gesucht werden soll. 167 * @param fullName Name des gesuchten Tags. 168 * @return �bergeornetes Element oder null. 169 */ 170 public static Tag getAncestorTag(Tag tag, String fullName) { 171 Statement parent=tag; 172 while(true) { 173 parent=parent.getParent(); 174 if(parent==null)return null; 175 if(parent instanceof Tag) { 176 tag=(Tag) parent; 177 if(tag.getFullname().equalsIgnoreCase(fullName)) 178 return tag; 179 } 180 } 181 } 182 183 /** 184 * extract the content of a attribut 185 * @param cfxdTag 186 * @param attrName 187 * @return attribute value 188 * @throws EvaluatorException 189 */ 190 public static Boolean getAttributeBoolean(Tag tag,String attrName) throws EvaluatorException { 191 Boolean b= getAttributeLiteral(tag, attrName).getBoolean(null); 192 if(b==null)throw new EvaluatorException("attribute ["+attrName+"] must be a constant boolean value"); 193 return b; 194 } 195 196 /** 197 * extract the content of a attribut 198 * @param cfxdTag 199 * @param attrName 200 * @return attribute value 201 * @throws EvaluatorException 202 */ 203 public static Boolean getAttributeBoolean(Tag tag,String attrName, Boolean defaultValue) { 204 Literal lit=getAttributeLiteral(tag, attrName,null); 205 if(lit==null) return defaultValue; 206 return lit.getBoolean(defaultValue); 207 } 208 209 210 /** 211 * extract the content of a attribut 212 * @param cfxdTag 213 * @param attrName 214 * @return attribute value 215 * @throws EvaluatorException 216 */ 217 public static String getAttributeString(Tag tag,String attrName) throws EvaluatorException { 218 return getAttributeLiteral(tag, attrName).getString(); 219 } 220 221 /** 222 * extract the content of a attribut 223 * @param cfxdTag 224 * @param attrName 225 * @return attribute value 226 * @throws EvaluatorException 227 */ 228 public static String getAttributeString(Tag tag,String attrName, String defaultValue) { 229 Literal lit=getAttributeLiteral(tag, attrName,null); 230 if(lit==null) return defaultValue; 231 return lit.getString(); 232 } 233 234 /** 235 * extract the content of a attribut 236 * @param cfxdTag 237 * @param attrName 238 * @return attribute value 239 * @throws EvaluatorException 240 */ 241 public static Literal getAttributeLiteral(Tag tag,String attrName) throws EvaluatorException { 242 Attribute attr = tag.getAttribute(attrName); 243 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 244 throw new EvaluatorException("attribute ["+attrName+"] must be a constant value"); 245 } 246 247 248 249 /** 250 * extract the content of a attribut 251 * @param cfxdTag 252 * @param attrName 253 * @return attribute value 254 * @throws EvaluatorException 255 */ 256 public static Literal getAttributeLiteral(Tag tag,String attrName, Literal defaultValue) { 257 Attribute attr = tag.getAttribute(attrName); 258 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 259 return defaultValue; 260 } 261 262 263 264 265 /** 266 * Pr�ft ob das das angegebene Tag in der gleichen Ebene nach dem angegebenen Tag vorkommt. 267 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 268 * @param nameToFind Tag Name der nicht vorkommen darf 269 * @return kommt das Tag vor. 270 */ 271 public static boolean hasSisterTagAfter(Tag tag, String nameToFind) { 272 Body body=(Body) tag.getParent(); 273 List stats = body.getStatements(); 274 Iterator it = stats.iterator(); 275 Statement other; 276 277 boolean isAfter=false; 278 while(it.hasNext()) { 279 other=(Statement) it.next(); 280 281 if(other instanceof Tag) { 282 if(isAfter) { 283 if(((Tag) other).getTagLibTag().getName().equals(nameToFind)) 284 return true; 285 } 286 else if(other == tag) isAfter=true; 287 288 } 289 290 } 291 return false; 292 } 293 294 295 296 /** 297 * Pr�ft ob das angegebene Tag innerhalb seiner Ebene einmalig ist oder nicht. 298 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 299 * @return kommt das Tag vor. 300 */ 301 public static boolean hasSisterTagWithSameName(Tag tag) { 302 303 Body body=(Body) tag.getParent(); 304 List stats = body.getStatements(); 305 Iterator it = stats.iterator(); 306 Statement other; 307 String name=tag.getTagLibTag().getName(); 308 309 while(it.hasNext()) { 310 other=(Statement) it.next(); 311 312 if(other != tag && other instanceof Tag && ((Tag) other).getTagLibTag().getName().equals(name)) 313 return true; 314 315 } 316 return false; 317 } 318 319 /** 320 * remove this tag from his parent body 321 * @param tag 322 */ 323 public static void remove(Tag tag) { 324 Body body=(Body) tag.getParent(); 325 body.getStatements().remove(tag); 326 } 327 328 /** 329 * replace src with trg 330 * @param src 331 * @param trg 332 */ 333 public static void replace(Tag src, Tag trg, boolean moveBody) { 334 trg.setParent(src.getParent()); 335 336 Body p=(Body) src.getParent(); 337 List stats = p.getStatements(); 338 Iterator it = stats.iterator(); 339 Statement stat; 340 int count=0; 341 342 while(it.hasNext()) { 343 stat=(Statement) it.next(); 344 if(stat==src) { 345 if(moveBody && src.getBody()!=null)src.getBody().setParent(trg); 346 stats.set(count, trg); 347 break; 348 } 349 count++; 350 } 351 } 352 353 public static Page getAncestorPage(Statement stat) throws BytecodeException { 354 Statement parent=stat; 355 while(true) { 356 parent=parent.getParent(); 357 if(parent==null) { 358 throw new BytecodeException("missing parent Statement of Statment",stat.getLine()); 359 //return null; 360 } 361 if(parent instanceof Page) return (Page) parent; 362 } 363 } 364 365 public static void listAncestor(Statement stat) throws BytecodeException { 366 Statement parent=stat; 367 aprint.o(stat); 368 while(true) { 369 parent=parent.getParent(); 370 if(parent instanceof Page)aprint.o("page-> "+ ((Page)parent).getSource()); 371 else aprint.o("parent-> "+ parent); 372 if(parent==null) break; 373 } 374 } 375 376 377 public static Tag getAncestorComponent(Statement stat) throws BytecodeException { 378 //print.ln("getAncestorPage:"+stat); 379 Statement parent=stat; 380 while(true) { 381 parent=parent.getParent(); 382 //print.ln(" - "+parent); 383 if(parent==null) { 384 throw new BytecodeException("missing parent Statement of Statment",stat.getLine()); 385 //return null; 386 } 387 if(parent instanceof TagComponent) 388 //if(parent instanceof Tag && "component".equals(((Tag)parent).getTagLibTag().getName())) 389 return (Tag) parent; 390 } 391 } 392 393 public static Statement getRoot(Statement stat) { 394 while(true) { 395 if(isRoot(stat)) { 396 return stat; 397 } 398 stat=stat.getParent(); 399 } 400 } 401 402 403 404 public static boolean isRoot(Statement statement) { 405 //return statement instanceof Page || (statement instanceof Tag && "component".equals(((Tag)statement).getTagLibTag().getName())); 406 return statement instanceof Page || statement instanceof TagComponent; 407 } 408 409 public static void invokeMethod(GeneratorAdapter adapter, Type type, Method method) { 410 if(type.getClass().isInterface()) 411 adapter.invokeInterface(type, method); 412 else 413 adapter.invokeVirtual(type, method); 414 } 415 416 public static byte[] createPojo(String className, ASMProperty[] properties,Class parent,Class[] interfaces, String srcName) throws PageException { 417 className=className.replace('.', '/'); 418 className=className.replace('\\', '/'); 419 className=railo.runtime.type.List.trim(className, "/"); 420 String[] inter=null; 421 if(interfaces!=null){ 422 inter=new String[interfaces.length]; 423 for(int i=0;i<inter.length;i++){ 424 inter[i]=interfaces[i].getName().replace('.', '/'); 425 } 426 } 427 // CREATE CLASS 428 //ClassWriter cw = new ClassWriter(true); 429 ClassWriter cw = ASMUtil.getClassWriter(); 430 cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, className, null, parent.getName().replace('.', '/'), inter); 431 String md5; 432 try{ 433 md5=createMD5(properties); 434 } 435 catch(Throwable t){ 436 md5=""; 437 t.printStackTrace(); 438 } 439 440 FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "_md5_", "Ljava/lang/String;", null, md5); 441 fv.visitEnd(); 442 443 444 // Constructor 445 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw); 446 adapter.loadThis(); 447 adapter.invokeConstructor(toType(parent,true), CONSTRUCTOR_OBJECT); 448 adapter.returnValue(); 449 adapter.endMethod(); 450 451 // properties 452 for(int i=0;i<properties.length;i++){ 453 createProperty(cw,className,properties[i]); 454 } 455 456 // complexType src 457 if(!StringUtil.isEmpty(srcName)) { 458 MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "_srcName", "()Ljava/lang/String;", null, null); 459 mv.visitCode(); 460 Label l0 = new Label(); 461 mv.visitLabel(l0); 462 mv.visitLineNumber(4, l0); 463 mv.visitLdcInsn(srcName); 464 mv.visitInsn(Opcodes.ARETURN); 465 mv.visitMaxs(1, 0); 466 mv.visitEnd(); 467 } 468 469 cw.visitEnd(); 470 return cw.toByteArray(); 471 } 472 473 private static void createProperty(ClassWriter cw,String classType, ASMProperty property) throws PageException { 474 String name = property.getName(); 475 Type type = property.getASMType(); 476 Class clazz = property.getClazz(); 477 478 cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd(); 479 480 int load=loadFor(type); 481 int sizeOf=sizeOf(type); 482 483 // get<PropertyName>():<type> 484 Type[] types=new Type[0]; 485 Method method = new Method((clazz==boolean.class?"get":"get")+StringUtil.ucFirst(name),type,types); 486 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 487 488 Label start = new Label(); 489 adapter.visitLabel(start); 490 491 adapter.visitVarInsn(Opcodes.ALOAD, 0); 492 adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString()); 493 adapter.returnValue(); 494 Label end = new Label(); 495 adapter.visitLabel(end); 496 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 497 adapter.visitMaxs(sizeOf, 1); 498 499 adapter.visitEnd(); 500 501 502 503 504 505 506 507 // set<PropertyName>(object):void 508 types=new Type[]{type}; 509 method = new Method("set"+StringUtil.ucFirst(name),Types.VOID,types); 510 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 511 512 start = new Label(); 513 adapter.visitLabel(start); 514 adapter.visitVarInsn(Opcodes.ALOAD, 0); 515 adapter.visitVarInsn(load, 1); 516 adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString()); 517 518 adapter.visitInsn(Opcodes.RETURN); 519 end = new Label(); 520 adapter.visitLabel(end); 521 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 522 adapter.visitLocalVariable(name, type.toString(), null, start, end, 1); 523 adapter.visitMaxs(sizeOf+1, sizeOf+1); 524 adapter.visitEnd(); 525 526 527 528 529 530 531 } 532 533 public static int loadFor(Type type) { 534 if(type.equals(Types.BOOLEAN_VALUE) || type.equals(Types.INT_VALUE) || type.equals(Types.CHAR) || type.equals(Types.SHORT_VALUE)) 535 return Opcodes.ILOAD; 536 if(type.equals(Types.FLOAT_VALUE)) 537 return Opcodes.FLOAD; 538 if(type.equals(Types.LONG_VALUE)) 539 return Opcodes.LLOAD; 540 if(type.equals(Types.DOUBLE_VALUE)) 541 return Opcodes.DLOAD; 542 return Opcodes.ALOAD; 543 } 544 545 public static int sizeOf(Type type) { 546 if(type.equals(Types.LONG_VALUE) || type.equals(Types.DOUBLE_VALUE)) 547 return 2; 548 return 1; 549 } 550 551 552 /** 553 * translate a string cfml type definition to a Type Object 554 * @param cfType 555 * @param axistype 556 * @return 557 * @throws PageException 558 */ 559 public static Type toType(String cfType, boolean axistype) throws PageException { 560 return toType(Caster.cfTypeToClass(cfType), axistype); 561 } 562 563 /** 564 * translate a string cfml type definition to a Type Object 565 * @param cfType 566 * @param axistype 567 * @return 568 * @throws PageException 569 */ 570 public static Type toType(Class type, boolean axistype) { 571 if(axistype)type=AxisCaster.toAxisTypeClass(type); 572 return Type.getType(type); 573 } 574 575 576 public static String createMD5(ASMProperty[] props) { 577 578 StringBuffer sb=new StringBuffer(); 579 for(int i=0;i<props.length;i++){ 580 sb.append("name:"+props[i].getName()+";"); 581 if(props[i] instanceof Property){ 582 sb.append("type:"+((Property)props[i]).getType()+";"); 583 } 584 else { 585 try { 586 sb.append("type:"+props[i].getASMType()+";"); 587 588 } 589 catch (PageException e) {} 590 } 591 } 592 try { 593 return MD5.getDigestAsString(sb.toString()); 594 } catch (IOException e) { 595 return ""; 596 } 597 } 598 599 600 601 public static void removeLiterlChildren(Tag tag, boolean recursive) { 602 Body body=tag.getBody(); 603 if(body!=null) { 604 List list = body.getStatements(); 605 Statement[] stats = (Statement[]) list.toArray(new Statement[list.size()]); 606 PrintOut po; 607 Tag t; 608 for(int i=0;i<stats.length;i++) { 609 if(stats[i] instanceof PrintOut) { 610 po=(PrintOut) stats[i]; 611 if(po.getExpr() instanceof Literal) { 612 body.getStatements().remove(po); 613 } 614 } 615 else if(recursive && stats[i] instanceof Tag) { 616 t=(Tag) stats[i]; 617 if(t.getTagLibTag().isAllowRemovingLiteral()) { 618 removeLiterlChildren(t, recursive); 619 } 620 } 621 } 622 } 623 } 624 625 626 public synchronized static String getId() { 627 if(id<0)id=0; 628 return StringUtil.addZeros(++id,6); 629 } 630 631 632 public static boolean isEmpty(Body body) { 633 return body==null || body.isEmpty(); 634 } 635 636 637 /** 638 * @param adapter 639 * @param expr 640 * @param mode 641 */ 642 public static void pop(GeneratorAdapter adapter, Expression expr,int mode) { 643 if(mode==Expression.MODE_VALUE && (expr instanceof ExprDouble))adapter.pop2(); 644 else adapter.pop(); 645 } 646 public static void pop(GeneratorAdapter adapter, Type type) { 647 if(type.equals(Types.DOUBLE_VALUE))adapter.pop2(); 648 else if(type.equals(Types.VOID)); 649 else adapter.pop(); 650 } 651 652 653 public static ClassWriter getClassWriter() { 654 if(version==VERSION_2) 655 return new ClassWriter(true); 656 657 try{ 658 ClassWriter cw = new ClassWriter(true); 659 version=VERSION_2; 660 return cw; 661 } 662 catch(NoSuchMethodError err){ 663 if(version==0){ 664 version=VERSION_3; 665 } 666 667 PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter(); 668 SystemOut.printDate(ew, VERSION_MESSAGE); 669 670 try { 671 return ClassWriter.class.getConstructor(new Class[]{int.class}).newInstance(new Object[]{new Integer(1)}); 672 673 } 674 catch (Exception e) { 675 throw new RuntimeException(Caster.toPageException(e)); 676 677 } 678 } 679 } 680 681 /* 682 * For 3.1 683 * 684 * public static ClassWriter getClassWriter() { 685 if(version==VERSION_3) 686 return new ClassWriter(ClassWriter.COMPUTE_MAXS); 687 688 try{ 689 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 690 version=VERSION_3; 691 return cw; 692 } 693 catch(NoSuchMethodError err){ 694 if(version==0){ 695 version=VERSION_2; 696 throw new RuntimeException(new ApplicationException(VERSION_MESSAGE+ 697 ", after reload this version will work as well, but please update to newer version")); 698 } 699 700 PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter(); 701 SystemOut.printDate(ew, VERSION_MESSAGE); 702 //err.printStackTrace(ew); 703 704 try { 705 return (ClassWriter) ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE}); 706 707 } 708 catch (Exception e) { 709 throw new RuntimeException(Caster.toPageException(e)); 710 711 } 712 } 713 }*/ 714 715 716 public static String createOverfowMethod() { 717 return "_call"+ASMUtil.getId(); 718 } 719 720 // FUTURE add to loader, same method is also in FD Extension railo.intergral.fusiondebug.server.util.FDUtil 721 public static boolean isOverfowMethod(String name) { 722 return name.startsWith("_call") && name.length()>=11; 723 } 724 725 726 public static boolean isDotKey(ExprString expr) { 727 return expr instanceof LitString && !((LitString)expr).fromBracket(); 728 } 729 730 public static String toString(Expression exp,String defaultValue) { 731 try { 732 return toString(exp); 733 } catch (BytecodeException e) { 734 return defaultValue; 735 } 736 } 737 public static String toString(Expression exp) throws BytecodeException { 738 if(exp instanceof Variable) { 739 return toString(VariableString.toExprString(exp)); 740 } 741 else if(exp instanceof VariableString) { 742 return ((VariableString)exp).castToString(); 743 } 744 else if(exp instanceof Literal) { 745 return ((Literal)exp).toString(); 746 } 747 return null; 748 } 749 750 751 public static Boolean toBoolean(Attribute attr, int line) throws BytecodeException { 752 if(attr==null) 753 throw new BytecodeException("attribute does not exist",line); 754 755 if(attr.getValue() instanceof Literal){ 756 Boolean b=((Literal)attr.getValue()).getBoolean(null); 757 if(b!=null) return b; 758 } 759 throw new BytecodeException("attribute ["+attr.getName()+"] must be a constant boolean value",line); 760 761 762 } 763 public static Boolean toBoolean(Attribute attr, int line, Boolean defaultValue) { 764 if(attr==null) 765 return defaultValue; 766 767 if(attr.getValue() instanceof Literal){ 768 Boolean b=((Literal)attr.getValue()).getBoolean(null); 769 if(b!=null) return b; 770 } 771 return defaultValue; 772 } 773 774 775 public static boolean isCFC(Statement s) { 776 Statement p; 777 while((p=s.getParent())!=null){ 778 s=p; 779 } 780 781 return true; 782 } 783 784 785 786 787 public static boolean isLiteralAttribute(Tag tag, String attrName, short type,boolean required,boolean throwWhenNot) throws EvaluatorException { 788 Attribute attr = tag.getAttribute(attrName); 789 String strType="/constant"; 790 if(attr!=null) { 791 switch(type){ 792 case TYPE_ALL: 793 if(attr.getValue() instanceof Literal) return true; 794 break; 795 case TYPE_BOOLEAN: 796 if(CastBoolean.toExprBoolean(attr.getValue()) instanceof LitBoolean) return true; 797 strType=" boolean"; 798 break; 799 case TYPE_NUMERIC: 800 if(CastDouble.toExprDouble(attr.getValue()) instanceof LitDouble) return true; 801 strType=" numeric"; 802 break; 803 case TYPE_STRING: 804 if(CastString.toExprString(attr.getValue()) instanceof LitString) return true; 805 strType=" string"; 806 break; 807 } 808 if(!throwWhenNot) return false; 809 throw new EvaluatorException("Attribute ["+attrName+"] of the Tag ["+tag.getFullname()+"] must be a literal"+strType+" value"); 810 } 811 if(required){ 812 if(!throwWhenNot) return false; 813 throw new EvaluatorException("Attribute ["+attrName+"] of the Tag ["+tag.getFullname()+"] is required"); 814 } 815 return true; 816 } 817 818 819 public static boolean isRefType(Type type) { 820 return 821 !(type==Types.BYTE_VALUE || type==Types.BOOLEAN_VALUE || type==Types.CHAR || type==Types.DOUBLE_VALUE || 822 type==Types.FLOAT_VALUE || type==Types.INT_VALUE || type==Types.LONG_VALUE || type==Types.SHORT_VALUE); 823 } 824 825 826 public static Type toRefType(Type type) { 827 if(type==Types.BYTE_VALUE) return Types.BYTE; 828 if(type==Types.BOOLEAN_VALUE) return Types.BOOLEAN; 829 if(type==Types.CHAR) return Types.CHARACTER; 830 if(type==Types.DOUBLE_VALUE) return Types.DOUBLE; 831 if(type==Types.FLOAT_VALUE) return Types.FLOAT; 832 if(type==Types.INT_VALUE) return Types.INTEGER; 833 if(type==Types.LONG_VALUE) return Types.LONG; 834 if(type==Types.SHORT_VALUE) return Types.SHORT; 835 836 return type; 837 } 838 839 /** 840 * return value type only when there is one 841 * @param type 842 * @return 843 */ 844 public static Type toValueType(Type type) { 845 if(type==Types.BYTE) return Types.BYTE_VALUE; 846 if(type==Types.BOOLEAN) return Types.BOOLEAN_VALUE; 847 if(type==Types.CHARACTER) return Types.CHAR; 848 if(type==Types.DOUBLE) return Types.DOUBLE_VALUE; 849 if(type==Types.FLOAT) return Types.FLOAT_VALUE; 850 if(type==Types.INTEGER) return Types.INT_VALUE; 851 if(type==Types.LONG) return Types.LONG_VALUE; 852 if(type==Types.SHORT) return Types.SHORT_VALUE; 853 854 return type; 855 } 856 857 858 public static Class getValueTypeClass(Type type, Class defaultValue) { 859 860 if(type==Types.BYTE_VALUE) return byte.class; 861 if(type==Types.BOOLEAN_VALUE) return boolean.class; 862 if(type==Types.CHAR) return char.class; 863 if(type==Types.DOUBLE_VALUE) return double.class; 864 if(type==Types.FLOAT_VALUE) return float.class; 865 if(type==Types.INT_VALUE) return int.class; 866 if(type==Types.LONG_VALUE) return long.class; 867 if(type==Types.SHORT_VALUE) return short.class; 868 869 return defaultValue; 870 } 871 872 873 public static boolean containsComponent(Body body) { 874 if(body==null) return false; 875 876 Iterator it = body.getStatements().iterator(); 877 while(it.hasNext()){ 878 if(it.next() instanceof TagComponent)return true; 879 } 880 return false; 881 } 882 883 }