001    package railo.runtime.tag;
002    
003    import java.io.IOException;
004    import java.util.Iterator;
005    import java.util.Map;
006    import java.util.Map.Entry;
007    
008    import javax.servlet.jsp.JspWriter;
009    import javax.servlet.jsp.tagext.Tag;
010    
011    import railo.commons.lang.StringUtil;
012    import railo.runtime.Component;
013    import railo.runtime.ComponentPro;
014    import railo.runtime.PageContext;
015    import railo.runtime.PageContextImpl;
016    import railo.runtime.component.ComponentLoader;
017    import railo.runtime.component.Member;
018    import railo.runtime.customtag.CustomTagUtil;
019    import railo.runtime.customtag.InitFile;
020    import railo.runtime.exp.ApplicationException;
021    import railo.runtime.exp.CasterException;
022    import railo.runtime.exp.ExpressionException;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.exp.PageRuntimeException;
025    import railo.runtime.exp.PageServletException;
026    import railo.runtime.ext.tag.AppendixTag;
027    import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl;
028    import railo.runtime.ext.tag.DynamicAttributes;
029    import railo.runtime.op.Caster;
030    import railo.runtime.op.Decision;
031    import railo.runtime.type.Collection;
032    import railo.runtime.type.KeyImpl;
033    import railo.runtime.type.List;
034    import railo.runtime.type.Struct;
035    import railo.runtime.type.StructImpl;
036    import railo.runtime.type.scope.Caller;
037    import railo.runtime.type.scope.CallerImpl;
038    import railo.runtime.type.scope.Undefined;
039    import railo.runtime.type.scope.UndefinedImpl;
040    import railo.runtime.type.scope.Variables;
041    import railo.runtime.type.scope.VariablesImpl;
042    import railo.runtime.type.util.ArrayUtil;
043    import railo.runtime.type.util.ComponentUtil;
044    import railo.runtime.type.util.Type;
045    import railo.runtime.util.QueryStack;
046    import railo.runtime.util.QueryStackImpl;
047    import railo.transformer.library.tag.TagLibTag;
048    import railo.transformer.library.tag.TagLibTagAttr;
049    
050    
051    /**
052    * Creates a CFML Custom Tag
053    **/
054    public class CFTag extends BodyTagTryCatchFinallyImpl implements DynamicAttributes,AppendixTag {
055    
056            private static Collection.Key GENERATED_CONTENT=KeyImpl.intern("GENERATEDCONTENT");
057            private static Collection.Key EXECUTION_MODE=KeyImpl.intern("EXECUTIONMODE");      
058            private static Collection.Key EXECUTE_BODY=KeyImpl.intern("EXECUTEBODY");
059            private static Collection.Key HAS_END_TAG=KeyImpl.intern("HASENDTAG");
060            private static Collection.Key PARENT=KeyImpl.intern("PARENT");
061            private static Collection.Key CFCATCH=KeyImpl.intern("CFCATCH");
062            private static Collection.Key SOURCE=KeyImpl.intern("SOURCE");
063            
064            
065            private static Collection.Key ATTRIBUTES=KeyImpl.intern("ATTRIBUTES");
066            private static Collection.Key CALLER=KeyImpl.intern("CALLER");
067            private static Collection.Key THIS_TAG=KeyImpl.intern("THISTAG");
068            
069    
070            private static final Collection.Key ON_ERROR = KeyImpl.intern("onError");
071            private static final Collection.Key ON_FINALLY = KeyImpl.intern("onFinally");
072            private static final Collection.Key ON_START_TAG = KeyImpl.intern("onStartTag");
073            private static final Collection.Key ON_END_TAG = KeyImpl.intern("onEndTag");
074            private static final Collection.Key INIT = KeyImpl.intern("init");
075    
076            private static final Collection.Key ATTRIBUTE_TYPE = KeyImpl.intern("attributetype");
077            private static final Collection.Key RT_EXPR_VALUE = KeyImpl.intern("rtexprvalue");
078            private static final Collection.Key PARSE_BODY = KeyImpl.intern("parsebody");
079            private static final Collection.Key METADATA = KeyImpl.intern("metadata");
080            private static final String MARKER = "2w12801";
081            
082        /**
083         * Field <code>attributesScope</code>
084         */
085        // new scopes
086        protected StructImpl attributesScope;
087        private Caller callerScope;
088        private StructImpl thistagScope;
089    
090        private Variables ctVariablesScope;
091    
092        private boolean hasBody;
093    
094        /**
095         * Field <code>filename</code>
096         */
097        //protected String filename;
098    
099        /**
100         * Field <code>source</code>
101         */
102        protected InitFile source;
103        private String appendix;
104            //private boolean doCustomTagDeepSearch;
105            
106            private ComponentPro cfc;
107            private boolean isEndTag;
108            
109            
110            
111        /**
112        * constructor for the tag class
113        **/
114        public CFTag() {
115            attributesScope = new StructImpl();
116            callerScope = new CallerImpl();
117            //thistagScope = new StructImpl();
118        }
119    
120        /**
121         * @see railo.runtime.ext.tag.DynamicAttributes#setDynamicAttribute(java.lang.String, java.lang.String, java.lang.Object)
122         */
123        public void setDynamicAttribute(String uri, String name, Object value) {
124            TagUtil.setDynamicAttribute(attributesScope,name,value,TagUtil.UPPER_CASE);
125        }
126    
127        /**
128        * @see javax.servlet.jsp.tagext.Tag#release()
129        */
130        public void release()   {
131            super.release();
132    
133            hasBody=false;
134            //filename=null;      
135    
136            attributesScope=new StructImpl();//.clear();
137            callerScope = new CallerImpl();
138            if(thistagScope!=null)thistagScope=null;
139            if(ctVariablesScope!=null)ctVariablesScope=null;  
140            
141    
142            isEndTag=false;     
143            
144            //cfc=null;
145            source=null;
146        }
147    
148        /**
149         * sets the appendix of the class
150         * @param appendix
151         */
152        public void setAppendix(String appendix) {
153            this.appendix=appendix;
154            //filename = appendix+'.'+pageContext.getConfig().getCFMLExtension();
155        }
156    
157        /**
158        * @see javax.servlet.jsp.tagext.Tag#doStartTag()
159        */
160        public int doStartTag() throws PageException    {
161            PageContextImpl pci=(PageContextImpl) pageContext;
162                    boolean old=pci.useSpecialMappings(true);
163                    try{
164                            initFile();
165                    callerScope.initialize(pageContext);
166                    if(source.isCFC())return cfcStartTag();
167                    return cfmlStartTag();  
168                    }
169                    finally{
170                            pci.useSpecialMappings(old);
171                    }
172            
173            
174            
175            
176        }
177    
178        /**
179        * @see javax.servlet.jsp.tagext.Tag#doEndTag()
180        */
181        public int doEndTag()   {
182            PageContextImpl pci=(PageContextImpl) pageContext;
183                    boolean old=pci.useSpecialMappings(true);
184                    try{
185                            if(source.isCFC())_doCFCFinally();
186                    return EVAL_PAGE;
187                    }
188                    finally{
189                            pci.useSpecialMappings(old);
190                    }
191        }
192    
193        /**
194        * @see javax.servlet.jsp.tagext.BodyTag#doInitBody()
195        */
196        public void doInitBody()    {
197            
198        }
199    
200        /**
201        * @see javax.servlet.jsp.tagext.BodyTag#doAfterBody()
202        */
203        public int doAfterBody() throws PageException   {
204            if(source.isCFC())return cfcEndTag();
205            return cfmlEndTag();
206        }
207        
208    
209            /**
210             * @see railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl#doCatch(java.lang.Throwable)
211             */
212        public void doCatch(Throwable t) throws Throwable {
213            if(source.isCFC()){
214                    String source=isEndTag?"end":"body";
215                    isEndTag=false;
216                    _doCFCCatch(t,source);
217            }
218            else super.doCatch(t);
219            }
220        
221        void initFile() throws PageException {
222            source=initFile(pageContext);
223        }
224    
225        public InitFile initFile(PageContext pageContext) throws PageException {
226            return CustomTagUtil.loadInitFile(pageContext, appendix);
227        }
228        
229            private int cfmlStartTag() throws PageException {
230                    callerScope.initialize(pageContext);
231            
232                    // thistag
233                    if(thistagScope==null)thistagScope=new StructImpl(StructImpl.TYPE_LINKED);
234            thistagScope.set(GENERATED_CONTENT,"");
235            thistagScope.set(EXECUTION_MODE,"start");      
236            thistagScope.set(EXECUTE_BODY,Boolean.TRUE);
237            thistagScope.set(HAS_END_TAG,Caster.toBoolean(hasBody));
238            
239                    
240                    ctVariablesScope=new VariablesImpl();
241            ctVariablesScope.setEL(ATTRIBUTES,attributesScope);
242            ctVariablesScope.setEL(CALLER,callerScope);
243            ctVariablesScope.setEL(THIS_TAG,thistagScope);
244            
245            
246            // include
247            doInclude();
248            
249            return Caster.toBooleanValue(thistagScope.get(EXECUTE_BODY))?EVAL_BODY_BUFFERED:SKIP_BODY;
250        } 
251            
252        private int cfmlEndTag() throws PageException {
253            // thistag     
254            String genConBefore = bodyContent.getString();
255            thistagScope.set(GENERATED_CONTENT,genConBefore);
256            thistagScope.set(EXECUTION_MODE,"end");
257            thistagScope.set(EXECUTE_BODY,Boolean.FALSE);
258            writeEL(bodyContent, MARKER);
259            
260            // include
261            try{
262                    doInclude();
263            }
264            catch(Throwable t){
265                    writeOut(genConBefore);
266                    throw Caster.toPageException(t);
267            }
268            
269            writeOut(genConBefore);
270    
271            return Caster.toBooleanValue(thistagScope.get(EXECUTE_BODY))?EVAL_BODY_BUFFERED:SKIP_BODY;
272        }
273    
274        
275    
276            private void writeOut(String genConBefore) throws PageException {
277                    String output = bodyContent.getString(); 
278                    bodyContent.clearBody();
279            String genConAfter = Caster.toString(thistagScope.get(GENERATED_CONTENT));
280            
281            if(genConBefore!=genConAfter){
282                    if(output.startsWith(genConBefore+MARKER)){
283                            output=output.substring((genConBefore+MARKER).length());
284                    }
285                    output=genConAfter+output;
286            }
287            else {
288                    if(output.startsWith(genConBefore+MARKER)){
289                            output=output.substring((genConBefore+MARKER).length());
290                            output=genConBefore+output;
291                    }
292            }
293            
294            
295            writeEL(bodyContent.getEnclosingWriter(),output);
296            }
297    
298            private void writeEL(JspWriter writer, String str) throws PageException {
299                    try {
300                            writer.write(str);
301                    } catch (IOException e) {
302                            throw Caster.toPageException(e);
303                    }
304            }
305    
306            void doInclude() throws PageException {
307            Variables var=pageContext.variablesScope();
308            pageContext.setVariablesScope(ctVariablesScope);
309            
310            
311            QueryStack cs=null;
312            Undefined undefined=pageContext.undefinedScope();
313            int oldMode=undefined.setMode(Undefined.MODE_NO_LOCAL_AND_ARGUMENTS);
314            if(oldMode!=Undefined.MODE_NO_LOCAL_AND_ARGUMENTS)
315                    callerScope.setScope(var,pageContext.localScope(),pageContext.argumentsScope(),true);
316            else 
317                    callerScope.setScope(var,null,null,false);
318            
319            if(pageContext.getConfig().allowImplicidQueryCall()) {
320                cs=undefined.getQueryStack();
321                undefined.setQueryStack(new QueryStackImpl());
322            }
323                
324            try {
325                pageContext.doInclude(source.getPageSource());
326            }
327            catch (Throwable t) {
328                throw Caster.toPageException(t);
329            }
330            finally {
331                undefined.setMode(oldMode);
332                //varScopeData=variablesScope.getMap();
333                pageContext.setVariablesScope(var);
334                if(pageContext.getConfig().allowImplicidQueryCall()) {
335                    undefined.setQueryStack(cs);
336                }
337            }
338        
339        }
340        
341        
342        // CFC
343        
344        private int cfcStartTag() throws PageException {
345            
346            callerScope.initialize(pageContext);
347            cfc = ComponentLoader.loadComponent(pageContext,null,source.getPageSource(), source.getFilename().substring(0,source.getFilename().length()-(pageContext.getConfig().getCFCExtension().length()+1)), false,true);
348            validateAttributes(cfc,attributesScope,StringUtil.ucFirst(List.last(source.getPageSource().getComponentName(),'.')));
349            
350            boolean exeBody = false;
351            try     {
352                            Object rtn=Boolean.TRUE;
353                            if(cfc.contains(pageContext, INIT)){
354                            Tag parent=getParent();
355                            while(parent!=null && !(parent instanceof CFTag && ((CFTag)parent).isCFCBasedCustomTag())) {
356                                    parent=parent.getParent();
357                            }
358                                    Struct args=new StructImpl(StructImpl.TYPE_LINKED);
359                                    args.set(HAS_END_TAG, Caster.toBoolean(hasBody));
360                            if(parent instanceof CFTag) {
361                                    args.set(PARENT, ((CFTag)parent).getComponent());
362                            }
363                            rtn=cfc.callWithNamedValues(pageContext, INIT, args);
364                    }
365                            
366                    if(cfc.contains(pageContext, ON_START_TAG)){
367                            Struct args=new StructImpl();
368                            args.set(ATTRIBUTES, attributesScope);
369                            setCaller(pageContext,args);
370                            
371                            
372                            
373                            rtn=cfc.callWithNamedValues(pageContext, ON_START_TAG, args);   
374                        }
375                    exeBody=Caster.toBooleanValue(rtn,true);
376            }
377            catch(Throwable t){
378                    _doCFCCatch(t,"start");
379            }
380            return exeBody?EVAL_BODY_BUFFERED:SKIP_BODY;
381        }
382        
383        private static void setCaller(PageContext pageContext, Struct args) throws PageException {
384            UndefinedImpl undefined=(UndefinedImpl) pageContext.undefinedScope();
385            args.set(CALLER, undefined.duplicate(false));
386            //args.set(CALLER, pageContext.variablesScope());
387            
388            }
389    
390            private static void validateAttributes(ComponentPro cfc,StructImpl attributesScope,String tagName) throws ApplicationException, ExpressionException {
391                    
392                    TagLibTag tag=getAttributeRequirments(cfc,false);
393                    if(tag==null) return;
394                    
395                    if(tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_FIXED || tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_MIXED){
396                            Iterator it = tag.getAttributes().entrySet().iterator();
397                            Map.Entry entry;
398                            int count=0;
399                            Collection.Key key;
400                            TagLibTagAttr attr;
401                            Object value;
402                            // check existing attributes
403                            while(it.hasNext()){
404                                    entry = (Entry) it.next();
405                                    count++;
406                                    key=KeyImpl.toKey(entry.getKey(),null);
407                                    attr=(TagLibTagAttr) entry.getValue();
408                                    value=attributesScope.get(key,null);
409                                    if(value==null){
410                                            if(attr.getDefaultValue()!=null){
411                                                    value=attr.getDefaultValue();
412                                                    attributesScope.setEL(key, value);
413                                            }
414                                            else if(attr.isRequired())
415                                                    throw new ApplicationException("attribute ["+key.getString()+"] is required for tag ["+tagName+"]");
416                                    }
417                                    if(value!=null) {
418                                            if(!Decision.isCastableTo(attr.getType(),value,true)) 
419                                                    throw new CasterException(createMessage(attr.getType(), value));
420                                    
421                                    }
422                            }
423                            
424                            // check if there are attributes not supported
425                            if(tag.getAttributeType()==TagLibTag.ATTRIBUTE_TYPE_FIXED && count<attributesScope.size()){
426                                    Collection.Key[] keys = attributesScope.keys();
427                                    for(int i=0;i<keys.length;i++){
428                                            if(tag.getAttribute(keys[i].getLowerString())==null)
429                                                    throw new ApplicationException("attribute ["+keys[i].getString()+"] is not supported for tag ["+tagName+"]");
430                                    }
431                                    
432                                    //Attribute susi is not allowed for tag cfmail
433                            }
434                    }
435            }
436        
437        private static String createMessage(String type, Object value) {
438            if(value instanceof String) return "can't cast String ["+value+"] to a value of type ["+type+"]";
439            else if(value!=null) return "can't cast Object type ["+Type.getName(value)+"] to a value of type ["+type+"]";
440                    else return "can't cast Null value to value of type ["+type+"]";
441    
442        } 
443        
444    
445            private static TagLibTag getAttributeRequirments(ComponentPro cfc, boolean runtime) throws ExpressionException {
446                    Struct meta=null;
447            //try {
448                    //meta = Caster.toStruct(cfc.get(Component.ACCESS_PRIVATE, METADATA),null,false);
449                    Member mem = ComponentUtil.toComponentAccess(cfc).getMember(Component.ACCESS_PRIVATE, METADATA,true,false);
450                    if(mem!=null)meta = Caster.toStruct(mem.getValue(),null,false);
451                    //}catch (PageException e) {e.printStackTrace();}
452            if(meta==null) return null;
453            
454            TagLibTag tag=new TagLibTag(null);
455        // TAG
456            
457            // type
458            
459            String type=Caster.toString(meta.get(ATTRIBUTE_TYPE,"dynamic"),"dynamic");
460            
461            if("fixed".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_FIXED);
462            //else if("mixed".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_MIXED);
463            //else if("noname".equalsIgnoreCase(type))tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_NONAME);
464            else tag.setAttributeType(TagLibTag.ATTRIBUTE_TYPE_DYNAMIC);
465            
466            if(!runtime){
467                    // hint
468                    String hint=Caster.toString(meta.get(KeyImpl.HINT,null),null);
469                    if(!StringUtil.isEmpty(hint))tag.setDescription(hint);
470                    
471                    // parseBody
472                    boolean rtexprvalue=Caster.toBooleanValue(meta.get(PARSE_BODY,Boolean.FALSE),false);
473                    tag.setParseBody(rtexprvalue);
474            }
475            
476        // ATTRIBUTES
477            Struct attributes=Caster.toStruct(meta.get(ATTRIBUTES,null),null,false);
478            if(attributes!=null) {
479                    Iterator it = attributes.entrySet().iterator();
480                    Map.Entry entry;
481                    TagLibTagAttr attr;
482                    Struct sct;
483                    String name;
484                    Object defaultValue;
485                    while(it.hasNext()){
486                            entry=(Entry) it.next();
487                            name=Caster.toString(entry.getKey(),null);
488                            if(StringUtil.isEmpty(name)) continue;
489                            attr=new TagLibTagAttr(tag);
490                            attr.setName(name);
491                            
492                            sct=Caster.toStruct(entry.getValue(),null,false);
493                            if(sct!=null){
494                                    attr.setRequired(Caster.toBooleanValue(sct.get(KeyImpl.REQUIRED,Boolean.FALSE),false));
495                                    attr.setType(Caster.toString(sct.get(KeyImpl.TYPE,"any"),"any"));
496                                    
497                                    defaultValue= sct.get(KeyImpl.DEFAULT,null);
498                                    if(defaultValue!=null)attr.setDefaultValue(defaultValue);
499                                    
500                                    
501                                    if(!runtime){
502                                            attr.setDescription(Caster.toString(sct.get(KeyImpl.HINT,null),null));
503                                            attr.setRtexpr(Caster.toBooleanValue(sct.get(RT_EXPR_VALUE,Boolean.TRUE),true));
504                                    }
505                            }
506                            tag.setAttribute(attr);
507                            
508                    }
509            }
510            return tag;
511            }
512    
513            private int cfcEndTag() throws PageException {
514            
515            boolean exeAgain = false;
516            try{
517                    String output=null;
518                    Object rtn=Boolean.FALSE;
519                    
520                    
521                    if(cfc.contains(pageContext, ON_END_TAG)){
522                            try {
523                                    output=bodyContent.getString();
524                                bodyContent.clearBody();
525                                //rtn=cfc.call(pageContext, ON_END_TAG, new Object[]{attributesScope,pageContext.variablesScope(),output});
526                                
527                                Struct args=new StructImpl(StructImpl.TYPE_LINKED);
528                                    args.set(ATTRIBUTES, attributesScope);
529                                    setCaller(pageContext, args);
530                                    args.set(GENERATED_CONTENT, output);
531                                    rtn=cfc.callWithNamedValues(pageContext, ON_END_TAG, args);     
532                                
533                                
534                                
535                            }
536                            finally {
537                                    writeEnclosingWriter();
538                            }
539                    }
540                    else writeEnclosingWriter();
541                    
542                    exeAgain= Caster.toBooleanValue(rtn,false);
543                }
544            catch(Throwable t){
545                    isEndTag=true;
546                    throw Caster.toPageException(t);
547            }
548            return exeAgain?EVAL_BODY_BUFFERED:SKIP_BODY;
549            
550        }
551        
552        public void _doCFCCatch(Throwable t, String source) throws PageException {
553            writeEnclosingWriter();
554            
555            // remove PageServletException wrap
556            if(t instanceof PageServletException) {
557                        PageServletException pse=(PageServletException)t;
558                        t=pse.getPageException();
559                    }
560            
561            // abort 
562            try {
563                            if(railo.runtime.exp.Abort.isAbort(t)){
564                                    if(bodyContent!=null){
565                                            bodyContent.writeOut(bodyContent.getEnclosingWriter());
566                                            bodyContent.clearBuffer();
567                                    }
568                                    throw Caster.toPageException(t);
569                            }
570                    }
571                    catch(IOException ioe){
572                            throw Caster.toPageException(ioe);
573                    }
574            
575            
576            
577            try {
578                            if(cfc.contains(pageContext, ON_ERROR)){
579                            PageException pe = Caster.toPageException(t);
580                            //Object rtn=cfc.call(pageContext, ON_ERROR, new Object[]{pe.getCatchBlock(pageContext),source});
581                            
582                            Struct args=new StructImpl(StructImpl.TYPE_LINKED);
583                            args.set(CFCATCH, pe.getCatchBlock(pageContext));
584                            args.set(SOURCE, source);
585                            Object rtn=cfc.callWithNamedValues(pageContext, ON_ERROR, args);        
586                        
587                            if(Caster.toBooleanValue(rtn,false))
588                                            throw t;
589                    }
590                            else throw t;
591            }
592            catch(Throwable th) {
593                    writeEnclosingWriter();
594                    _doCFCFinally();
595                    throw Caster.toPageException(th);
596            }
597            writeEnclosingWriter();
598            }
599        
600        private void _doCFCFinally() {
601                    if(cfc.contains(pageContext, ON_FINALLY)){
602                            try {
603                                    cfc.call(pageContext, ON_FINALLY, ArrayUtil.OBJECT_EMPTY);
604                            } 
605                            catch (PageException pe) {
606                                    throw new PageRuntimeException(pe);
607                            }
608                            finally{
609                                    writeEnclosingWriter();
610                            }
611            }
612            }
613        
614        
615        private void writeEnclosingWriter()  {
616            if(bodyContent!=null){
617                            try {
618                                    String output = bodyContent.getString(); 
619                                    bodyContent.clearBody();
620                        bodyContent.getEnclosingWriter().write(output);    
621                    } 
622                            catch (IOException e) {
623                            //throw Caster.toPageException(e);
624                    }
625            }
626            }
627        
628        
629    
630        /**
631         * sets if tag has a body or not
632         * @param hasBody
633         */
634        public void hasBody(boolean hasBody) {
635            this.hasBody=hasBody;
636        }
637    
638        /**
639         * @return Returns the appendix.
640         */
641        public String getAppendix() {
642            return appendix;
643        }
644    
645        /**
646         * @return return thistag
647         */
648        public Struct getThis() {
649            if(isCFCBasedCustomTag()){
650                    return cfc;
651            }
652            return thistagScope;
653        }
654        
655        /**
656         * @return return thistag
657         */
658        public Struct getCallerScope() {
659            return callerScope;
660        }
661        
662        /**
663         * @return return thistag
664         */
665        public Struct getAttributesScope() {
666            return attributesScope;
667        }
668    
669            /**
670             * @return the ctVariablesScope
671             */
672            public Struct getVariablesScope() {
673                    if(isCFCBasedCustomTag())       {
674                            return cfc.getComponentScope();
675                    }
676                    return ctVariablesScope;
677            }
678            
679        /**
680             * @return the cfc
681             */
682            public Component getComponent() {
683                    return cfc;
684            }
685            
686            public boolean isCFCBasedCustomTag() {
687                    return getSource().isCFC();
688            }
689            
690            private InitFile getSource() {
691                    if(source==null){
692                            try {
693                                    source=initFile(pageContext);
694                            } catch (PageException e) {
695                                    e.printStackTrace();
696                            }
697                    }
698                    return source;
699            }
700    
701            /*class InitFile {
702                    PageSource ps;
703                    String filename;
704                    boolean isCFC;
705    
706                    public InitFile(PageSource ps,String filename,boolean isCFC){
707                            this.ps=ps;
708                            this.filename=filename;
709                            this.isCFC=isCFC;
710                    }
711            }*/
712            
713            
714    }