/* * Copyright (c) 2014 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.common.schema.model.constraint.factory; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import org.w3c.dom.Element; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import eu.esdihumboldt.hale.common.core.io.DOMValueUtil; import eu.esdihumboldt.hale.common.core.io.Value; import eu.esdihumboldt.hale.common.schema.model.Definition; import eu.esdihumboldt.hale.common.schema.model.GroupPropertyConstraint; import eu.esdihumboldt.hale.common.schema.model.PropertyConstraint; import eu.esdihumboldt.hale.common.schema.model.TypeConstraint; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; import eu.esdihumboldt.hale.common.schema.model.constraint.ConstraintUtil; import eu.esdihumboldt.hale.common.schema.model.constraint.factory.extension.ValueConstraintExtension; import eu.esdihumboldt.hale.common.schema.model.constraint.factory.extension.ValueConstraintFactoryDescriptor; import eu.esdihumboldt.hale.common.schema.model.impl.DefaultGroupPropertyDefinition; import eu.esdihumboldt.hale.common.schema.model.impl.DefaultPropertyDefinition; import eu.esdihumboldt.hale.common.schema.model.impl.DefaultTypeDefinition; import eu.esdihumboldt.hale.common.test.TestUtil; import eu.esdihumboldt.util.groovy.xml.NSDOMBuilder; import groovy.util.GroovyTestCase; /** * Base class for {@link ValueConstraintFactory} tests. * * @author Simon Templer * @param <T> the constraint type */ public abstract class AbstractValueConstraintFactoryTest<T> extends GroovyTestCase { private static final QName DEF_PROPERTY_TYPE_NAME = new QName("TestPropertyType"); private static final QName DEF_TYPE_NAME = new QName("TestType"); private static final QName DEF_NAME = new QName("test"); /** * Test storing a constraint, restoring it and compare both using an empty * type index and a default constraint definition. * * @param constraint the constraint to store * @throws Exception if an error occurs during storing, restoring or * comparing the constraint */ protected void storeRestoreTest(T constraint) throws Exception { storeRestoreTest(constraint, null, null); } /** * Test storing a constraint, restoring it and compare both. * * @param constraint the constraint to store * @param typeIndex the type index (as context for storing/restoring), * <code>null</code> for an empty index * @param constraintDef the definition the constraint is associated to (as * context for storing/restoring), for <code>null</code> the * method will try to generate a default definition based on the * constraint type * @throws Exception if an error occurs during storing, restoring or * comparing the constraint */ @SuppressWarnings("unchecked") protected void storeRestoreTest(T constraint, Map<TypeDefinition, Value> typeIndex, Definition<?> constraintDef) throws Exception { // conversion service may be needed for Value conversions TestUtil.startConversionService(); ValueConstraintFactoryDescriptor desc = ValueConstraintExtension.INSTANCE .getForConstraint(constraint); // provide defaults for null parameters if (typeIndex == null) { typeIndex = new HashMap<>(); } if (constraintDef == null) { constraintDef = getDefaultConstraintDefinition(constraint.getClass()); } @SuppressWarnings("rawtypes") ValueConstraintFactory factory = desc.getFactory(); Value val = factory.store(constraint, new MapTypeReferenceBuilder(typeIndex)); T read; if (val != null) { // to DOM NSDOMBuilder builder = NSDOMBuilder.newBuilder(new HashMap<String, String>()); Element elem = DOMValueUtil.valueTag(builder, "test", val); // from DOM Value res = DOMValueUtil.fromTag(elem); // bimap for reverse index BiMap<TypeDefinition, Value> types = HashBiMap.create(typeIndex); read = (T) factory.restore(res, constraintDef, new MapTypeResolver(types.inverse()), new OsgiClassResolver()); } else { // fall back to default constraint Class<?> constraintType = ConstraintUtil.getConstraintType(constraint.getClass()); read = (T) ConstraintUtil.getDefaultConstraint(constraintType, constraintDef); } compare(constraint, read); } /** * Create a default definition where the given constraint type is * applicable. This is decided on whether the constraint implements certain * (marker) interfaces. * * @param constraintType the constraint type * @return the default definition */ protected Definition<?> getDefaultConstraintDefinition(Class<?> constraintType) { TypeDefinition type = new DefaultTypeDefinition(DEF_TYPE_NAME); if (TypeConstraint.class.isAssignableFrom(constraintType)) { return type; } else if (PropertyConstraint.class.isAssignableFrom(constraintType)) { return new DefaultPropertyDefinition(DEF_NAME, type, new DefaultTypeDefinition(DEF_PROPERTY_TYPE_NAME)); } else if (GroupPropertyConstraint.class.isAssignableFrom(constraintType)) { return new DefaultGroupPropertyDefinition(DEF_NAME, type, false); } // fall back to type definition return type; } /** * Compare an original and restored constraint. Should throw an exception or * error if the constraints are not equal. * * @param org the original constraint * @param restored the restored constraint * @throws Exception if the constraints are not equal */ protected abstract void compare(T org, T restored) throws Exception; }