/* * 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: * 1Spatial PLC <http://www.1spatial.com> * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package com.onespatial.jrc.tns.oml_to_rif.digest; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.onespatial.jrc.tns.oml_to_rif.HaleAlignment; import com.onespatial.jrc.tns.oml_to_rif.api.AbstractFollowableTranslator; import com.onespatial.jrc.tns.oml_to_rif.api.TranslationException; import com.onespatial.jrc.tns.oml_to_rif.model.alignment.ModelAlignment; import com.onespatial.jrc.tns.oml_to_rif.model.alignment.ModelAttributeMappingCell; import com.onespatial.jrc.tns.oml_to_rif.model.alignment.ModelClassMappingCell; import com.onespatial.jrc.tns.oml_to_rif.model.alignment.ModelStaticAssignmentCell; import com.onespatial.jrc.tns.oml_to_rif.schema.GmlAttribute; import com.onespatial.jrc.tns.oml_to_rif.schema.GmlAttributePath; import eu.esdihumboldt.commons.goml.align.Alignment; import eu.esdihumboldt.commons.goml.omwg.ComposedProperty; import eu.esdihumboldt.commons.goml.omwg.FeatureClass; import eu.esdihumboldt.commons.goml.omwg.Property; import eu.esdihumboldt.commons.goml.omwg.Restriction; import eu.esdihumboldt.commons.goml.rdf.DetailedAbout; import eu.esdihumboldt.commons.goml.rdf.IDetailedAbout; import eu.esdihumboldt.cst.corefunctions.ConstantValueFunction; import eu.esdihumboldt.cst.corefunctions.NilReasonFunction; import eu.esdihumboldt.cst.corefunctions.RenameAttributeFunction; import eu.esdihumboldt.hale.schemaprovider.model.AttributeDefinition; import eu.esdihumboldt.hale.schemaprovider.model.SchemaElement; import eu.esdihumboldt.hale.schemaprovider.model.TypeDefinition; import eu.esdihumboldt.hale.ui.io.legacy.mappingexport.MappingExportReport; import eu.esdihumboldt.specification.cst.align.ICell; import eu.esdihumboldt.specification.cst.align.IEntity; import eu.esdihumboldt.specification.cst.align.ext.IParameter; /** * Alignment to model alignment digester. * * @author Simon Payne (Simon.Payne@1spatial.com) / 1Spatial Group Ltd. * @author Richard Sunderland (Richard.Sunderland@1spatial.com) / 1Spatial Group Ltd. * @author Simon Templer / Fraunhofer IGD */ public class AlignmentToModelAlignmentDigester extends AbstractFollowableTranslator<HaleAlignment, ModelAlignment> { private final MappingExportReport report; /** * Constructor * * @param report the export report */ public AlignmentToModelAlignmentDigester(MappingExportReport report) { super(); this.report = report; } /** * Translates a {@link HaleAlignment} into an intermediate * {@link ModelAlignment} format. * * @param hal the HALE alignment * @return {@link ModelAlignment} * @throws TranslationException * if any problems occurred during translation */ @Override public ModelAlignment translate(HaleAlignment hal) throws TranslationException { List<ModelClassMappingCell> classMappings = new ArrayList<ModelClassMappingCell>(); List<ModelAttributeMappingCell> attributeMappings = new ArrayList<ModelAttributeMappingCell>(); ArrayList<ModelStaticAssignmentCell> staticAssigments = new ArrayList<ModelStaticAssignmentCell>(); Alignment source = hal.getAlignment(); Map<String, SchemaElement> sourceFeatures = hal.getSourceElements(); Map<String, SchemaElement> targetFeatures = hal.getTargetElements(); for (ICell cell : source.getMap()) { IEntity sourceEntity = cell.getEntity1(); IEntity targetEntity = cell.getEntity2(); boolean sourceIsFeatureClass = sourceEntity instanceof FeatureClass; boolean targetIsFeatureClass = targetEntity instanceof FeatureClass; if (sourceIsFeatureClass && targetIsFeatureClass) { // type mapping classMappings.add(createCell((FeatureClass) sourceEntity, (FeatureClass) targetEntity, sourceFeatures, targetFeatures)); } else if (!sourceIsFeatureClass && !targetIsFeatureClass) { // property mapping ModelAttributeMappingCell modelCell = createAttribute(cell, (Property) sourceEntity, (Property) targetEntity, sourceFeatures, targetFeatures); if (modelCell != null) { attributeMappings.add(modelCell); } } else if (sourceIsFeatureClass && !targetIsFeatureClass) { // augmentations ModelStaticAssignmentCell modelCell = createStaticAssignment(cell, (Property) targetEntity, targetFeatures); if (modelCell != null) { staticAssigments.add(modelCell); } } else { throw new TranslationException("Unhandled combination"); //$NON-NLS-1$ } } return new ModelAlignment(classMappings, attributeMappings, staticAssigments); } private ModelStaticAssignmentCell createStaticAssignment(ICell original, Property targetEntity, Map<String, SchemaElement> targetFeatures) { String function = targetEntity.getTransformation().getService().getLocation(); if (ConstantValueFunction.class.getName().equals(function)) { // constant value String content = null; for (IParameter param : targetEntity.getTransformation().getParameters()) { if (param.getName().equals(ConstantValueFunction.DEFAULT_VALUE_PARAMETER_NAME)) { content = param.getValue(); break; } } IDetailedAbout targetAbout = DetailedAbout.getDetailedAbout(targetEntity.getAbout(), true); try { return new ModelStaticAssignmentCell( createAttributePath(targetAbout, targetFeatures), content); } catch (TranslationException e) { report.setFailed(original, e.getMessage()); return null; } } else if (NilReasonFunction.class.getName().equals(function)) { // nil reason String reason = null; for (IParameter param : targetEntity.getTransformation().getParameters()) { if (param.getName().equals(NilReasonFunction.PARAMETER_NIL_REASON_TYPE)) { reason = param.getValue(); break; } } report.setWarning(original, "The nil reason will be set regardless of whether a value for its parent is set or not"); //$NON-NLS-1$ IDetailedAbout targetAbout = DetailedAbout.getDetailedAbout(targetEntity.getAbout(), true); List<String> properties = new ArrayList<String>(targetAbout.getProperties()); properties.add("nilReason"); //XXX this is an attribute does it make any difference? //$NON-NLS-1$ targetAbout = new DetailedAbout(targetAbout.getNamespace(), targetAbout.getFeatureClass(), properties); try { return new ModelStaticAssignmentCell( createAttributePath(targetAbout, targetFeatures), reason); } catch (TranslationException e) { report.setFailed(original, e.getMessage()); return null; } } else { // not supported report.setFailed(original, "Only default value augmentations supported"); //$NON-NLS-1$ return null; } } private ModelAttributeMappingCell createAttribute(ICell original, Property sourceEntity, Property targetEntity, Map<String, SchemaElement> sourceFeatures, Map<String, SchemaElement> targetFeatures) { //FIXME what about composed properties? if (sourceEntity instanceof ComposedProperty || targetEntity instanceof ComposedProperty) { report.setFailed(original, "Composed properties not supported"); //$NON-NLS-1$ return null; } List<FeatureClass> filter = sourceEntity.getDomainRestriction(); if (filter != null && !filter.isEmpty()) { report.setWarning(original, "Filters on attributive functions currently not supported in the RIF export"); //$NON-NLS-1$ } String function = sourceEntity.getTransformation().getService().getLocation(); if (!RenameAttributeFunction.class.getName().equals(function)) { report.setWarning(original, "Function " + function + " not recognized"); //$NON-NLS-1$ //$NON-NLS-2$ } IDetailedAbout sourceAbout = DetailedAbout.getDetailedAbout(sourceEntity.getAbout(), true); IDetailedAbout targetAbout = DetailedAbout.getDetailedAbout(targetEntity.getAbout(), true); try { return new ModelAttributeMappingCell( createAttributePath(sourceAbout, sourceFeatures), createAttributePath(targetAbout, targetFeatures)); } catch (TranslationException e) { report.setFailed(original, e.getMessage()); return null; } } /** * Create an attribute path from an {@link IDetailedAbout} * * @param about the about * @param elements the available elements * @return the attribute path * @throws TranslationException if the attribute path cannot be resolved */ private static GmlAttributePath createAttributePath( IDetailedAbout about, Map<String, SchemaElement> elements) throws TranslationException { GmlAttributePath binding = new GmlAttributePath(); // get the parent class for the entity SchemaElement entityParent = elements.get(about.getNamespace() + "/" + about.getFeatureClass()); //$NON-NLS-1$ if (entityParent == null) { throw new TranslationException("Element " + about.getFeatureClass() + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ } TypeDefinition type = entityParent.getType(); List<String> nestedParts = about.getProperties(); for (String attributeName : nestedParts) { AttributeDefinition attDef = type.getAttribute(attributeName); if (attDef == null) { throw new TranslationException("Attribute " + attributeName + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ } GmlAttribute attribute = new GmlAttribute(attDef); binding.add(attribute); type = attDef.getAttributeType(); } return binding; } private ModelClassMappingCell createCell(FeatureClass sourceEntity, FeatureClass targetEntity, Map<String, SchemaElement> sourceFeatures, Map<String, SchemaElement> targetFeatures) throws TranslationException { return new ModelClassMappingCell(findFeatureElementDecl(sourceEntity, sourceFeatures), findFeatureElementDecl(targetEntity, targetFeatures), findFilter(sourceEntity)); } private List<Restriction> findFilter(FeatureClass sourceEntity) { List<Restriction> result = sourceEntity.getAttributeValueCondition(); return (result == null)?(new ArrayList<Restriction>()):(result); } private SchemaElement findFeatureElementDecl(FeatureClass entity, Map<String, SchemaElement> nameToFeatureMap) { String featureName = entity.getAbout().getAbout(); SchemaElement result = nameToFeatureMap.get(featureName); return result; } }