package nl.ipo.cds.admin.ba.attributemapping; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import nl.ipo.cds.admin.ba.controller.MappingParserException; import nl.ipo.cds.admin.ba.controller.beans.mapping.ConditionOperation; import nl.ipo.cds.admin.ba.controller.beans.mapping.InputAttribute; import nl.ipo.cds.admin.ba.controller.beans.mapping.Mapping; import nl.ipo.cds.admin.ba.controller.beans.mapping.Operation; import nl.ipo.cds.admin.ba.controller.beans.mapping.TransformOperation; import nl.ipo.cds.attributemapping.operations.OperationType; import nl.ipo.cds.dao.attributemapping.InputOperationDTO; import nl.ipo.cds.dao.attributemapping.OperationDTO; import nl.ipo.cds.dao.attributemapping.OperationInputDTO; import nl.ipo.cds.dao.attributemapping.TransformOperationDTO; import nl.ipo.cds.domain.AttributeType; import nl.ipo.cds.domain.FeatureType; import nl.ipo.cds.domain.FeatureTypeAttribute; import nl.ipo.cds.etl.operations.transform.ConditionalTransform; import nl.ipo.cds.etl.theme.AttributeDescriptor; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.core.convert.ConversionService; public class OperationFactory { private final AttributeDescriptor<?> attributeDescriptor; private final Collection<OperationType> operationTypes; private final FeatureType featureType; private final ConversionService conversionService; public OperationFactory (final AttributeDescriptor<?> attributeDescriptor, final Collection<OperationType> operationTypes, final FeatureType featureType, final ConversionService conversionService) { this.attributeDescriptor = attributeDescriptor; this.operationTypes = operationTypes; this.featureType = featureType; this.conversionService = conversionService; } public OperationDTO buildOperationCommand (final Mapping mapping) throws MappingParserException { final TransformOperationDTO conditionalCommand = buildConditionalTransformOperation (mapping.getOperations ()); final List<OperationInputDTO> inputs = new ArrayList<OperationInputDTO> (1); inputs.add (new OperationInputDTO (conditionalCommand)); return new TransformOperationDTO (attributeDescriptor, inputs, null); } public TransformOperationDTO buildConditionalTransformOperation (final List<Operation> operations) throws MappingParserException { final List<OperationInputDTO> inputs = new ArrayList<OperationInputDTO> (); final List<ConditionalTransform.Condition> conditions = new ArrayList<ConditionalTransform.Condition> (); // Build inputs and conditions: for (final Operation operation: operations) { if (!(operation instanceof ConditionOperation)) { throw new MappingParserException ("Expected condition operation"); } // Add the input: if (((ConditionOperation)operation).getOperationInputs ().size () != 0) { if (((ConditionOperation)operation).getOperationInputs ().size () > 1) { throw new MappingParserException ("Conditional operation has more than 1 input"); } inputs.add (buildInput (((ConditionOperation)operation).getOperationInputs ().get (0))); } else { inputs.add (new OperationInputDTO (null)); } // Add condition, if present: final Map<String, Object> settings = ((ConditionOperation)operation).getSettings (); if (settings == null) { continue; } if (!settings.containsKey ("attribute")) { continue; } if (!settings.containsKey ("operator") || settings.get ("operator") == null) { continue; } final String referenceAttributeName = settings.get ("attribute") == null ? null : settings.get ("attribute").toString (); final String operator = settings.get ("operator").toString (); final String value = settings.get ("value") == null ? null : settings.get ("value").toString (); final ConditionalTransform.Operation op = getConditionalOperation (operator); if (op == null) { throw new MappingParserException (String.format ("Unknown conditional operation: %s", operator)); } if ((op == ConditionalTransform.Operation.IN || op == ConditionalTransform.Operation.NOT_IN) && value == null) { throw new MappingParserException (String.format ("No value provided for conditional operation %s", operator)); } final ConditionalTransform.Condition condition = new ConditionalTransform.Condition (); condition.setAttribute (referenceAttributeName); condition.setOperation (op); condition.setValues (value == null ? new String[0] : new String[] { value }); conditions.add (condition); } // Validate the number of inputs: if (!(conditions.size () == 0 && inputs.size () == 0) && conditions.size () != inputs.size () - 1) { throw new MappingParserException (String.format ("The number of inputs does not match the number of conditions (%d conditions, %d inputs)", conditions.size (), inputs.size ())); } // Build a settings object: final ConditionalTransform.Settings settings = new ConditionalTransform.Settings (); settings.setConditions (conditions); return new TransformOperationDTO (getConditionalTransformOperationType (), inputs, settings); } public OperationInputDTO buildInput (final Operation operation) throws MappingParserException { if (operation == null) { return new OperationInputDTO (null); } else { return new OperationInputDTO (buildOperation (operation)); } } public OperationDTO buildOperation (final Operation operation) throws MappingParserException { if (operation instanceof InputAttribute) { return buildInputOperation ((InputAttribute)operation); } else { return buildTransformOperation ((TransformOperation)operation); } } public InputOperationDTO buildInputOperation (final InputAttribute inputAttribute) throws MappingParserException { final FeatureTypeAttribute attribute = getInputAttribute (featureType, inputAttribute.getName (), inputAttribute.getInputAttributeType ()); final AttributeType attributeType = AttributeType.fromString (inputAttribute.getInputAttributeType ()); if (attributeType == null) { throw new MappingParserException (String.format ("Attribute type not found: %s", inputAttribute.getInputAttributeType ())); } // attributeType is mandatory return new InputOperationDTO (attribute, inputAttribute.getName (), attribute != null ? attribute.getType () : attributeType); } public TransformOperationDTO buildTransformOperation (final TransformOperation transformOperation) throws MappingParserException { final OperationType operationType = getTransformOperationType (transformOperation.getName ()); final Object properties = buildOperationProperties (operationType, transformOperation.getSettings ()); final List<OperationInputDTO> inputs = new ArrayList<OperationInputDTO> (); for (final Operation operation: transformOperation.getOperationInputs ()) { inputs.add (buildInput (operation)); } return new TransformOperationDTO (operationType, inputs, properties); } public Object buildOperationProperties (final OperationType operationType, final Map<String, Object> settings) { if (operationType == null || settings == null || operationType.getPropertyBeanClass () == null) { return null; } final BeanWrapper wrapper; try { wrapper = new BeanWrapperImpl (operationType.getPropertyBeanClass ().newInstance ()); } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } wrapper.setConversionService (conversionService); for (final Map.Entry<String, Object> entry: settings.entrySet ()) { wrapper.setPropertyValue (entry.getKey (), entry.getValue ()); } return wrapper.getWrappedInstance (); } private FeatureTypeAttribute getInputAttribute (final FeatureType featureType, final String attributeName, final String attributeType) { for (final FeatureTypeAttribute attribute: featureType.getAttributes ()) { final String typeString = attribute.getType ().getJavaType ().toString (); if (attribute.getName ().getLocalPart ().equals (attributeName) && typeString.equals (attributeType)) { return attribute; } } return null; } private OperationType getTransformOperationType (final String operationName) { for (final OperationType operationType: operationTypes) { if (operationType.getName ().equals (operationName)) { return operationType; } } return null; } private ConditionalTransform.Operation getConditionalOperation (final String operationName) { if ("in".equals (operationName)) { return ConditionalTransform.Operation.IN; } else if ("not_in".equals (operationName)) { return ConditionalTransform.Operation.NOT_IN; } else if ("empty".equals (operationName)) { return ConditionalTransform.Operation.IS_EMPTY; } else if ("not_empty".equals (operationName)) { return ConditionalTransform.Operation.IS_NOT_EMPTY; } return null; } private OperationType getConditionalTransformOperationType () throws MappingParserException { for (final OperationType operationType: operationTypes) { if (operationType.getPropertyBeanClass () != null && operationType.getPropertyBeanClass ().equals (ConditionalTransform.Settings.class)) { return operationType; } } throw new MappingParserException ("No conditional transform operation type found"); } }