001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime;
020
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Map;
026import java.util.Map.Entry;
027import java.util.Set;
028
029import lucee.commons.lang.StringUtil;
030import lucee.runtime.component.ComponentLoader;
031import lucee.runtime.component.MetaDataSoftReference;
032import lucee.runtime.component.MetadataUtil;
033import lucee.runtime.dump.DumpData;
034import lucee.runtime.dump.DumpProperties;
035import lucee.runtime.dump.DumpTable;
036import lucee.runtime.engine.ThreadLocalPageContext;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.type.Array;
039import lucee.runtime.type.ArrayImpl;
040import lucee.runtime.type.Collection;
041import lucee.runtime.type.KeyImpl;
042import lucee.runtime.type.Struct;
043import lucee.runtime.type.StructImpl;
044import lucee.runtime.type.UDF;
045import lucee.runtime.type.UDFImpl;
046import lucee.runtime.type.UDFProperties;
047import lucee.runtime.type.util.ArrayUtil;
048import lucee.runtime.type.util.KeyConstants;
049
050/**
051 * 
052 * MUST add handling for new attributes (style, namespace, serviceportname, porttypename, wsdlfile, bindingname, and output)
053 */ 
054public class InterfaceImpl implements Interface {
055
056        private static final long serialVersionUID = -2488865504508636253L;
057
058        private static final InterfaceImpl[] EMPTY = new InterfaceImpl[]{};
059        
060        //private InterfacePage page;
061        private PageSource pageSource;
062        private String extend;
063        private String hint;
064        private String dspName;
065        private String callPath;
066        private boolean relPath;
067        private Map meta;
068        
069        private InterfaceImpl[] superInterfaces;
070        
071        private Map<Collection.Key,UDF> udfs=new HashMap<Collection.Key,UDF>();
072        private Map<Collection.Key,UDF> interfacesUDFs;
073
074        /**
075     * Constructor of the Component
076     * @param output 
077     * @param extend 
078     * @param hint 
079     * @param dspName 
080     */
081        public InterfaceImpl(InterfacePage page,String extend, String hint, String dspName,String callPath, boolean relPath,Map interfacesUDFs) {
082        this(page.getPageSource(),extend, hint, dspName,callPath, relPath,interfacesUDFs,null);
083        }
084        public InterfaceImpl(InterfacePage page,String extend, String hint, String dspName,String callPath, boolean relPath,Map interfacesUDFs, Map meta) {
085        this(page.getPageSource(),extend, hint, dspName,callPath, relPath,interfacesUDFs,meta);
086        }
087        public InterfaceImpl(PageSource pageSource,String extend, String hint, String dspName,String callPath, boolean relPath,Map interfacesUDFs) {
088        this(pageSource, extend, hint, dspName, callPath, relPath, interfacesUDFs, null);
089        }
090        public InterfaceImpl(PageSource pageSource,String extend, String hint, String dspName,String callPath, boolean relPath,Map interfacesUDFs, Map meta) {
091        this.pageSource=pageSource;
092        this.extend=extend;
093        this.hint=hint;
094        this.dspName=dspName;
095        this.callPath=callPath;
096        this.relPath=relPath;
097        this.interfacesUDFs=interfacesUDFs;
098        this.meta=meta;
099}
100         
101         
102         
103            
104
105        private static void init(PageContext pc,InterfaceImpl icfc) throws PageException {
106                if(!StringUtil.isEmpty(icfc.extend) && (icfc.superInterfaces==null || icfc.superInterfaces.length==0)) {
107                        icfc.superInterfaces=loadImplements(ThreadLocalPageContext.get(pc),icfc.getPageSource(),icfc.extend,icfc.interfacesUDFs);
108                }
109                else icfc.superInterfaces=EMPTY;
110        }
111
112
113    public static InterfaceImpl[] loadImplements(PageContext pc, PageSource child, String lstExtend, Map interfaceUdfs) throws PageException {
114        List<InterfaceImpl> interfaces=new ArrayList<InterfaceImpl>();
115        loadImplements(pc,child, lstExtend, interfaces, interfaceUdfs);
116        return interfaces.toArray(new InterfaceImpl[interfaces.size()]);
117        
118        }
119
120    private static void loadImplements(PageContext pc,PageSource child, String lstExtend,List interfaces, Map interfaceUdfs) throws PageException {
121        
122        Array arr = lucee.runtime.type.util.ListUtil.listToArrayRemoveEmpty(lstExtend, ',');
123        Iterator<Object> it = arr.valueIterator();
124        InterfaceImpl ic;
125        String extend;
126
127        while(it.hasNext()) {
128                extend=((String) it.next()).trim();
129                ic=ComponentLoader.loadInterface(pc,child,extend,interfaceUdfs);
130                interfaces.add(ic);
131                ic.setUDFListener(interfaceUdfs);
132                if(!StringUtil.isEmpty(ic.extend)) {
133                        loadImplements(pc,ic.getPageSource(),ic.extend,interfaces,interfaceUdfs);
134                }
135        }
136        }
137    
138    private void setUDFListener(Map<Collection.Key,UDF> interfacesUDFs) {
139                this.interfacesUDFs=interfacesUDFs;
140        }
141
142
143
144        /*public boolean instanceOf(String type) {
145        boolean b = _instanceOf(type);
146        print.out("instanceOf("+type+"):"+page+":"+b);
147        return b;
148    }*/
149    public boolean instanceOf(String type) {
150                if(relPath) {
151                if(type.equalsIgnoreCase(callPath)) return true;
152            if(type.equalsIgnoreCase(pageSource.getComponentName())) return true;
153            if(type.equalsIgnoreCase(_getName())) return true;       
154        }
155        else {
156                if(type.equalsIgnoreCase(callPath)) return true;
157            if(type.equalsIgnoreCase(_getName())) return true; 
158        }
159                if(superInterfaces==null){
160                        try {
161                                init(null,this);
162                        } catch (PageException e) {
163                                superInterfaces=EMPTY;
164                        }
165                }
166        for(int i=0;i<superInterfaces.length;i++){
167                if(superInterfaces[i].instanceOf(type))return true;
168        }
169        return false;
170    }
171
172 
173    /**
174         * @return the callPath
175         */
176        public String getCallPath() {
177                return callPath;
178        }
179
180
181
182        private String _getName() { // MUST nicht so toll
183            if(callPath==null) return "";
184            return lucee.runtime.type.util.ListUtil.last(callPath,"./",true);
185        }
186    
187    public void registerUDF(String key, UDF udf) {
188        udfs.put(KeyImpl.init(key),udf);
189        interfacesUDFs.put(KeyImpl.init(key), udf);
190    }
191    
192    public void registerUDF(Collection.Key key, UDF udf) {
193        udfs.put(key,udf);
194        interfacesUDFs.put(key, udf);
195    }
196    
197    public void registerUDF(String key, UDFProperties props) {
198        registerUDF(key, new UDFImpl(props));
199    }
200    
201    public void registerUDF(Collection.Key key, UDFProperties props) {
202        registerUDF(key, new UDFImpl(props));
203    }
204    
205    
206    
207    
208    
209    
210    
211    
212    @Override
213        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
214            DumpTable table = new DumpTable("interface","#99cc99","#ffffff","#000000");
215        table.setTitle("Interface "+callPath+""+(" "+StringUtil.escapeHTML(dspName)));
216        table.setComment("Interface can not directly invoked as a object");
217        //if(top.properties.extend.length()>0)table.appendRow(1,new SimpleDumpData("Extends"),new SimpleDumpData(top.properties.extend));
218        //if(top.properties.hint.trim().length()>0)table.appendRow(1,new SimpleDumpData("Hint"),new SimpleDumpData(top.properties.hint));
219        
220        //table.appendRow(1,new SimpleDumpData(""),_toDumpData(top,pageContext,maxlevel,access));
221        return table;
222    }
223
224        /* *
225         * @return the page
226         * /
227        public InterfacePage getPage() {
228                return page;
229        }*/
230
231        public PageSource getPageSource() {
232                return pageSource;
233        }
234        public InterfaceImpl[] getExtends() {
235                return superInterfaces;
236        }
237
238
239        public Struct getMetaData(PageContext pc) throws PageException {
240                return _getMetaData(pc,this,false);
241        }
242        public Struct getMetaData(PageContext pc, boolean ignoreCache) throws PageException {
243                return _getMetaData(pc,this,ignoreCache);
244        }
245        private static Struct _getMetaData(PageContext pc,InterfaceImpl icfc, boolean ignoreCache) throws PageException {
246                Page page=MetadataUtil.getPageWhenMetaDataStillValid(pc, icfc, ignoreCache);
247        if(page!=null && page.metaData!=null && page.metaData.get()!=null) return page.metaData.get();
248        
249        long creationTime=System.currentTimeMillis();
250        
251                
252                Struct sct=new StructImpl();
253                ArrayImpl arr=new ArrayImpl();
254                {
255                        Iterator<UDF> it = icfc.udfs.values().iterator();
256                while(it.hasNext()) {
257                        arr.append(it.next().getMetaData(pc));
258                }
259                }
260        
261        if(icfc.meta!=null) {
262                Iterator it = icfc.meta.entrySet().iterator();
263                Map.Entry entry;
264                while(it.hasNext()){
265                        entry=(Entry) it.next();
266                        sct.setEL(KeyImpl.toKey(entry.getKey()), entry.getValue());
267                }
268        }
269        
270        
271        if(!StringUtil.isEmpty(icfc.hint,true))sct.set(KeyConstants._hint,icfc.hint);
272        if(!StringUtil.isEmpty(icfc.dspName,true))sct.set(KeyConstants._displayname,icfc.dspName);
273        init(pc,icfc);
274        if(!ArrayUtil.isEmpty(icfc.superInterfaces)){
275            Set<String> _set = lucee.runtime.type.util.ListUtil.listToSet(icfc.extend,',',true);
276            Struct ex=new StructImpl();
277                sct.set(KeyConstants._extends,ex);
278                for(int i=0;i<icfc.superInterfaces.length;i++){
279                        if(!_set.contains(icfc.superInterfaces[i].getCallPath())) continue;
280                        ex.setEL(KeyImpl.init(icfc.superInterfaces[i].getCallPath()),_getMetaData(pc,icfc.superInterfaces[i],true));
281                }
282                
283        }
284        
285        if(arr.size()!=0)sct.set(KeyConstants._functions,arr);
286        PageSource ps = icfc.pageSource;
287        sct.set(KeyConstants._name,ps.getComponentName());
288        sct.set(KeyConstants._fullname,ps.getComponentName());
289       
290        sct.set(KeyConstants._path,ps.getDisplayPath());
291        sct.set(KeyConstants._type,"interface");
292        
293
294        page.metaData=new MetaDataSoftReference<Struct>(sct,creationTime);
295        return sct;
296        }
297
298}