/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import lucee.commons.lang.StringUtil;
import lucee.runtime.component.ComponentLoader;
import lucee.runtime.component.MetaDataSoftReference;
import lucee.runtime.component.MetadataUtil;
import lucee.runtime.dump.DumpData;
import lucee.runtime.dump.DumpProperties;
import lucee.runtime.dump.DumpTable;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.exp.PageException;
import lucee.runtime.type.ArrayImpl;
import lucee.runtime.type.Collection;
import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.UDF;
import lucee.runtime.type.UDFImpl;
import lucee.runtime.type.UDFProperties;
import lucee.runtime.type.scope.Variables;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.KeyConstants;
/**
*
* MUST add handling for new attributes (style, namespace, serviceportname, porttypename, wsdlfile, bindingname, and output)
*/
public class InterfaceImpl implements Interface {
private static final long serialVersionUID = -2488865504508636253L;
private static final InterfaceImpl[] EMPTY = new InterfaceImpl[]{};
private PageSource pageSource;
private String strExtend;
private String hint;
private String dspName;
private String callPath;
private boolean realPath;
private Map meta;
boolean initialized;
private List<InterfaceImpl> extend;
private final Map<Collection.Key,UDF> udfs=new HashMap<Collection.Key,UDF>();
//private Map<Collection.Key,UDF> interfacesUDFs=null;
public InterfaceImpl(PageContext pc,InterfacePageImpl page,String strExtend, String hint, String dspName,
String callPath, boolean realPath, Map meta) throws PageException {
//print.ds("Interface::Constructor:"+page.getPageSource().getDisplayPath());
pc=ThreadLocalPageContext.get(pc);
this.pageSource=page.getPageSource();
this.strExtend=strExtend;
this.hint=hint;
this.dspName=dspName;
this.callPath=callPath;
this.realPath=realPath;
this.meta=meta;
// load extends
if(!StringUtil.isEmpty(strExtend,true))
this.extend=loadInterfaces(pc, pageSource, strExtend);
}
public static List<InterfaceImpl> loadInterfaces(PageContext pc,PageSource loadingLocation,String listExtends) throws PageException{
List<InterfaceImpl> extend=new ArrayList<InterfaceImpl>();
Iterator<String> it = lucee.runtime.type.util.ListUtil.toListRemoveEmpty(listExtends, ',').iterator();
InterfaceImpl inter;
String str;
while(it.hasNext()) {
str=it.next().trim();
if(str.isEmpty()) continue;
inter=ComponentLoader.searchInterface(pc,loadingLocation,str);
extend.add(inter);
}
return extend;
}
@Override
public boolean instanceOf(String type) {
if(realPath) {
if(type.equalsIgnoreCase(callPath)) return true;
if(type.equalsIgnoreCase(pageSource.getComponentName())) return true;
if(type.equalsIgnoreCase(_getName())) return true;
}
else {
if(type.equalsIgnoreCase(callPath)) return true;
if(type.equalsIgnoreCase(_getName())) return true;
}
// extends
if(extend==null || extend.isEmpty()) return false; // no kids
Iterator<InterfaceImpl> it = extend.iterator();
while(it.hasNext()){
if(it.next().instanceOf(type))return true;
}
return false;
}
/**
* @return the callPath
*/
@Override
public String getCallPath() {
return callPath;
}
private String _getName() { // MUST nicht so toll
if(callPath==null) return "";
return lucee.runtime.type.util.ListUtil.last(callPath,"./",true);
}
@Override
public void registerUDF(Collection.Key key, UDF udf) throws ApplicationException {
if(udf.getModifier()==Component.MODIFIER_FINAL)
throw new ApplicationException("the final function ["+key+"] is not allowed within the interface ["+getPageSource().getDisplayPath()+"]");
udfs.put(key,udf);
}
@Override
public void registerUDF(Collection.Key key, UDFProperties props) throws ApplicationException {
registerUDF(key, new UDFImpl(props));
}
@Override
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
DumpTable table = new DumpTable("interface","#99cc99","#ffffff","#000000");
table.setTitle("Interface "+callPath+""+(" "+StringUtil.escapeHTML(dspName)));
table.setComment("Interface can not directly invoked as a object");
//if(top.properties.extend.length()>0)table.appendRow(1,new SimpleDumpData("Extends"),new SimpleDumpData(top.properties.extend));
//if(top.properties.hint.trim().length()>0)table.appendRow(1,new SimpleDumpData("Hint"),new SimpleDumpData(top.properties.hint));
//table.appendRow(1,new SimpleDumpData(""),_toDumpData(top,pageContext,maxlevel,access));
return table;
}
/* *
* @return the page
* /
public InterfacePage getPage() {
return page;
}*/
@Override
public PageSource getPageSource() {
return pageSource;
}
@Override
public Interface[] getExtends() {
return extend==null?EMPTY:extend.toArray(new InterfaceImpl[extend.size()]);
}
public List<InterfaceImpl> _getExtends() {
return extend;
}
@Override
public Struct getMetaData(PageContext pc) throws PageException {
return _getMetaData(pc,this,false);
}
@Override
public Struct getMetaData(PageContext pc, boolean ignoreCache) throws PageException {
return _getMetaData(pc,this,ignoreCache);
}
private static Struct _getMetaData(PageContext pc,InterfaceImpl icfc, boolean ignoreCache) throws PageException {
Page page=MetadataUtil.getPageWhenMetaDataStillValid(pc, icfc, ignoreCache);
if(page!=null && page.metaData!=null && page.metaData.get()!=null) return page.metaData.get();
long creationTime=System.currentTimeMillis();
Struct sct=new StructImpl();
ArrayImpl arr=new ArrayImpl();
{
Iterator<UDF> it = icfc.udfs.values().iterator();
while(it.hasNext()) {
arr.append(it.next().getMetaData(pc));
}
}
if(icfc.meta!=null) {
Iterator it = icfc.meta.entrySet().iterator();
Map.Entry entry;
while(it.hasNext()){
entry=(Entry) it.next();
sct.setEL(KeyImpl.toKey(entry.getKey()), entry.getValue());
}
}
if(!StringUtil.isEmpty(icfc.hint,true))sct.set(KeyConstants._hint,icfc.hint);
if(!StringUtil.isEmpty(icfc.dspName,true))sct.set(KeyConstants._displayname,icfc.dspName);
//init(pc,icfc);
if(!ArrayUtil.isEmpty(icfc.extend)){
Set<String> _set = lucee.runtime.type.util.ListUtil.listToSet(icfc.strExtend,',',true);
Struct ex=new StructImpl();
sct.set(KeyConstants._extends,ex);
Iterator<InterfaceImpl> it = icfc.extend.iterator();
InterfaceImpl inter;
while(it.hasNext()) {
inter = it.next();
if(!_set.contains(inter.getCallPath())) continue;
ex.setEL(KeyImpl.init(inter.getCallPath()),_getMetaData(pc,inter,true));
}
}
if(arr.size()!=0)sct.set(KeyConstants._functions,arr);
PageSource ps = icfc.pageSource;
sct.set(KeyConstants._name,ps.getComponentName());
sct.set(KeyConstants._fullname,ps.getComponentName());
sct.set(KeyConstants._path,ps.getDisplayPath());
sct.set(KeyConstants._type,"interface");
page.metaData=new MetaDataSoftReference<Struct>(sct,creationTime);
return sct;
}
@Override
public Variables beforeStaticConstructor(PageContext pc){
return null;
}
@Override
public void afterStaticConstructor(PageContext pc, Variables var){
}
public Iterator<UDF> getUDFIt() {
return udfs.values().iterator();
}
}