/* * Copyright (c) 2015 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.io.xsd.anytype; import java.util.LinkedList; import java.util.List; import javax.xml.namespace.QName; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.common.schema.model.ChildDefinition; import eu.esdihumboldt.hale.common.schema.model.Definition; import eu.esdihumboldt.hale.common.schema.model.DefinitionGroup; import eu.esdihumboldt.hale.common.schema.model.DefinitionUtil; import eu.esdihumboldt.hale.common.schema.model.PropertyDefinition; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; import eu.esdihumboldt.hale.common.schema.model.constraint.DisplayName; import eu.esdihumboldt.hale.common.schema.model.constraint.property.Cardinality; import eu.esdihumboldt.hale.common.schema.model.constraint.property.ChoiceFlag; import eu.esdihumboldt.hale.common.schema.model.constraint.property.NillableFlag; import eu.esdihumboldt.hale.common.schema.model.constraint.type.MappableFlag; 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.schema.model.impl.PropertyTypeOverrideProperty; import eu.esdihumboldt.hale.io.xsd.model.XmlElement; import eu.esdihumboldt.hale.io.xsd.model.XmlIndex; /** * Helper methods for custom type content. * * @author Simon Templer */ public class CustomTypeContentHelper { private static final ALogger log = ALoggerFactory.getLogger(CustomTypeContentHelper.class); /** * Apply custom type configurations to the given schema. * * @param index the XML schema * @param config the custom type configurations */ public static void applyConfigurations(XmlIndex index, CustomTypeContentConfiguration config) { for (CustomTypeContentAssociation assoc : config.getAssociations()) { applyConfiguration(index, assoc); } } /** * Apply a custom type configuration to the given schema. * * @param index the XML schema * @param association the custom type configuration for an individual * property */ public static void applyConfiguration(XmlIndex index, CustomTypeContentAssociation association) { CustomTypeContent config = association.getConfig(); // property identified by a list of qualified names List<QName> property = association.getProperty(); PropertyDefinition propDef = null; DefinitionGroup propParent = null; if (property != null && property.size() > 1) { QName typeName = property.get(0); TypeDefinition type = index.getType(typeName); if (type != null) { LinkedList<QName> nameQueue = new LinkedList<>( property.subList(1, property.size())); Definition<?> parent = null; Definition<?> child = type; while (!nameQueue.isEmpty() && child != null) { parent = child; QName name = nameQueue.pollFirst(); child = DefinitionUtil.getChild(parent, name); } if (nameQueue.isEmpty() && child instanceof PropertyDefinition) { propDef = (PropertyDefinition) child; if (parent instanceof TypeDefinition) { propParent = (DefinitionGroup) parent; } else if (parent instanceof ChildDefinition<?>) { ChildDefinition<?> pc = (ChildDefinition<?>) parent; if (pc.asProperty() != null) { propParent = pc.asProperty().getPropertyType(); } else if (pc.asGroup() != null) { propParent = pc.asGroup(); } } else { log.error("Illegal parent for custom type content property"); return; } } else { log.warn( "Cannot apply custom type content configuration due to invalid property path"); return; } } else { log.warn( "Cannot apply custom type content configuration due because the type {} starting the property path could not be found", typeName); return; } } else { log.warn("Cannot apply custom type content configuration due to missing property path"); return; } switch (config.getMode()) { case simple: applySimpleMode(propDef, propParent, config); case elements: applyElementsMode(propDef, propParent, config, index); default: log.error("Unrecognized custom type content mode {}", config.getMode().name()); } } private static void applyElementsMode(PropertyDefinition propDef, DefinitionGroup propParent, CustomTypeContent config, XmlIndex index) { // build new property type based on config DefaultTypeDefinition type = new DefaultTypeDefinition( new QName(propDef.getIdentifier(), "customElementsContentType"), false); type.setConstraint(MappableFlag.DISABLED); DefaultGroupPropertyDefinition choice = new DefaultGroupPropertyDefinition( new QName(propDef.getIdentifier(), "customElementsContentChoice"), type, false); choice.setConstraint(new DisplayName("elements")); choice.setConstraint(ChoiceFlag.ENABLED); choice.setConstraint(Cardinality.CC_ANY_NUMBER); for (QName elementName : config.getElements()) { XmlElement element = index.getElements().get(elementName); if (element != null) { DefaultPropertyDefinition elementProp = new DefaultPropertyDefinition(elementName, choice, element.getType()); elementProp.setConstraint(Cardinality.CC_EXACTLY_ONCE); elementProp.setConstraint(NillableFlag.DISABLED); } else { log.error("Element {} could not be found when creating custom type content", elementName); } } replaceTypeForProperty(propDef, propParent, type); } @SuppressWarnings("unused") private static void applySimpleMode(PropertyDefinition propDef, DefinitionGroup propParent, CustomTypeContent config) { // XXX currently no modification needed // replaceTypeForProperty(propDef, propParent, type); } private static void replaceTypeForProperty(PropertyDefinition propDef, DefinitionGroup propParent, TypeDefinition newPropertyType) { PropertyDefinition newProperty; if (propDef instanceof PropertyTypeOverrideProperty) { newProperty = new PropertyTypeOverrideProperty( ((PropertyTypeOverrideProperty) propDef).getDecoratedProperty(), newPropertyType); } else { newProperty = new PropertyTypeOverrideProperty(propDef, newPropertyType); } if (propParent instanceof DefaultTypeDefinition) { DefaultTypeDefinition type = (DefaultTypeDefinition) propParent; type.overrideChild(newProperty); } // else if (propParent instanceof DefaultGroupPropertyDefinition) { // // TODO // } else { log.error( "Could not update custom content property because of unsupported parent definition group"); } } }