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