/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fib.model; import java.util.Iterator; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.antar.binding.AbstractBinding; import org.openflexo.antar.binding.AbstractBinding.BindingEvaluationContext; import org.openflexo.antar.binding.Bindable; import org.openflexo.antar.binding.BindingDefinition; import org.openflexo.antar.binding.BindingFactory; import org.openflexo.antar.expr.Expression; import org.openflexo.antar.expr.Function; import org.openflexo.antar.expr.NullReferenceException; import org.openflexo.antar.expr.TypeMismatchException; import org.openflexo.antar.expr.Variable; import org.openflexo.antar.expr.parser.ParseException; import org.openflexo.fib.model.FIBModelObject.FIBModelAttribute; import org.openflexo.toolbox.StringUtils; import org.openflexo.xmlcode.StringConvertable; import org.openflexo.xmlcode.StringEncoder.Converter; public class DataBinding implements StringConvertable<DataBinding> { private static final Logger logger = Logger.getLogger(FIBComponent.class.getPackage().getName()); public static DataBinding.DataBindingConverter CONVERTER = new DataBindingConverter(); public static class DataBindingConverter extends Converter<DataBinding> { public DataBindingConverter() { super(DataBinding.class); } @Override public DataBinding convertFromString(String value) { return new DataBinding(value); } @Override public String convertToString(DataBinding value) { return value.toString(); }; } @Override public Converter<? extends DataBinding> getConverter() { return CONVERTER; } private FIBModelObject owner; private FIBModelAttribute bindingAttribute; private String unparsedBinding; private BindingDefinition bindingDefinition; private AbstractBinding binding; // private Exception newIntanceException; public DataBinding(FIBModelObject owner, FIBModelAttribute attribute, BindingDefinition df) { // newIntanceException = new Exception("Create instance with owner "+owner); setOwner(owner); setBindingAttribute(attribute); setBindingDefinition(df); } public DataBinding(String unparsed) { // newIntanceException = new Exception("Create instance with "+unparsed); unparsedBinding = unparsed; } public Object execute(BindingEvaluationContext context) { return getBindingValue(context); } public Object getBindingValue(BindingEvaluationContext context) { // logger.info("getBindingValue() "+this); if (getBinding() != null) { try { return getBinding().getBindingValue(context); } catch (TypeMismatchException e) { return null; } catch (NullReferenceException e) { return null; } } return null; } public void setBindingValue(Object value, BindingEvaluationContext context) { if (getBinding() != null && getBinding().isSettable()) { getBinding().setBindingValue(value, context); } } @Override public String toString() { if (binding != null) { return binding.getStringRepresentation(); } return unparsedBinding; } public BindingDefinition getBindingDefinition() { return bindingDefinition; } public void setBindingDefinition(BindingDefinition bindingDefinition) { this.bindingDefinition = bindingDefinition; } public AbstractBinding getBinding() { if (binding == null) { finalizeDeserialization(); } return binding; } public AbstractBinding getBinding(boolean silentMode) { if (binding == null) { finalizeDeserialization(silentMode); } return binding; } /*public void setBinding(AbstractBinding binding) { this.binding = binding; }*/ public void setBinding(AbstractBinding value) { AbstractBinding oldValue = this.binding; if (oldValue == null) { if (value == null) { return; // No change } else { this.binding = value; unparsedBinding = value != null ? value.getStringRepresentation() : null; updateDependancies(); if (bindingAttribute != null) { owner.notify(new FIBAttributeNotification<AbstractBinding>(bindingAttribute, oldValue, value)); } owner.notifyBindingChanged(this); return; } } else { if (oldValue.equals(value)) { return; // No change } else { this.binding = value; unparsedBinding = value != null ? value.getStringRepresentation() : null; if (logger.isLoggable(Level.FINE)) { logger.fine("Binding takes now value " + value); } updateDependancies(); if (bindingAttribute != null) { owner.notify(new FIBAttributeNotification<AbstractBinding>(bindingAttribute, oldValue, value)); } owner.notifyBindingChanged(this); return; } } } public boolean hasBinding() { return binding != null; } public boolean isValid() { return getBinding() != null && getBinding().isBindingValid(); } public boolean isValid(boolean silentMode) { return getBinding(silentMode) != null && getBinding(silentMode).isBindingValid(); } public boolean isSet() { return unparsedBinding != null || binding != null; } public boolean isUnset() { return unparsedBinding == null && binding == null; } public String getUnparsedBinding() { return unparsedBinding; } public void setUnparsedBinding(String unparsedBinding) { this.unparsedBinding = unparsedBinding; binding = null; } public Bindable getBindable() { return getOwner(); } public BindingFactory getBindingFactory() { return getBindable().getBindingFactory(); } public FIBModelObject getOwner() { return owner; } public void setOwner(FIBModelObject owner) { this.owner = owner; } protected void finalizeDeserialization(boolean silentMode) { if (getUnparsedBinding() == null) { return; } /*if (getUnparsedBinding().equals("data.isAcceptableAsSubProcess(SubProcess.component.candidateValue)")) { System.out.println("finalizeDeserialization for "+getUnparsedBinding()); System.out.println("Owner: "+getOwner()+" of "+getOwner().getClass()); System.out.println("BindingModel: "+getOwner().getBindingModel()); }*/ // System.out.println("BindingModel: "+getOwner().getBindingModel()); if (getBindable() != null) { BindingFactory factory = getBindingFactory(); binding = factory.convertFromString(getUnparsedBinding(), getBindable()); binding.setBindingDefinition(getBindingDefinition()); // System.out.println(">>>>>>>>>>>>>> Binding: "+binding.getStringRepresentation()+" owner="+binding.getOwner()); // System.out.println("binding.isBindingValid()="+binding.isBindingValid()); } if (binding == null) { logger.warning("Unexpected null binding for [" + getUnparsedBinding() + "]"); } if (binding != null && !binding.isBindingValid()) { if (!silentMode) { logger.warning("Binding not valid: " + binding + " for owner " + getOwner() + " context=" + (getOwner() != null ? getOwner().getRootComponent() : null) + "reason=" + binding.invalidBindingReason()); // binding.debugIsBindingValid(); // Dev note: Uncomment following to get more informations // logger.warning("Binding not valid: " + binding + " for owner " + getOwner() + " context=" // + (getOwner() != null ? (getOwner()).getRootComponent() : null)); // logger.info("BindingModel=" + getOwner().getBindingModel()); // logger.info("BindingFactory=" + getOwner().getBindingFactory()); // binding.debugIsBindingValid(); // BindingExpression.logger.setLevel(Level.FINE); // binding = AbstractBinding.abstractBindingConverter.convertFromString(getUnparsedBinding()); // binding.setBindingDefinition(getBindingDefinition()); // binding.isBindingValid(); // (new Exception("prout")).printStackTrace(); // System.exit(-1); } } updateDependancies(); } protected void finalizeDeserialization() { finalizeDeserialization(true); if (owner != null && hasBinding() && isValid()) { owner.notifyBindingChanged(this); } } protected void updateDependancies() { if (getOwner() instanceof FIBComponent) { if (binding == null) { return; } Vector<Expression> primitives; try { primitives = Expression.extractPrimitives(binding.getStringRepresentation()); FIBComponent component = (FIBComponent) getOwner(); FIBComponent rootComponent = component.getRootComponent(); Iterator<FIBComponent> subComponents = rootComponent.subComponentIterator(); while (subComponents.hasNext()) { FIBComponent next = subComponents.next(); if (next != getOwner()) { if (next instanceof FIBWidget && ((FIBWidget) next).getData() != null && ((FIBWidget) next).getData().isSet()) { String data = ((FIBWidget) next).getData().toString(); if (data != null) { for (Expression p : primitives) { String primitiveValue = null; if (p instanceof Variable) { primitiveValue = ((Variable) p).getName(); } if (p instanceof Function) { primitiveValue = ((Function) p).getName(); } if (primitiveValue != null && primitiveValue.startsWith(data)) { // try { component.declareDependantOf(next); /*} catch (DependancyLoopException e) { logger.warning("DependancyLoopException raised while declaring dependancy (data lookup)" + "in the context of binding: " + binding.getStringRepresentation() + " primitive: " + primitiveValue + " component: " + component + " dependency: " + next + " data: " + data + " message: " + e.getMessage()); }*/ } } } } if (next.getName() != null) { for (Expression p : primitives) { String primitiveValue = null; if (p instanceof Variable) { primitiveValue = ((Variable) p).getName(); } if (p instanceof Function) { primitiveValue = ((Function) p).getName(); } if (primitiveValue != null && StringUtils.isNotEmpty(next.getName()) && primitiveValue.startsWith(next.getName())) { // try { component.declareDependantOf(next); /*} catch (DependancyLoopException e) { logger.warning("DependancyLoopException raised while declaring dependancy (name lookup)" + "in the context of binding: " + binding.getStringRepresentation() + " primitive: " + primitiveValue + " component: " + component + " dependency: " + next + " message: " + e.getMessage()); }*/ } } } } } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TypeMismatchException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public FIBModelAttribute getBindingAttribute() { return bindingAttribute; } public void setBindingAttribute(FIBModelAttribute bindingAttribute) { this.bindingAttribute = bindingAttribute; } }