package org.geotoolkit.filter.function;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.util.iso.SimpleInternationalString;
import org.geotoolkit.internal.simple.SimpleParameterDescriptor;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.util.InternationalString;
/**
* Abstract function factory.
* Expects Function classes to have a constructors only with Expressions.
* Function may declare there parameters with a static variable called DESCRIPTOR instance of OperationType.
* If the descriptor is not found a generic one will be created from the constructor number of parameters.
*
* @author Johann Sorel (Geomatys)
*/
public class AbstractFunctionFactory implements FunctionFactory{
private final String identifier;
private final Map<String,Class> functions;
private final String[] names;
public AbstractFunctionFactory(String identifier, Map<String, Class> functions) {
this.identifier = identifier;
this.functions = functions;
this.names = functions.keySet().toArray(new String[0]);
}
@Override
public String getIdentifier() {
return identifier;
}
@Override
public String[] getNames() {
return names;
}
@Override
public Function createFunction(String name, Literal fallback, Expression... parameters) throws IllegalArgumentException {
final Class clazz = functions.get(name);
if(clazz == null){
throw new IllegalArgumentException("Unknowed function name : "+ name);
}
final Constructor construct = clazz.getConstructors()[0];
final Object[] cstParams = new Object[construct.getParameterTypes().length];
for(int i=0;i<cstParams.length;i++){
cstParams[i] = parameters[i];
}
try {
return (Function) construct.newInstance(cstParams);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
throw new IllegalArgumentException("Failed to initialize function wih given parameters : "+ name + " "+ex.getMessage(),ex);
}
}
@Override
public ParameterDescriptorGroup describeFunction(String name) throws IllegalArgumentException {
final Class clazz = functions.get(name);
if(clazz == null){
throw new IllegalArgumentException("Unknowed function name : "+ name);
}
return getDescription(name,clazz);
}
private static ParameterDescriptorGroup getDescription(String name, Class clazz){
final String baseName = clazz.getName().replace('.', '_');
InternationalString description;
final List<GeneralParameterDescriptor> args = new ArrayList<>();
try {
Short key = (Short) Bundle.Keys.class.getDeclaredField(baseName+"_description").get(null);
description = Bundle.formatInternational(key);
} catch (Exception ex) {
description = new SimpleInternationalString(clazz.getSimpleName());
}
for(int i=0;;i++){
try {
final Short key = (Short) Bundle.Keys.class.getDeclaredField(baseName+"_arg"+i).get(null);
final InternationalString argDesc = Bundle.formatInternational(key);
final ParameterBuilder params = new ParameterBuilder();
params.addName("arg"+i);
params.setRemarks(argDesc);
args.add(params.create(Object.class, null));
} catch (Exception ex) {
break;
}
}
if(args.isEmpty()){
//use reflection
try{
final Constructor construct = clazz.getConstructors()[0];
final GeneralParameterDescriptor[] cstParams = new GeneralParameterDescriptor[construct.getParameterTypes().length];
for(int i=0;i<cstParams.length;i++){
args.add(new SimpleParameterDescriptor(Object.class, "", "param"+(i+1)));
}
}catch(Exception ex){
}catch(Error ex){
}
}
final GeneralParameterDescriptor[] cstParams = new GeneralParameterDescriptor[args.size()];
args.toArray(cstParams);
final ParameterBuilder params = new ParameterBuilder();
params.addName(name);
params.setRemarks(description);
try{
return params.createGroup(cstParams);
}catch(Exception ex){
return new ParameterBuilder().addName(name).createGroup();
}
}
}