001    package railo.transformer.library.tag;
002    
003    import java.io.IOException;
004    import java.lang.reflect.Constructor;
005    import java.lang.reflect.InvocationTargetException;
006    import java.util.HashMap;
007    import java.util.Iterator;
008    import java.util.LinkedHashMap;
009    import java.util.Map;
010    import java.util.Map.Entry;
011    
012    import org.objectweb.asm.Type;
013    
014    import railo.commons.lang.ClassException;
015    import railo.commons.lang.ClassUtil;
016    import railo.commons.lang.Md5;
017    import railo.commons.lang.StringUtil;
018    import railo.runtime.op.Caster;
019    import railo.transformer.bytecode.Position;
020    import railo.transformer.bytecode.cast.CastOther;
021    import railo.transformer.bytecode.expression.Expression;
022    import railo.transformer.bytecode.literal.LitBoolean;
023    import railo.transformer.bytecode.literal.LitDouble;
024    import railo.transformer.bytecode.literal.LitString;
025    import railo.transformer.bytecode.statement.tag.Attribute;
026    import railo.transformer.bytecode.statement.tag.Tag;
027    import railo.transformer.bytecode.statement.tag.TagOther;
028    import railo.transformer.cfml.attributes.AttributeEvaluator;
029    import railo.transformer.cfml.attributes.AttributeEvaluatorException;
030    import railo.transformer.cfml.evaluator.Evaluator;
031    import railo.transformer.cfml.evaluator.EvaluatorException;
032    import railo.transformer.cfml.tag.TagDependentBodyTransformer;
033    
034    /**
035     * Die Klasse TagLibTag repaesentiert ein einzelne Tag Definition einer TagLib, 
036     * beschreibt also alle Informationen die man zum validieren eines Tags braucht. 
037     */
038    public final class TagLibTag {
039            
040            public final static int ATTRIBUTE_TYPE_FIXED=0;
041            public final static int ATTRIBUTE_TYPE_DYNAMIC=1;
042            public final static int ATTRIBUTE_TYPE_NONAME=3;
043            public final static int ATTRIBUTE_TYPE_MIXED=4;
044            
045            
046            /**
047             * Definition des Attribut Type 
048             */
049            //public final static int ATTRIBUTE_TYPE_FULLDYNAMIC=2; deprecated
050            /**
051             * Definition des Attribut Type 
052             */
053            
054            private final static Class[] CONSTRUCTOR_PARAMS=new Class[]{Position.class,Position.class};
055            
056            private int attributeType;
057            private String name;
058            private boolean hasBody=true;
059            
060            private boolean isBodyReq=false;
061            private boolean isTagDependent=false;
062            private boolean bodyFree=true;
063            
064            private boolean parseBody;
065            private boolean hasAppendix;
066            private String description="";
067            private String tagClass;
068            private String tteClass;
069            private String tdbtClass;
070            private int min;
071            private int max;
072            private TagLib tagLib;
073            private Evaluator eval;
074            private TagDependentBodyTransformer tdbt;
075    
076            private Map<String,TagLibTagAttr> attributes=new LinkedHashMap<String,TagLibTagAttr>();
077            private Map<String,String> setters=new HashMap<String,String>();
078            private TagLibTagAttr attrFirst;
079            private TagLibTagAttr attrLast;
080            
081            private String strAttributeEvaluator;
082            private AttributeEvaluator attributeEvaluator;
083            private boolean handleException;
084        private boolean hasDefaultValue=false;
085            private Type tagType;
086            private String tttClass;
087            private Constructor  tttConstructor;
088            private boolean allowRemovingLiteral;
089            private TagLibTagAttr defaultAttribute;
090            private short status=TagLib.STATUS_IMPLEMENTED;
091            private Class clazz;
092            private TagLibTagScript script;
093            private final static TagLibTagAttr UNDEFINED=new TagLibTagAttr(null);
094            private TagLibTagAttr singleAttr=UNDEFINED;
095            private Expression attributeDefaultValue;
096    
097            public TagLibTag duplicate(boolean cloneAttributes) {
098                    TagLibTag tlt = new TagLibTag(tagLib);
099    
100                    tlt.attributeType=attributeType;
101                    tlt.name=name;
102                    tlt.hasBody=hasBody;
103                    tlt.isBodyReq=isBodyReq;
104                    tlt.isTagDependent=isTagDependent;
105                    tlt.bodyFree=bodyFree;
106                    tlt.parseBody=parseBody;
107                    tlt.hasAppendix=hasAppendix;
108                    tlt.description=description;
109                    tlt.tagClass=tagClass;
110                    tlt.tteClass=tteClass;
111                    tlt.tdbtClass=tdbtClass;
112                    tlt.min=min;
113                    tlt.max=max;
114                    tlt.strAttributeEvaluator=strAttributeEvaluator;
115                    tlt.handleException=handleException;
116                    tlt.hasDefaultValue=hasDefaultValue;
117                    tlt.tagType=tagType;
118                    tlt.tttClass=tttClass;
119                    tlt.tttConstructor=tttConstructor;
120                    tlt.allowRemovingLiteral=allowRemovingLiteral;
121                    tlt.status=status;
122                    
123                    tlt.eval=null;
124                    tlt.tdbt=null;
125                    tlt.attributeEvaluator=null;
126                    
127                    
128                    Iterator<Entry<String, TagLibTagAttr>> it = attributes.entrySet().iterator();
129                    if(cloneAttributes) {
130                            while(it.hasNext()){
131                                    tlt.setAttribute(it.next().getValue().duplicate(tlt));
132                            }
133                            if(defaultAttribute!=null)tlt.defaultAttribute=defaultAttribute.duplicate(tlt);
134                    }
135                    else {
136                            while(it.hasNext()){
137                                    tlt.setAttribute(it.next().getValue());
138                                    tlt.attrFirst=attrFirst;
139                                    tlt.attrLast=attrLast;
140                            }
141                            tlt.defaultAttribute=defaultAttribute;
142                    }
143                    
144                    
145                    // setter
146                    Iterator<Entry<String, String>> sit = setters.entrySet().iterator();
147                    Entry<String, String> se;
148                    while(sit.hasNext()){
149                            se = sit.next();
150                            tlt.setters.put(se.getKey(), se.getValue());
151                    }
152                    
153                    
154                    
155    /*
156                    private Map attributes=new HashMap();
157                    private TagLibTagAttr attrFirst;
158                    private TagLibTagAttr attrLast;
159                    
160                    private Map setters=new HashMap();
161                    private TagLibTagAttr defaultAttribute;
162            */      
163                    return tlt;
164            }
165            
166            
167            /**
168             * Geschuetzer Konstruktor ohne Argumente.
169             * @param tagLib
170             */
171            public TagLibTag(TagLib tagLib) {
172                this.tagLib=tagLib;
173            }
174    
175            /**
176             * Gibt alle Attribute (TagLibTagAttr) eines Tag als HashMap zurueck.
177             * @return HashMap Attribute als HashMap.
178             */
179            public Map<String,TagLibTagAttr> getAttributes() {
180                    return attributes;
181            }
182            
183            /**
184             * Gibt ein bestimmtes Attribut anhand seines Namens zurueck, 
185             * falls dieses Attribut nicht existiert wird null zurueckgegeben.
186             * @param name Name des Attribut das zurueckgegeben werden soll.
187             * @return Attribute das angfragt wurde oder null.
188             */
189            public TagLibTagAttr getAttribute(String name) {
190                    return attributes.get(name);
191            }
192            
193    
194    
195            
196            /**
197             * Gibt das erste Attribut, welches innerhalb des Tag definiert wurde, zurueck.
198             * @return  Attribut das angfragt wurde oder null.
199             */
200            public TagLibTagAttr getFirstAttribute() {
201                    return attrFirst;
202            }
203            
204            /**
205              * Gibt das letzte Attribut, welches innerhalb des Tag definiert wurde, zurueck.
206             * @return Attribut das angfragt wurde oder null.
207             */
208            public TagLibTagAttr getLastAttribute() {
209                    return attrLast;
210            }
211    
212            /**
213             * Gibt den Namen des Tag zurueck.
214             * @return String Name des Tag.
215             */
216            public String getName() {
217                    return name;
218            }
219            
220            /**
221             * Gibt den kompletten Namen des Tag zurueck, inkl. Name-Space und Trenner.
222             * @return String Kompletter Name des Tag.
223             */
224            public String getFullName() {
225                    String fullName;
226                    if(tagLib!=null)        {
227                            fullName=tagLib.getNameSpaceAndSeparator()+name;
228                    }
229                    else    {
230                            fullName=name;
231                    }
232                    return fullName;
233            }
234    
235            /**
236             * Gibt die Klassendefinition, welche diesen Tag implementiert, als Zeichenkette zurueck.
237             * Achtung: Die implementierende Klasse ist keine Java Klasse.
238             * @return String Zeichenkette der Klassendefinition.
239             */
240            public String getTagClassName() {
241                    return tagClass;
242            }
243            
244    
245            public Class getClazz() throws ClassException {
246                    if(clazz==null) {
247                            clazz=ClassUtil.loadClass(tagClass);
248                    }
249                    return clazz;
250            }
251            
252            
253            public Type getTagType() throws ClassException {
254                    if(tagType==null) {
255                            tagType=Type.getType(getClazz());
256                    }
257                    return tagType;
258            }
259            /**
260             * @return the status (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
261             */
262            public short getStatus() {
263                    return status;
264            }
265    
266    
267            /**
268             * @param status the status to set (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
269             */
270            public void setStatus(short status) {
271                    this.status = status;
272            }
273            
274            /**
275             * Gibt die Klassendefinition, der Klasse die den Evaluator (Translation Time Evaluator) implementiert, 
276             * als Zeichenkette zurueck.
277             * Falls kein Evaluator definiert ist wird null zurueckgegeben.
278             * @return String Zeichenkette der Klassendefinition.
279             */
280            public String getTteClassName() {
281                    return tteClass;
282            }
283            
284            public String getTttClassName() {
285                    return tttClass;
286            }
287            
288            /**
289             * Gibt den Evaluator (Translation Time Evaluator) dieser Klasse zurueck.
290             * Falls kein Evaluator definiert ist, wird null zurueckgegeben.
291             * @return Implementation des Evaluator zu dieser Klasse.
292             * @throws EvaluatorException Falls die Evaluator-Klasse nicht geladen werden kann.
293             */
294            public Evaluator getEvaluator() throws EvaluatorException {
295                    if(!hasTteClass()) return null;
296                    if(eval!=null) return eval;
297                    try {
298                            eval = (Evaluator) ClassUtil.loadInstance(tteClass);
299                    } 
300                    catch (ClassException e) {
301                            throw new EvaluatorException(e.getMessage());
302                    } 
303                    return eval;
304            }
305            
306            /**
307             * Gibt den TagDependentBodyTransformer dieser Klasse zurueck.
308             * Falls kein TagDependentBodyTransformer definiert ist, wird null zurueckgegeben.
309             * @return Implementation des TagDependentBodyTransformer zu dieser Klasse.
310             * @throws TagLibException Falls die TagDependentBodyTransformer-Klasse nicht geladen werden kann.
311             */
312            public TagDependentBodyTransformer getBodyTransformer() throws TagLibException {
313                    if(!hasTdbtClass()) return null;
314                    if(tdbt!=null) return tdbt;
315                    try {
316                            tdbt = (TagDependentBodyTransformer) ClassUtil.loadInstance(tdbtClass);
317                    } catch (ClassException e) {
318                            throw new TagLibException(e);
319                    } 
320                    return tdbt;
321            }
322            
323            /**
324             * Gibt zurueck ob Exception durch die implementierte Klasse abgehandelt werden oder nicht
325             * @return Wird eine Exception abgehandelt?
326             */
327            public boolean handleException() {
328                    return handleException;
329            }
330    
331            /**
332             * Gibt zurueck, ob eine Klassendefinition
333             * der Klasse die den Evaluator (Translation Time Evaluator) implementiert existiert.
334             * @return Ob eine Evaluator definiert ist.
335             */
336            public boolean hasTteClass() {
337                    return tteClass !=null && tteClass.length()>0;
338            }
339    
340            /**
341             * Gibt zurueck, ob eine Klassendefinition
342             * der Klasse die den TagDependentBodyTransformer implementiert existiert.
343             * @return Ob eine Evaluator definiert ist.
344             */
345            public boolean hasTdbtClass() {
346                    return tdbtClass !=null && tdbtClass.length()>0;
347            }
348    
349            /**
350             * Gibt den Attributetyp der Klasse zurueck.
351             * ( ATTRIBUTE_TYPE_FIX, ATTRIBUTE_TYPE_DYNAMIC, ATTRIBUTE_TYPE_NONAME)
352             * @return int
353             */
354            public int getAttributeType() {
355                    return attributeType;
356            }
357    
358            /**
359             * Gibt zurueck, ob das Tag einen Body haben kann oder nicht.
360             * @return Kann das Tag einen Body haben.
361             */
362            public boolean getHasBody() {
363                    return hasBody;
364            }
365    
366            /**
367             * Gibt die maximale Anzahl Attribute zurueck, die das Tag haben kann.
368             * @return Maximale moegliche Anzahl Attribute.
369             */
370            public int getMax() {
371                    return max;
372            }
373    
374            /**
375             * Gibt die minimale Anzahl Attribute zurueck, die das Tag haben muss.
376             * @return Minimal moegliche Anzahl Attribute.
377             */
378            public int getMin() {
379                    return min;
380            }
381    
382            /**
383             * Gibt die TagLib zurueck zu der das Tag gehoert.
384             * @return TagLib Zugehoerige TagLib.
385             */
386            public TagLib getTagLib() {
387                    return tagLib;
388            }
389            
390            /**
391             * Gibt zurueck ob das Tag seinen Body parsen soll oder nicht.
392             * @return Soll der Body geparst werden.
393             */
394            public boolean getParseBody() {
395                    return parseBody;
396            }
397            
398            /**
399             * Gibt zurueck, ob das Tag einen Appendix besitzen kann oder nicht.
400             * @return Kann das Tag einen Appendix besitzen.
401             */
402            public boolean hasAppendix() {
403                    return hasAppendix;
404            }
405    
406            /**
407             * Fragt ab ob der Body eines Tag freiwillig ist oder nicht.
408             * @return is required
409             */
410            public boolean isBodyReq() {
411                    return isBodyReq;
412            }
413    
414            /**
415             * Fragt ab ob die verarbeitung des Inhaltes eines Tag mit einem eigenen Transformer 
416             * vorgenommen werden soll.
417             * @return Fragt ab ob die verarbeitung des Inhaltes eines Tag mit einem eigenen Transformer 
418             * vorgenommen werden soll.
419             */
420            public boolean isTagDependent() {
421                    return isTagDependent;
422            }
423    
424            /**
425             * Setzt die TagLib des Tag.
426             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
427             * @param tagLib TagLib des Tag.
428             */
429            protected void setTagLib(TagLib tagLib) {
430                    this.tagLib = tagLib;
431            }
432            
433            /**
434             * Setzt ein einzelnes Attribut (TagLibTagAttr) eines Tag.
435             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
436             * @param attribute Attribute eines Tag.
437             */
438            public void setAttribute(TagLibTagAttr attribute) {
439                    attributes.put(attribute.getName(),attribute);
440                    if(attrFirst==null)attrFirst=attribute;
441                    attrLast=attribute;
442            }
443    
444            /**
445             * Setzt den Attributtyp eines Tag.
446             * ( ATTRIBUTE_TYPE_FIX, ATTRIBUTE_TYPE_DYNAMIC, ATTRIBUTE_TYPE_FULLDYNAMIC, ATTRIBUTE_TYPE_NONAME)
447             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
448             * @param attributeType The attributeType to set
449             */
450            public void setAttributeType(int attributeType) {
451                    
452                    this.attributeType = attributeType;
453            }
454    
455            /**
456             * Setzt die Information, was fuer ein BodyContent das Tag haben kann.
457             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
458             * @param value BodyContent Information.
459             */
460            public void setBodyContent(String value) {
461                    // empty, free, must, tagdependent
462                    value=value.toLowerCase().trim();
463                    //if(value.equals("jsp")) value="free";
464                    
465                    this.hasBody = !value.equals("empty");
466                    this.isBodyReq = !value.equals("free");
467                    this.isTagDependent = value.equals("tagdependent");
468                    bodyFree=value.equals("free");
469            }
470    
471            /**
472             * Setzt wieviele Attribute das Tag maximal haben darf.
473             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
474             * @param max The max to set
475             */
476            protected void setMax(int max) {
477                    this.max = max;
478            }
479    
480            /**
481             * Setzt wieviele Attribute das Tag minimal haben darf.
482             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
483             * @param min The min to set
484             */
485            protected void setMin(int min) {
486                    this.min = min;
487            }
488    
489            /**
490             * Setzt den Namen des Tag.
491             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
492             * @param name Name des Tag.
493             */
494            public void setName(String name) {
495                    this.name = name.toLowerCase();
496            }
497    
498            /**
499             * Setzt die implementierende Klassendefinition des Tag.
500             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
501             * @param tagClass Klassendefinition der Tag-Implementation.
502             */
503            public void setTagClass(String tagClass) {
504                    this.tagClass = tagClass;
505            }
506    
507            /**
508             * Setzt die implementierende Klassendefinition des Evaluator.
509             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
510             * @param  tteClass Klassendefinition der Evaluator-Implementation.
511             */
512            protected void setTteClass(String tteClass) {
513                    this.tteClass = tteClass;
514            }
515    
516            /**
517             * Setzt die implementierende Klassendefinition des Evaluator.
518             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
519             * @param  tteClass Klassendefinition der Evaluator-Implementation.
520             */
521            public void setTttClass(String tttClass) {
522                    this.tttClass = tttClass;
523                    this.tttConstructor=null;
524            }
525    
526            /**
527             * Setzt die implementierende Klassendefinition des TagDependentBodyTransformer.
528             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
529             * @param  tdbtClass Klassendefinition der TagDependentBodyTransformer-Implementation.
530             */
531            public void setTdbtClass(String tdbtClass) {
532                    this.tdbtClass = tdbtClass;
533                    this.tdbt = null;
534            }
535    
536            /**
537             * Setzt, ob der Body des Tag geparst werden soll oder nicht.
538             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
539             * @param parseBody Soll der Body geparst werden.
540             */
541            public void setParseBody(boolean parseBody) {
542                    this.parseBody = parseBody;
543            }
544    
545            /**
546             * Setzt ob das Tag einen Appendix besitzen kann oder nicht.
547             * Diese Methode wird durch die Klasse TagLibFactory verwendet.
548             * @param hasAppendix Kann das Tag einen Appendix besitzen.
549             */
550            public void setAppendix(boolean hasAppendix) {
551                    this.hasAppendix = hasAppendix;
552            }
553            /**
554             * @return Returns the description.
555             */
556            public String getDescription() {
557                    return description;
558            }
559    
560            /**
561             * @param description The description to set.
562             */
563            public void setDescription(String description) {
564                    this.description = description;
565            }
566    
567            /**
568             * @return Returns the bodyIsFree.
569             */
570            public boolean isBodyFree() {
571                    return bodyFree;
572            }
573    
574            public boolean hasBodyMethodExists() {
575                    Class clazz= ClassUtil.loadClass(getTagClassName(),(Class)null);//Class.orName(tag.getTagClassName());
576                    if(clazz==null) return false;
577                    
578                    try {
579                            java.lang.reflect.Method method = clazz.getMethod("hasBody", new Class[]{boolean.class});
580                            if(method==null)return false;
581                            return method.getReturnType()==void.class;
582                    } 
583                    catch (Exception e) {}
584                    return false;
585            }
586    
587            /**
588             * @return Gibt zurueck ob ein Attribut Evaluator definiert ist oder nicht.
589             */
590            public boolean hasAttributeEvaluator() {
591                    return strAttributeEvaluator!=null;
592            }
593    
594            /**
595             * @return Gibt den AttributeEvaluator zum Tag zurueck
596             * @throws AttributeEvaluatorException
597             */
598            public AttributeEvaluator getAttributeEvaluator() throws AttributeEvaluatorException {
599                    if(!hasAttributeEvaluator()) return null;
600                    if(attributeEvaluator!=null) return attributeEvaluator;
601                    try {
602                            return  attributeEvaluator=(AttributeEvaluator) ClassUtil.loadInstance(strAttributeEvaluator);
603                            
604                    } catch (ClassException e) {
605                            throw new AttributeEvaluatorException(e.getMessage());
606                    } 
607            }
608    
609            /**
610             * Setzt den Namen der Klasse welche einen AttributeEvaluator implementiert.
611             * @param value Name der AttributeEvaluator Klassse
612             */
613            public void setAttributeEvaluatorClassName(String value) {
614                    strAttributeEvaluator=value;
615                    
616            }
617    
618            /**
619             * sets if tag handle exception inside his body or not
620             * @param handleException handle it or not
621             */
622            public void setHandleExceptions(boolean handleException) {
623                    this.handleException=handleException;
624            }
625    
626        /**
627         * @return
628         */
629        public boolean hasDefaultValue() {
630            return hasDefaultValue;
631        }
632    
633        /**
634         * @param hasDefaultValue The hasDefaultValue to set.
635         */
636        public void setHasDefaultValue(boolean hasDefaultValue) {
637            this.hasDefaultValue = hasDefaultValue;
638        }
639    
640            /**
641             * return ASM Tag for this tag
642             * @param line
643             * @return
644    
645             */
646            public Tag getTag(Position start,Position end) throws TagLibException {
647                    if(StringUtil.isEmpty(tttClass)) return new TagOther(start,end);
648                    try {
649                            return _getTag(start,end);
650                    } 
651                    catch (ClassException e) {
652                            throw new TagLibException(e.getMessage());
653                    } 
654                    catch (NoSuchMethodException e) {
655                            throw new TagLibException(e.getMessage());
656                    } 
657                    catch (Throwable e) {
658                            throw new TagLibException(e);
659                    }
660            }
661            private Tag _getTag(Position start,Position end) throws ClassException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
662                    if(tttConstructor==null) {
663                            Class clazz = ClassUtil.loadClass(tttClass);
664                            tttConstructor = clazz.getConstructor(CONSTRUCTOR_PARAMS);
665                    }
666                    return (Tag) tttConstructor.newInstance(new Object[]{start,end});
667            }
668    
669            public void setAllowRemovingLiteral(boolean allowRemovingLiteral) {
670                    this.allowRemovingLiteral=allowRemovingLiteral;
671            }
672    
673            /**
674             * @return the allowRemovingLiteral
675             */
676            public boolean isAllowRemovingLiteral() {
677                    return allowRemovingLiteral;
678            }
679    
680            public String getAttributeNames() {
681                    Iterator<String> it = attributes.keySet().iterator();
682                    StringBuffer sb=new StringBuffer();
683                    while(it.hasNext()) {
684                            if(sb.length()>0)sb.append(",");
685                            sb.append(it.next());
686                    }
687                    return sb.toString();
688            }
689    
690            public String getSetter(Attribute attr, Type type) {
691                    if(tagLib.isCore())
692                            return "set"+StringUtil.ucFirst(attr.getName());
693                    
694                    String setter=setters.get(attr.getName());
695                    if(setter!=null)return setter;
696                    setter = "set"+StringUtil.ucFirst(attr.getName());
697                    Class clazz;
698                    try {
699                            if(type==null) type = CastOther.getType(attr.getType());
700                            clazz=ClassUtil.loadClass(getTagClassName());
701                            java.lang.reflect.Method m = ClassUtil.getMethodIgnoreCase(clazz,setter,new Class[]{ClassUtil.loadClass(type.getClassName())});
702                            setter=m.getName();
703                    } 
704                    catch (Exception e) {
705                            //print.err(setter);
706                            e.printStackTrace();
707                    }
708                    setters.put(attr.getName(), setter);
709                    return setter;
710            }
711    
712            public String getHash() {
713                    StringBuffer sb=new StringBuffer();
714                    sb.append(this.getTagClassName());
715                    sb.append(this.getAttributeNames());
716                    sb.append(this.getAttributeType());
717                    sb.append(this.getMax());
718                    sb.append(this.getMin());
719                    sb.append(this.getName());
720                    sb.append(this.getParseBody());
721                    sb.append(this.getTteClassName());
722                    sb.append(this.getTttClassName());
723                    Iterator<Entry<String, TagLibTagAttr>> it = this.getAttributes().entrySet().iterator();
724                    Entry<String, TagLibTagAttr> entry;
725                    while(it.hasNext()){
726                            entry = it.next();
727                            sb.append(entry.getKey());
728                            sb.append(entry.getValue().getHash());
729                    }
730                    
731                    try {
732                            return Md5.getDigestAsString(sb.toString());
733                    } catch (IOException e) {
734                            return "";
735                    }
736            }
737    
738            public TagLibTagAttr getDefaultAttribute() {
739                    return defaultAttribute;
740            }
741            
742            public void setDefaultAttribute(TagLibTagAttr defaultAttribute) {
743                    this.defaultAttribute=defaultAttribute;
744            }
745    
746    
747            public void setScript(TagLibTagScript script) {
748                    this.script=script;
749            }
750    
751    
752            /**
753             * @return the script
754             */
755            public TagLibTagScript getScript() {
756                    return script;
757            }
758    
759    
760            public TagLibTagAttr getSingleAttr() {
761                    
762                    if(singleAttr==UNDEFINED) {
763                            singleAttr=null;
764                            Iterator<TagLibTagAttr> it = getAttributes().values().iterator();
765                            TagLibTagAttr attr;
766                            while(it.hasNext()){
767                                    attr=it.next();
768                                    if(attr.getNoname()){
769                                            singleAttr=attr;
770                                            break;
771                                    }       
772                            }
773                    }
774                    return singleAttr;
775            }
776    
777    
778            /**
779             * attribute value set, if the attribute has no value defined
780             * @return
781             */
782            public Expression getAttributeDefaultValue() {
783                    if(attributeDefaultValue==null) return LitBoolean.TRUE;
784                    return attributeDefaultValue;
785            }
786            
787            public void setAttributeDefaultValue(String defaultValue) {
788                    defaultValue=defaultValue.trim();
789                    // boolean
790                    if(StringUtil.startsWithIgnoreCase(defaultValue, "boolean:")) {
791                            String str=defaultValue.substring(8).trim();
792                            Boolean b = Caster.toBoolean(str,null);
793                            if(b!=null){
794                                    this.attributeDefaultValue=LitBoolean.toExprBoolean(b.booleanValue());
795                                    return;
796                            }
797                            
798                    }
799                    // number
800                    else if(StringUtil.startsWithIgnoreCase(defaultValue, "number:")) {
801                            String str=defaultValue.substring(7).trim();
802                            Double d = Caster.toDouble(str,null);
803                            if(d!=null){
804                                    this.attributeDefaultValue=LitDouble.toExprDouble(d.doubleValue());
805                                    return;
806                            }
807                            
808                    }
809                    else this.attributeDefaultValue=LitString.toExprString(defaultValue);
810            }
811    }