/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * 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.type; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import lucee.commons.digest.Hash; import lucee.commons.lang.CFTypes; import lucee.commons.lang.ExceptionUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.Component; import lucee.runtime.PageContext; import lucee.runtime.PageSource; import lucee.runtime.component.MemberSupport; import lucee.runtime.config.Config; import lucee.runtime.config.ConfigImpl; import lucee.runtime.dump.DumpData; import lucee.runtime.dump.DumpProperties; import lucee.runtime.dump.DumpTable; import lucee.runtime.exp.ApplicationException; import lucee.runtime.exp.ExpressionException; import lucee.runtime.exp.PageException; import lucee.runtime.interpreter.ref.Ref; import lucee.runtime.interpreter.ref.cast.Casting; import lucee.runtime.interpreter.ref.func.BIFCall; import lucee.runtime.interpreter.ref.literal.LFunctionValue; import lucee.runtime.interpreter.ref.literal.LString; import lucee.runtime.type.Collection.Key; import lucee.runtime.type.util.ArrayUtil; import lucee.runtime.type.util.CollectionUtil; import lucee.runtime.type.util.UDFUtil; import lucee.transformer.library.function.FunctionLib; import lucee.transformer.library.function.FunctionLibFunction; import lucee.transformer.library.function.FunctionLibFunctionArg; public class BIF extends MemberSupport implements UDFPlus { private final FunctionLibFunction flf; private short rtnType=CFTypes.TYPE_UNKNOW; private Component owner; private final ConfigImpl ci; private FunctionArgument[] args; private String id; public BIF(PageContext pc,String name) throws ApplicationException{ super(Component.ACCESS_PUBLIC); ci=(ConfigImpl) pc.getConfig(); FunctionLib fl = ci.getCombinedFLDs(pc.getCurrentTemplateDialect()); flf = fl.getFunction(name); // BIF not found if(flf==null) { Key[] keys = CollectionUtil.toKeys(fl.getFunctions().keySet()); throw new ApplicationException(ExceptionUtil.similarKeyMessage(keys, name, "build in function", "build in functions",null, false)); } try { this.id=Hash.md5(name); } catch (NoSuchAlgorithmException e) { this.id=name; } } public BIF(Config config, FunctionLibFunction flf) { super(Component.ACCESS_PUBLIC); ci=(ConfigImpl) config; this.flf=flf; } @Override public FunctionArgument[] getFunctionArguments() { if(args==null) { ArrayList<FunctionLibFunctionArg> src = flf.getArg(); args = new FunctionArgument[src.size()]; String def; int index=-1; FunctionLibFunctionArg arg; Iterator<FunctionLibFunctionArg> it = src.iterator(); while(it.hasNext()){ arg = it.next(); def = arg.getDefaultValue(); args[++index]=new FunctionArgumentImpl( KeyImpl.init(arg.getName()) , arg.getTypeAsString() , arg.getType() , arg.getRequired() , def==null?FunctionArgument.DEFAULT_TYPE_NULL:FunctionArgument.DEFAULT_TYPE_LITERAL , true , arg.getName() , arg.getDescription() , null); } } return args; } @Override public Object callWithNamedValues(PageContext pageContext, Struct values, boolean doIncludePath) throws PageException { ArrayList<FunctionLibFunctionArg> flfas = flf.getArg(); Iterator<FunctionLibFunctionArg> it = flfas.iterator(); FunctionLibFunctionArg arg; Object val; List<Ref> refs=new ArrayList<Ref>(); while(it.hasNext()){ arg=it.next(); // match by name val = values.get(arg.getName(),null); //match by alias if(val==null) { String alias=arg.getAlias(); if(!StringUtil.isEmpty(alias,true)) { String[] aliases = lucee.runtime.type.util.ListUtil.trimItems(lucee.runtime.type.util.ListUtil.listToStringArray(alias,',')); for(int x=0;x<aliases.length;x++){ val = values.get(aliases[x],null); if(val!=null) break; } } } if(val==null) { if(arg.getRequired()) { String[] names = flf.getMemberNames(); String n=ArrayUtil.isEmpty(names)?"":names[0]; throw new ExpressionException("missing required argument ["+arg.getName()+"] for build in function call ["+n+"]"); } } else{ refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),val))); } } BIFCall call=new BIFCall(flf, refs.toArray(new Ref[refs.size()])); return call.getValue(pageContext); } @Override public Object call(PageContext pageContext, Object[] args, boolean doIncludePath) throws PageException { ArrayList<FunctionLibFunctionArg> flfas = flf.getArg(); FunctionLibFunctionArg flfa; List<Ref> refs=new ArrayList<Ref>(); for(int i=0;i<args.length;i++){ if(i>=flfas.size()) throw new ApplicationException("too many Attributes in function call ["+flf.getName()+"]"); flfa=flfas.get(i); refs.add(new Casting(flfa.getTypeAsString(),flfa.getType(),args[i])); } BIFCall call=new BIFCall(flf, refs.toArray(new Ref[refs.size()])); return call.getValue(pageContext); } @Override public Object callWithNamedValues(PageContext pageContext, Key calledName, Struct values, boolean doIncludePath) throws PageException { return callWithNamedValues(pageContext, values, doIncludePath); } @Override public Object call(PageContext pageContext, Key calledName, Object[] args, boolean doIncludePath) throws PageException { return call(pageContext, args, doIncludePath); } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { DumpTable dt= (DumpTable) UDFUtil.toDumpData(pageContext, maxlevel, dp,this,UDFUtil.TYPE_BIF); //dt.setTitle(title); return dt; } @Override public UDF duplicate() { return new BIF(ci, flf); } @Override public Object duplicate(boolean deepCopy) { return duplicate(); } @Override public Component getOwnerComponent() { return owner; } @Override public String getDisplayName() { return flf.getName(); } @Override public String getHint() { return flf.getDescription(); } @Override public String getFunctionName() { return flf.getName(); } @Override public int getReturnType() { if(rtnType==CFTypes.TYPE_UNKNOW) rtnType=CFTypes.toShort(flf.getReturnTypeAsString(), false, CFTypes.TYPE_UNKNOW); return rtnType; } @Override public String getDescription() { return flf.getDescription(); } @Override public void setOwnerComponent(Component owner) { this.owner=owner; } @Override public int getReturnFormat(int defaultFormat) { return getReturnFormat(); } @Override public int getReturnFormat() { return UDF.RETURN_FORMAT_WDDX; } @Override public String getReturnTypeAsString() { return flf.getReturnTypeAsString(); } @Override public Object getValue() { return this; } @Override public boolean getOutput() { return false; } @Override public Object getDefaultValue(PageContext pc, int index) throws PageException { return null; } @Override public Boolean getSecureJson() { return null; } @Override public Boolean getVerifyClient() { return null; } /*@Override public PageSource getPageSource() { return null; }*/ @Override public boolean equals(Object other) { if(!(other instanceof UDF)) return false; return UDFImpl.equals(this, (UDF) other); } @Override public String id() { return id; } @Override public String getSource() { return ""; } @Override public int getIndex() { return -1; } @Override public Object getDefaultValue(PageContext pc, int index, Object defaultValue) throws PageException { return null; } // MUST @Override public Struct getMetaData(PageContext pc) throws PageException { // TODO Auto-generated method stub return new StructImpl(); } @Override public Object implementation(PageContext pageContext) throws Throwable { // TODO Auto-generated method stub return null; } @Override public PageSource getPageSource() { // TODO Auto-generated method stub return null; } @Override public boolean getBufferOutput(PageContext pc) { return pc.getApplicationContext().getBufferOutput(); } }