com.opengamma.integration.marketdata.manipulator.dsl.SimulationScript.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.integration.marketdata.manipulator.dsl.SimulationScript.java

Source

/**
 * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.integration.marketdata.manipulator.dsl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.apache.commons.io.IOUtils;

import com.google.common.collect.Maps;
import com.opengamma.DataNotFoundException;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.util.ArgumentChecker;

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.Script;

/**
 * Base class for scripts that create {@link Simulation}s and {@link Scenario}s. The methods in this class are available
 * in the script and form the basis of a DSL.
 */
public abstract class SimulationScript extends Script {

    /** The currently building simulation. */
    private Simulation _simulation;
    /** The currently building scenario. */
    private Scenario _scenario;

    public SimulationScript() {
        initialize();
    }

    public SimulationScript(Binding binding) {
        super(binding);
        initialize();
    }

    // TODO is there a nicer way to do this?
    private void initialize() {
        InputStream scriptStream = SimulationScript.class.getResourceAsStream("InitializeScript.groovy");
        try {
            evaluate(IOUtils.toString(scriptStream));
        } catch (IOException e) {
            throw new OpenGammaRuntimeException("Failed to initialize DSL script", e);
        }
    }

    /**
     * Defines a method in the DSL taking a block to define the script parameters and their types. It checks the
     * parameters are available in the script's binding and that they have the expected type.
     * <pre>
     * parameters {
     *   foo String
     *   bar Number
     * }
     * </pre>
     * @param body The block that defines the script's parameters
     */
    public void parameters(Closure body) {
        ParametersDelegate parametersDelegate = new ParametersDelegate();
        body.setDelegate(parametersDelegate);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
        // check the parameters are all in the binding and have the expected types
        Binding binding = getBinding();
        Map<String, Class<?>> parameters = parametersDelegate.getParameters();
        for (Map.Entry<String, Class<?>> entry : parameters.entrySet()) {
            String varName = entry.getKey();
            Class<?> varType = entry.getValue();
            if (!binding.hasVariable(varName)) {
                throw new DataNotFoundException("Parameter named " + varName + " not found");
            }
            Object varValue = binding.getVariable(varName);
            if (!varType.isInstance(varValue)) {
                throw new IllegalArgumentException("Parameter " + varName + " has type "
                        + varValue.getClass().getName() + ", " + "required type is " + varType.getName());
            }
        }
    }

    /**
     * Delegate for the closure that declares the script parameters and their types.
     */
    private static class ParametersDelegate extends GroovyObjectSupport {

        /** Map of parameter names to types. */
        private final Map<String, Class<?>> _params = Maps.newHashMap();

        @Override
        public Object invokeMethod(String name, Object args) {
            ArgumentChecker.notEmpty(name, "name");
            if (!(args instanceof Object[])) {
                throw new IllegalArgumentException();
            }
            Object[] argArray = (Object[]) args;
            if (argArray.length != 1 || !argArray[0].getClass().equals(Class.class)) {
                throw new IllegalArgumentException("parameter declarations must be of the form 'var Type");
            }
            if (_params.containsKey(name)) {
                throw new IllegalArgumentException("parameter " + name + " can only be declared once");
            }
            _params.put(name, (Class<?>) argArray[0]);
            return null;
        }

        private Map<String, Class<?>> getParameters() {
            return _params;
        }
    }

    /**
     * Defines a method in the DSL that takes a closure defining a simulation.
     * @param name The simulation name
     * @param body The block that defines the simulation
     * @return The simulation
     */
    public Simulation simulation(String name, Closure body) {
        _simulation = new Simulation(name);
        body.setDelegate(_simulation);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
        return _simulation;
    }

    /**
     * Defines a method in the DSL that takes a closure defining a scenario.
     * @param name The scenario name, not empty
     * @param body The block that defines the scenario
     * @return The scenario
     */
    public Scenario scenario(String name, Closure body) {
        // scenarios can be defined as part of a simulation or stand-alone
        if (_simulation != null) {
            _scenario = _simulation.scenario(name);
        } else {
            _scenario = new Scenario(name);
        }
        body.setDelegate(_scenario);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
        return _scenario;
    }

    /**
     * Defines a method in the DSL that takes a closure which defines how to select and transform a curve.
     * @param body The block that defines the selection and transformation
     */
    public void curve(Closure body) {
        CurveBuilder selector = new CurveBuilder(_scenario);
        body.setDelegate(selector);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
    }

    /**
     * Defines a method in the DSL that takes a closure which defines how to select and transform a market data point.
     * @param body The block that defines the selection and transformation
     */
    public void marketData(Closure body) {
        PointBuilder selector = new PointBuilder(_scenario);
        body.setDelegate(selector);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
    }

    /**
     * Defines a method in the DSL that takes a closure which defines how to select and transform a volatility surface.
     * @param body The block that defines the selection and transformation
     */
    public void surface(Closure body) {
        SurfaceBuilder selector = new SurfaceBuilder(_scenario);
        body.setDelegate(selector);
        body.setResolveStrategy(Closure.DELEGATE_FIRST);
        body.call();
    }

    /**
     * Delegate class for closures that define a surface transformation in the DSL.
     */
    private static final class SurfaceBuilder extends VolatilitySurfaceSelector.Builder {

        private SurfaceBuilder(Scenario scenario) {
            super(scenario);
        }

        public void apply(Closure body) {
            VolatilitySurfaceManipulatorBuilder builder = new VolatilitySurfaceManipulatorBuilder(getScenario(),
                    getSelector());
            body.setDelegate(builder);
            body.setResolveStrategy(Closure.DELEGATE_FIRST);
            body.call();
        }
    }

    /**
     * Delegate class for blocks that define a market data point transformation in the DSL.
     */
    private static final class PointBuilder extends PointSelector.Builder {

        private PointBuilder(Scenario scenario) {
            super(scenario);
        }

        public void apply(Closure body) {
            PointManipulatorBuilder builder = new PointManipulatorBuilder(getScenario(), getSelector());
            body.setDelegate(builder);
            body.setResolveStrategy(Closure.DELEGATE_FIRST);
            body.call();
        }
    }

    /**
     * Delegate class for closures that define a curve transformation in the DSL.
     */
    private static final class CurveBuilder extends YieldCurveSelector.Builder {

        private CurveBuilder(Scenario scenario) {
            super(scenario);
        }

        public void apply(Closure body) {
            YieldCurveManipulatorBuilder builder = new YieldCurveManipulatorBuilder(getSelector(), getScenario());
            body.setDelegate(builder);
            body.setResolveStrategy(Closure.DELEGATE_FIRST);
            body.call();
        }
    }
}