/**
* 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.transformer.library.function;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import lucee.commons.lang.CFTypes;
import lucee.commons.lang.ClassException;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.Md5;
import lucee.commons.lang.StringUtil;
import lucee.runtime.config.Identification;
import lucee.runtime.db.ClassDefinition;
import lucee.runtime.exp.PageRuntimeException;
import lucee.runtime.exp.TemplateException;
import lucee.runtime.ext.function.BIF;
import lucee.runtime.functions.BIFProxy;
import lucee.runtime.op.Caster;
import lucee.runtime.osgi.OSGiUtil;
import lucee.runtime.reflection.Reflector;
import lucee.runtime.type.util.ListUtil;
import lucee.transformer.cfml.evaluator.FunctionEvaluator;
import lucee.transformer.library.ClassDefinitionImpl;
import lucee.transformer.library.tag.TagLib;
import org.osgi.framework.Version;
import org.xml.sax.Attributes;
/**
* Eine FunctionLibFunction repraesentiert eine einzelne Funktion innerhalb einer FLD.
*/
public final class FunctionLibFunction {
/**
* Dynamischer Argument Typ
*/
public static final int ARG_DYNAMIC = 0;
/**
* statischer Argument Typ
*/
public static final int ARG_FIX = 1;
private FunctionLib functionLib;
private String name;
private ArrayList<FunctionLibFunctionArg> argument=new ArrayList<FunctionLibFunctionArg>();
private int argMin=0;
private int argMax=-1;
private int argType=ARG_FIX;
private String strReturnType;
private ClassDefinition clazz;
private String description;
private boolean hasDefaultValues;
private FunctionEvaluator eval;
private ClassDefinition tteCD;
private short status=TagLib.STATUS_IMPLEMENTED;
private String[] memberNames;
private int memberPosition=1;
private short memberType=CFTypes.TYPE_UNKNOW;
private boolean memberChaining;
private BIF bif;
private String[] keywords;
private ClassDefinition functionCD;
private Version introduced;
private final boolean core;
/**
* Geschuetzer Konstruktor ohne Argumente.
*/
/*public FunctionLibFunction() {
this.core=false;
}*/
public FunctionLibFunction(boolean core) {
this.core=core;
}
public FunctionLibFunction(FunctionLib functionLib, boolean core) {
this.functionLib=functionLib;
this.core=core;
}
/**
* Gibt den Namen der Funktion zurueck.
* @return name Name der Funktion.
*/
public String getName() {
return name;
}
/**
* Gibt alle Argumente einer Funktion als ArrayList zurueck.
* @return Argumente der Funktion.
*/
public ArrayList<FunctionLibFunctionArg> getArg() {
return argument;
}
/**
* Gibt zurueck wieviele Argumente eine Funktion minimal haben muss.
* @return Minimale Anzahl Argumente der Funktion.
*/
public int getArgMin() {
return argMin;
}
/**
* Gibt zurueck wieviele Argumente eine Funktion minimal haben muss.
* @return Maximale Anzahl Argumente der Funktion.
*/
public int getArgMax() {
return argMax;
}
/**
* @return the status (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
*/
public short getStatus() {
return status;
}
/**
* @param status the status to set (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
*/
public void setStatus(short status) {
this.status = status;
}
/**
* Gibt die argument art zurueck.
* @return argument art
*/
public int getArgType() {
return argType;
}
/**
* Gibt die argument art als String zurueck.
* @return argument art
*/
public String getArgTypeAsString() {
if(argType==ARG_DYNAMIC) return "dynamic";
return "fixed";
}
/**
* Gibt zurueck von welchem Typ der Rueckgabewert dieser Funktion sein muss (query, string, struct, number usw.).
* @return Typ des Rueckgabewert.
*/
public String getReturnTypeAsString() {
return strReturnType;
}
/**
* Gibt die Klasse zurueck, welche diese Funktion implementiert.
* @return Klasse der Function.
* @throws ClassException
*/
public ClassDefinition getFunctionClassDefinition() {
return functionCD;
}
/**
* Gibt die Beschreibung der Funktion zurueck.
* @return String
*/
public String getDescription() {
return description;
}
/**
* Gibt die FunctionLib zurueck, zu der die Funktion gehoert.
* @return Zugehoerige FunctionLib.
*/
public FunctionLib getFunctionLib() {
return functionLib;
}
/**
* Setzt den Namen der Funktion.
* @param name Name der Funktion.
*/
public void setName(String name) {
this.name = name.toLowerCase();
}
/**
* Fuegt der Funktion ein Argument hinzu.
* @param arg Argument zur Funktion.
*/
public void addArg(FunctionLibFunctionArg arg) {
arg.setFunction(this);
argument.add(arg);
if(arg.getDefaultValue()!=null)
hasDefaultValues=true;
}
/**
* Fuegt der Funktion ein Argument hinzu, alias fuer addArg.
* @param arg Argument zur Funktion.
*/
public void setArg(FunctionLibFunctionArg arg) {
addArg(arg);
}
/**
* Setzt wieviele Argumente eine Funktion minimal haben muss.
* @param argMin Minimale Anzahl Argumente der Funktion.
*/
public void setArgMin(int argMin) {
this.argMin = argMin;
}
/**
* Setzt wieviele Argumente eine Funktion minimal haben muss.
* @param argMax Maximale Anzahl Argumente der Funktion.
*/
public void setArgMax(int argMax) {
this.argMax = argMax;
}
/**
* Setzt den Rueckgabewert der Funktion (query,array,string usw.)
* @param value
*/
public void setReturn(String value) {
strReturnType=value;
}
/**
* Setzt die Klassendefinition als Zeichenkette, welche diese Funktion implementiert.
* @param value Klassendefinition als Zeichenkette.
*/
public void setFunctionClass(String value,Identification id,Attributes attrs) {
functionCD=ClassDefinitionImpl.toClassDefinition(value,id, attrs);
}
/**
* Setzt die Beschreibung der Funktion.
* @param description Beschreibung der Funktion.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Setzt die zugehoerige FunctionLib.
* @param functionLib Zugehoerige FunctionLib.
*/
public void setFunctionLib(FunctionLib functionLib) {
this.functionLib=functionLib;
}
/**
* sets the argument type of the function
* @param argType
*/
public void setArgType(int argType) {
this.argType=argType;
}
public String getHash() {
StringBuilder sb=new StringBuilder();
sb.append(this.getArgMax());
sb.append(this.getArgMin());
sb.append(this.getArgType());
sb.append(this.getArgTypeAsString());
sb.append(getFunctionClassDefinition().toString());
sb.append(tteCD);
sb.append(this.getName());
sb.append(this.getReturnTypeAsString());
Iterator<FunctionLibFunctionArg> it = this.getArg().iterator();
FunctionLibFunctionArg arg;
while(it.hasNext()){
arg=it.next();
sb.append(arg.getHash());
}
try {
return Md5.getDigestAsString(sb.toString());
} catch (IOException e) {
return "";
}
}
public boolean hasDefaultValues() {
return hasDefaultValues;
}
public boolean hasTteClass() {
return tteCD !=null ;
}
public FunctionEvaluator getEvaluator() throws TemplateException {
if(!hasTteClass()) return null;
if(eval!=null) return eval;
try {
eval = (FunctionEvaluator) tteCD.getClazz().newInstance();
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
throw new TemplateException(t.getMessage());
}
return eval;
}
public void setTTEClass(String tteClass, Identification id,Attributes attrs) {
this.tteCD=ClassDefinitionImpl.toClassDefinition(tteClass,id,attrs);
}
public void setMemberName(String memberNames) {
if(StringUtil.isEmpty(memberNames,true)) return;
this.memberNames=ListUtil.trimItems(ListUtil.listToStringArray(memberNames, ','));
}
public String[] getMemberNames() {
return memberNames;
}
public void setKeywords(String keywords) {
this.keywords=ListUtil.trimItems(ListUtil.listToStringArray(keywords, ','));
}
public String[] getKeywords() {
return keywords;
}
public boolean isCore() {
return core;
}
public void setMemberPosition(int pos) {
this.memberPosition=pos;
}
public int getMemberPosition() {
return memberPosition;
}
public void setMemberChaining(boolean memberChaining) {
this.memberChaining=memberChaining;
}
public boolean getMemberChaining() {
return memberChaining;
}
public void setMemberType(String memberType) {
this.memberType=CFTypes.toShortStrict(memberType,CFTypes.TYPE_UNKNOW);
}
public short getMemberType() {
if(memberNames!=null && memberType==CFTypes.TYPE_UNKNOW){
ArrayList<FunctionLibFunctionArg> args = getArg();
if(args.size()>=1){
memberType=CFTypes.toShortStrict(args.get(getMemberPosition()-1).getTypeAsString(),CFTypes.TYPE_UNKNOW);
}
}
return memberType;
}
public String getMemberTypeAsString() {
return CFTypes.toString(getMemberType(),"any");
}
public BIF getBIF() {
if(bif!=null) return bif;
Class clazz=null;
try {
clazz = getFunctionClassDefinition().getClazz();
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
throw new PageRuntimeException(Caster.toPageException(t));
}
if(Reflector.isInstaneOf(clazz, BIF.class)) {
try {
bif=(BIF)clazz.newInstance();
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
throw new RuntimeException(t);
}
}
else {
return new BIFProxy(clazz);
}
return bif;
}
public void setIntroduced(String introduced) {
this.introduced=OSGiUtil.toVersion(introduced, null);
}
public Version getIntroduced() {
return introduced;
}
}