/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.common.definition.editors; import java.util.Objects; import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; import eu.esdihumboldt.hale.common.align.model.ParameterValue; import eu.esdihumboldt.hale.common.core.HalePlatform; import eu.esdihumboldt.hale.common.core.io.util.VariableReplacer; import eu.esdihumboldt.hale.ui.common.editors.AbstractAttributeEditor; /** * Abstract editor that is based on a binding and a validator. Expects the input * to happen with strings. * * @author Kai Schwierczek * @param <T> the attribute value type/binding */ public abstract class AbstractBindingValidatingEditor<T> extends AbstractAttributeEditor<T> { private final ConversionService cs = HalePlatform.getService(ConversionService.class); private final Class<? extends T> binding; private String stringValue; private T objectValue; private boolean validated = false; private String validationResult; private boolean inaccurateConversion = false; /** * Constructor with the binding class. * * @param binding the binding class */ public AbstractBindingValidatingEditor(Class<? extends T> binding) { this.binding = binding; } /** * Updates the local value, valid status and fires necessary events. * * @param newValue the new value * @return the validation result string, <code>null</code> if everything was * okay, otherwise the error text */ protected String valueChanged(String newValue) { // get old status boolean oldValid = isValid(); T oldObjectValue = objectValue; // set new value and validate stringValue = newValue; validate(); boolean newValid = isValid(); // fire events // XXX currently fire events with object value fireValueChanged(VALUE, oldObjectValue, objectValue); if (oldValid != isValid()) { fireStateChanged(IS_VALID, oldValid, newValid); } return validationResult; } /** * Validates the current string value and sets validationResult.<br> * Also sets object result if possible and updates the ControlDecoration. */ private void validate() { validationResult = null; validated = true; String strValue = stringValue; // replace variable in string before passing it to validation VariableReplacer variableReplacer = getVariableReplacer(); if (variableReplacer != null) { try { strValue = variableReplacer.replaceVariables(strValue); } catch (Exception e) { validationResult = e.getLocalizedMessage(); objectValue = null; inaccurateConversion = true; return; } } // check binding first T objValue = null; try { // for example boolean converter returns null for empty string... objValue = cs.convert(strValue, binding); if (objValue == null) { validationResult = strValue + " cannot be converted to " + binding.getSimpleName(); } } catch (ConversionException ce) { objValue = null; validationResult = strValue + " cannot be converted to " + binding.getSimpleName(); } if (Objects.equals(stringValue, strValue)) { // accurate conversion objectValue = objValue; inaccurateConversion = false; } else { // conversion features replacement objectValue = objValue; inaccurateConversion = true; } // validators if (validationResult == null) { validationResult = additionalValidate(strValue, objValue); } } /** * Validates the given value. The returned string should be * <code>null</code> if the input validates, it should contain an error * message otherwise. <br> * The default implementation always returns <code>null</code>. * * @param stringValue the string value * @param objectValue the according to the binding converted string value * @return <code>null</code> or an error message */ protected String additionalValidate(String stringValue, T objectValue) { return null; } @Override public void setValue(T value) { setAsText(cs.convert(value, String.class)); } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#getValue() * * @throws IllegalStateException if the current input is not valid */ @Override public T getValue() { if (isValid()) return objectValue; else throw new IllegalStateException(); } @Override public String getAsText() { if (isValid()) { if (!inaccurateConversion) { // return converted value, as that SHOULD be XML conform // in contrast to input value where the converter maybe allows // more. return cs.convert(objectValue, String.class); } else { // return value including variables to be replaced return stringValue; } } else return stringValue; } @Override public boolean isValid() { if (!validated) validate(); return validationResult == null; } @Override public String getValueType() { return ParameterValue.DEFAULT_TYPE; } }