com.opengamma.financial.currency.AbstractCurrencyMatrixSourcingFunction.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.financial.currency.AbstractCurrencyMatrixSourcingFunction.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.financial.currency;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.AbstractFunction;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.financial.currency.CurrencyMatrixValue.CurrencyMatrixCross;
import com.opengamma.financial.currency.CurrencyMatrixValue.CurrencyMatrixFixed;
import com.opengamma.financial.currency.CurrencyMatrixValue.CurrencyMatrixValueRequirement;
import com.opengamma.timeseries.DoubleTimeSeries;
import com.opengamma.util.money.Currency;

/**
 * Injects values from a {@link CurrencyMatrix} into a dependency graph to satisfy the requirements generated by {@link CurrencyMatrixLookupFunction}.
 */
public abstract class AbstractCurrencyMatrixSourcingFunction extends AbstractFunction.NonCompiledInvoker {

    /**
     * Property name when applied to a {@link CurrencyMatrix} target to allow the counter currency to be identified.
     */
    protected static final String SOURCE_CURRENCY_PROPERTY = "Counter";

    /**
     * Property name when applied to a {@link CurrencyMatrix} target to allow the base currency to be identified.
     */
    protected static final String TARGET_CURRENCY_PROPERTY = "Base";

    /**
     * Property name for tagging input values.
     */
    private static final String SOURCE_CURRENCY_TAG = ValuePropertyNames.OUTPUT_RESERVED_PREFIX
            + SOURCE_CURRENCY_PROPERTY;

    /**
     * Property name for tagging input values.
     */
    private static final String TARGET_CURRENCY_TAG = ValuePropertyNames.OUTPUT_RESERVED_PREFIX
            + TARGET_CURRENCY_PROPERTY;

    private final String _valueRequirementName;

    protected AbstractCurrencyMatrixSourcingFunction(final String valueRequirementName) {
        _valueRequirementName = valueRequirementName;
    }

    protected String getValueRequirementName() {
        return _valueRequirementName;
    }

    @Override
    public ComputationTargetType getTargetType() {
        return CurrencyMatrixResolver.TYPE;
    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
            final ComputationTarget target) {
        final String valueRequirementName = getValueRequirementName();
        final ComputationTargetSpecification targetSpec = target.toSpecification();
        final CurrencyMatrix matrix = (CurrencyMatrix) target.getValue();
        final Collection<Currency> sourceCurrencies = matrix.getSourceCurrencies();
        final Collection<Currency> targetCurrencies = matrix.getTargetCurrencies();
        final Set<ValueSpecification> results = Sets
                .<ValueSpecification>newHashSetWithExpectedSize(sourceCurrencies.size() * targetCurrencies.size());
        final ValueProperties.Builder properties = createValueProperties();
        for (Currency sourceCurrency : sourceCurrencies) {
            properties.withoutAny(SOURCE_CURRENCY_PROPERTY).with(SOURCE_CURRENCY_PROPERTY,
                    sourceCurrency.getCode());
            for (Currency targetCurrency : targetCurrencies) {
                if (!targetCurrency.equals(sourceCurrency)) {
                    final CurrencyMatrixValue conversion = matrix.getConversion(sourceCurrency, targetCurrency);
                    if (conversion != null) {
                        results.add(new ValueSpecification(valueRequirementName, targetSpec,
                                properties.withoutAny(TARGET_CURRENCY_PROPERTY)
                                        .with(TARGET_CURRENCY_PROPERTY, targetCurrency.getCode()).get()));
                    }
                }
            }
        }
        return results;
    }

    protected ValueRequirement tagInput(final ValueRequirement requirement, final Currency source,
            final Currency target) {
        return new ValueRequirement(requirement.getValueName(), requirement.getTargetReference(),
                requirement.getConstraints().copy().with(SOURCE_CURRENCY_TAG, source.getCode())
                        .withOptional(SOURCE_CURRENCY_TAG).with(TARGET_CURRENCY_TAG, target.getCode())
                        .withOptional(TARGET_CURRENCY_TAG).get());
    }

    protected abstract boolean getRequirements(FunctionCompilationContext context, ValueRequirement desiredValue,
            CurrencyMatrix matrix, Set<ValueRequirement> requirements, Currency source, Currency target);

    @Override
    public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context,
            final ComputationTarget target, final ValueRequirement desiredValue) {
        final CurrencyMatrix matrix = (CurrencyMatrix) target.getValue();
        final Currency sourceCurrency = Currency.of(desiredValue.getConstraint(SOURCE_CURRENCY_PROPERTY));
        final Currency targetCurrency = Currency.of(desiredValue.getConstraint(TARGET_CURRENCY_PROPERTY));
        final Set<ValueRequirement> requirements = new HashSet<ValueRequirement>();
        if (getRequirements(context, desiredValue, matrix, requirements, sourceCurrency, targetCurrency)) {
            return requirements;
        } else {
            return null;
        }
    }

    private static final class DetermineResults implements CurrencyMatrixValueVisitor<Boolean> {

        private final CurrencyMatrix _matrix;
        private final Collection<Currency> _sourceCurrencies;
        private final Collection<Currency> _targetCurrencies;
        private final Map<Currency, Map<Currency, Boolean>> _valid;

        private Currency _currentSourceCurrency;
        private Currency _currentTargetCurrency;

        public DetermineResults(final CurrencyMatrix matrix) {
            _matrix = matrix;
            _sourceCurrencies = _matrix.getSourceCurrencies();
            _targetCurrencies = _matrix.getTargetCurrencies();
            _valid = Maps.newHashMapWithExpectedSize(_sourceCurrencies.size());
        }

        private void input(final Currency source, final Currency target, final Boolean status) {
            Map<Currency, Boolean> target2status = _valid.get(source);
            if (target2status == null) {
                target2status = Maps.newHashMapWithExpectedSize(_targetCurrencies.size());
                _valid.put(source, target2status);
            }
            target2status.put(target, status);
        }

        public void present(final Currency source, final Currency target) {
            input(source, target, Boolean.TRUE);
        }

        public void missing(final Currency source, final Currency target) {
            input(source, target, Boolean.FALSE);
        }

        public boolean hasInputFor(final Currency source, final Currency target) {
            if (source.equals(target)) {
                return false;
            }
            Map<Currency, Boolean> target2status = _valid.get(source);
            if (target2status != null) {
                Boolean status = target2status.get(target);
                if (status != null) {
                    return status;
                }
            }
            final CurrencyMatrixValue conversion = _matrix.getConversion(source, target);
            if (conversion == null) {
                missing(source, target);
                return false;
            }
            _currentSourceCurrency = source;
            _currentTargetCurrency = target;
            return conversion.accept(this);
        }

        // CurrentMatrixVisitor

        @Override
        public Boolean visitFixed(CurrencyMatrixFixed fixedValue) {
            present(_currentSourceCurrency, _currentTargetCurrency);
            return Boolean.TRUE;
        }

        @Override
        public Boolean visitValueRequirement(CurrencyMatrixValueRequirement uniqueId) {
            return Boolean.FALSE;
        }

        @Override
        public Boolean visitCross(CurrencyMatrixCross cross) {
            final Currency sourceCurrency = _currentSourceCurrency;
            final Currency targetCurrency = _currentTargetCurrency;
            // Declare as missing to avoid a loop forming
            missing(sourceCurrency, targetCurrency);
            boolean result = hasInputFor(sourceCurrency, cross.getCrossCurrency())
                    && hasInputFor(cross.getCrossCurrency(), targetCurrency);
            if (result) {
                // Is present after all
                present(sourceCurrency, targetCurrency);
            }
            return result;
        }

    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
            final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) {
        final String valueRequirementName = getValueRequirementName();
        final ComputationTargetSpecification targetSpec = target.toSpecification();
        final CurrencyMatrix matrix = (CurrencyMatrix) target.getValue();
        final DetermineResults resultBuilder = new DetermineResults(matrix);
        for (ValueRequirement input : inputs.values()) {
            final Currency sourceCurrency = Currency.of(input.getConstraint(SOURCE_CURRENCY_TAG));
            final Currency targetCurrency = Currency.of(input.getConstraint(TARGET_CURRENCY_TAG));
            resultBuilder.present(sourceCurrency, targetCurrency);
        }
        final Set<ValueSpecification> results = Sets.newHashSetWithExpectedSize(
                resultBuilder._sourceCurrencies.size() * resultBuilder._targetCurrencies.size());
        final ValueProperties.Builder properties = createValueProperties();
        for (Currency sourceCurrency : resultBuilder._sourceCurrencies) {
            properties.withoutAny(SOURCE_CURRENCY_PROPERTY).with(SOURCE_CURRENCY_PROPERTY,
                    sourceCurrency.getCode());
            for (Currency targetCurrency : resultBuilder._targetCurrencies) {
                if (resultBuilder.hasInputFor(sourceCurrency, targetCurrency)) {
                    results.add(new ValueSpecification(valueRequirementName, targetSpec,
                            properties.withoutAny(TARGET_CURRENCY_PROPERTY)
                                    .with(TARGET_CURRENCY_PROPERTY, targetCurrency.getCode()).get()));
                }
            }
        }
        return results;
    }

    @Override
    public boolean canHandleMissingInputs() {
        return true;
    }

    protected abstract Object getRate(CurrencyMatrix matrix, ValueRequirement desiredValue,
            FunctionExecutionContext executionContext, FunctionInputs inputs, Currency source, Currency target);

    @Override
    public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs,
            final ComputationTarget target, final Set<ValueRequirement> desiredValues) {
        final CurrencyMatrix matrix = (CurrencyMatrix) target.getValue();
        final Set<ComputedValue> result = Sets.newHashSetWithExpectedSize(desiredValues.size());
        for (ValueRequirement desiredValue : desiredValues) {
            final Currency sourceCurrency = Currency.of(desiredValue.getConstraint(SOURCE_CURRENCY_PROPERTY));
            final Currency targetCurrency = Currency.of(desiredValue.getConstraint(TARGET_CURRENCY_PROPERTY));
            final ValueSpecification valueSpec = new ValueSpecification(desiredValue.getValueName(),
                    target.toSpecification(), desiredValue.getConstraints());
            final Object resultValue = getRate(matrix, desiredValue, executionContext, inputs, sourceCurrency,
                    targetCurrency);
            if (resultValue != null) {
                result.add(new ComputedValue(valueSpec, resultValue));
            }
        }
        return result;
    }

    protected static Object createCrossRate(final Object r1, final Object r2) {
        if ((r1 == null) || (r2 == null)) {
            // Missing input case; reported elsewhere
            return null;
        }
        if (r1 instanceof Double) {
            if (r2 instanceof Double) {
                return (Double) r1 * (Double) r2;
            } else if (r2 instanceof DoubleTimeSeries) {
                return ((DoubleTimeSeries<?>) r2).multiply((Double) r1);
            } else {
                throw new IllegalArgumentException();
            }
        } else if (r1 instanceof DoubleTimeSeries) {
            if (r2 instanceof Double) {
                return ((DoubleTimeSeries<?>) r1).multiply((Double) r2);
            } else if (r2 instanceof DoubleTimeSeries) {
                return ((DoubleTimeSeries<?>) r1).multiply((DoubleTimeSeries<?>) r2);
            } else {
                throw new IllegalArgumentException();
            }
        } else {
            throw new IllegalArgumentException();
        }
    }

}