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    }