package org.openflexo.antar.binding; import org.openflexo.antar.binding.AbstractBinding.BindingEvaluationContext; import org.openflexo.antar.binding.BindingDefinition.BindingDefinitionType; import org.openflexo.antar.expr.BindingValueAsExpression; import org.openflexo.antar.expr.BindingValueAsExpression.AbstractBindingPathElement; import org.openflexo.antar.expr.BindingValueAsExpression.NormalBindingPathElement; import org.openflexo.antar.expr.DefaultExpressionParser; import org.openflexo.antar.expr.Expression; import org.openflexo.antar.expr.ExpressionTransformer; import org.openflexo.antar.expr.NullReferenceException; import org.openflexo.antar.expr.TransformException; import org.openflexo.antar.expr.TypeMismatchException; import org.openflexo.antar.expr.parser.ExpressionParser; import org.openflexo.antar.expr.parser.ParseException; /** * Utility class allowing to compute binding value over an expression and a given object.<br> * Expression must be expressed with or without supplied object (when mentioned, use "object." prefix).<br> * Considering we are passing a String, valid binding path are for example: * <ul> * <li>toString</li> * <li>toString()</li> * <li>toString()+' hash='+object.hashCode()</li> * <li>substring(6,11)</li> * <li>substring(3,length()-2)+' hash='+hashCode()</li> * </ul> * * @author sylvain * */ public class BindingEvaluator implements Bindable, BindingEvaluationContext { private static final DefaultBindingFactory BINDING_FACTORY = new DefaultBindingFactory(); private Object object; private BindingDefinition bindingDefinition; private BindingModel bindingModel; private BindingEvaluator(Object object) { this.object = object; bindingDefinition = new BindingDefinition("object", object.getClass(), BindingDefinitionType.GET, true); bindingModel = new BindingModel(); bindingModel.addToBindingVariables(new BindingVariableImpl(this, "object", object.getClass())); } private static String normalizeBindingPath(String bindingPath) { DefaultExpressionParser parser = new DefaultExpressionParser(); Expression expression = null; try { expression = ExpressionParser.parse(bindingPath); expression = expression.transform(new ExpressionTransformer() { @Override public Expression performTransformation(Expression e) throws TransformException { if (e instanceof BindingValueAsExpression) { BindingValueAsExpression bv = (BindingValueAsExpression) e; if (bv.getBindingPath().size() > 0) { AbstractBindingPathElement firstPathElement = bv.getBindingPath().get(0); if (!(firstPathElement instanceof NormalBindingPathElement) || !((NormalBindingPathElement) firstPathElement).property.equals("object")) { bv.getBindingPath().add(0, new NormalBindingPathElement("object")); } } return bv; } return e; } }); return expression.toString(); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TransformException e) { // TODO Auto-generated catch block e.printStackTrace(); } return expression.toString(); } @Override public BindingModel getBindingModel() { return bindingModel; } @Override public BindingFactory getBindingFactory() { return BINDING_FACTORY; } @Override public Object getValue(BindingVariable variable) { return object; } private Object evaluate(String bindingPath) throws InvalidKeyValuePropertyException, TypeMismatchException, NullReferenceException { String normalizedBindingPath = normalizeBindingPath(bindingPath); System.out.println("Normalize " + bindingPath + " to " + normalizedBindingPath); AbstractBinding binding = BINDING_FACTORY.convertFromString(normalizedBindingPath, this); binding.setBindingDefinition(bindingDefinition); System.out.println("Binding = " + binding + " valid=" + binding.isBindingValid() + " as " + binding.getClass()); if (!binding.isBindingValid()) { System.out.println("not valid: " + binding.invalidBindingReason()); throw new InvalidKeyValuePropertyException("Cannot interpret " + normalizedBindingPath + " for object of type " + object.getClass()); } return binding.getBindingValue(this); } public static Object evaluateBinding(String bindingPath, Object object) throws InvalidKeyValuePropertyException, TypeMismatchException, NullReferenceException { BindingEvaluator evaluator = new BindingEvaluator(object); return evaluator.evaluate(bindingPath); } public static void main(String[] args) { String thisIsATest = "Hello world, this is a test"; try { System.out.println(evaluateBinding("toString", thisIsATest)); System.out.println(evaluateBinding("toString()", thisIsATest)); System.out.println(evaluateBinding("toString()+' hash='+object.hashCode()", thisIsATest)); System.out.println(evaluateBinding("substring(6,11)", thisIsATest)); System.out.println(evaluateBinding("substring(3,length()-2)+' hash='+hashCode()", thisIsATest)); } catch (InvalidKeyValuePropertyException e) { e.printStackTrace(); } catch (TypeMismatchException e) { e.printStackTrace(); } catch (NullReferenceException e) { e.printStackTrace(); } } }