/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.calc.runner;
import static com.opengamma.strata.collect.Guavate.toImmutableList;
import static com.opengamma.strata.collect.Guavate.toImmutableMap;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.joda.beans.BeanDefinition;
import org.joda.beans.ImmutableBean;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.Property;
import org.joda.beans.PropertyDefinition;
import org.joda.beans.impl.light.LightMetaBean;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.opengamma.strata.basics.CalculationTarget;
import com.opengamma.strata.calc.CalculationRules;
import com.opengamma.strata.calc.Column;
import com.opengamma.strata.calc.Measure;
import com.opengamma.strata.calc.ReportingCurrency;
/**
* The calculation parameters.
* <p>
* This provides a set of parameters that will be used in a calculation.
* Each parameter defines a {@linkplain CalculationParameter#queryType() query type},
* thus the functions are keyed in a {@code Map} by the query type {@code Class}.
* <p>
* Parameters exist to provide control over the calculation.
* For example, {@link ReportingCurrency} is a parameter that controls currency conversion.
* If specified, on a {@link Column}, or in {@link CalculationRules}, then the output will
* be converted to the specified currency.
*/
@BeanDefinition(style = "light")
public final class CalculationParameters implements ImmutableBean, Serializable {
/**
* An empty instance.
*/
private static final CalculationParameters EMPTY = new CalculationParameters(ImmutableMap.of());
/**
* The parameters, keyed by query type.
*/
@PropertyDefinition(validate = "notNull")
private final ImmutableMap<Class<? extends CalculationParameter>, CalculationParameter> parameters;
//-------------------------------------------------------------------------
/**
* Obtains an empty instance with no parameters.
*
* @return the empty instance
*/
public static CalculationParameters empty() {
return EMPTY;
}
/**
* Obtains an instance from the specified parameters.
* <p>
* The list will be converted to a {@code Map} using {@link CalculationParameter#queryType()}.
* Each parameter must refer to a different query type.
*
* @param parameters the parameters
* @return the calculation parameters
* @throws IllegalArgumentException if two parameters have same query type
*/
public static CalculationParameters of(CalculationParameter... parameters) {
if (parameters.length == 0) {
return EMPTY;
}
return new CalculationParameters(Stream.of(parameters).collect(toImmutableMap(p -> p.queryType())));
}
/**
* Obtains an instance from the specified parameters.
* <p>
* The list will be converted to a {@code Map} using {@link CalculationParameter#queryType()}.
* Each parameter must refer to a different query type.
*
* @param parameters the parameters
* @return the calculation parameters
* @throws IllegalArgumentException if two parameters have same query type
*/
public static CalculationParameters of(List<? extends CalculationParameter> parameters) {
if (parameters.isEmpty()) {
return EMPTY;
}
return new CalculationParameters(parameters.stream().collect(toImmutableMap(p -> p.queryType())));
}
// create checking for empty
private CalculationParameters of(Map<Class<? extends CalculationParameter>, CalculationParameter> map) {
if (map.isEmpty()) {
return EMPTY;
}
return new CalculationParameters(map);
}
//-------------------------------------------------------------------------
/**
* Combines this set of parameters with the specified set.
* <p>
* This set of parameters takes priority.
*
* @param other the other parameters
* @return the combined calculation parameters
*/
public CalculationParameters combinedWith(CalculationParameters other) {
if (other.parameters.isEmpty()) {
return this;
}
if (parameters.isEmpty()) {
return other;
}
Map<Class<? extends CalculationParameter>, CalculationParameter> map = new HashMap<>(other.getParameters());
map.putAll(parameters);
return of(map);
}
/**
* Returns a copy of this instance with the specified parameter added.
* <p>
* If this instance already has a parameter with the query type, it will be replaced.
*
* @param parameter the parameter to add
* @return the new instance based on this with the parameter added
*/
public CalculationParameters with(CalculationParameter parameter) {
Map<Class<? extends CalculationParameter>, CalculationParameter> map = new HashMap<>(parameters);
map.put(parameter.queryType(), parameter);
return of(map);
}
/**
* Filters the parameters, returning a set without the specified type.
*
* @param type the type to remove
* @return the filtered calculation parameters
*/
public CalculationParameters without(Class<? extends CalculationParameter> type) {
if (!parameters.containsKey(type)) {
return this;
}
Map<Class<? extends CalculationParameter>, CalculationParameter> map = new HashMap<>(parameters);
map.remove(type);
return of(map);
}
/**
* Filters the parameters, matching only those that are applicable for the target and measure.
* <p>
* The resulting parameters are filtered to the target and measure.
* The implementation of each parameter may be changed by this process.
* If two parameters are filtered to the same {@linkplain CalculationParameter#queryType() query type}
* then an exception will be thrown
*
* @param target the calculation target, such as a trade
* @param measure the measure to be calculated
* @return the filtered calculation parameters
* @throws IllegalArgumentException if two parameters are filtered to the same query type
*/
public CalculationParameters filter(CalculationTarget target, Measure measure) {
ImmutableList<CalculationParameter> filtered = parameters.values().stream()
.map(cp -> cp.filter(target, measure))
.filter(opt -> opt.isPresent())
.map(opt -> opt.get())
.collect(toImmutableList());
return of(filtered);
}
//-------------------------------------------------------------------------
/**
* Finds the parameter that matches the specified query type.
*
* @param <T> the type of the parameter
* @param type the query type to find
* @return the parameter
*/
@SuppressWarnings("unchecked")
public <T extends CalculationParameter> Optional<T> findParameter(Class<T> type) {
return Optional.ofNullable((T) parameters.get(type));
}
/**
* Returns the parameter that matches the specified query type throwing an exception if not available.
*
* @param <T> the type of the parameter
* @param type the query type to return
* @return the parameter
* @throws IllegalArgumentException if no parameter if found for the type
*/
@SuppressWarnings("unchecked")
public <T extends CalculationParameter> T getParameter(Class<T> type) {
T calculationParameter = (T) parameters.get(type);
if (calculationParameter == null) {
throw new IllegalArgumentException("No parameter found for query type " + type.getName());
}
return calculationParameter;
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code CalculationParameters}.
*/
private static MetaBean META_BEAN = LightMetaBean.of(CalculationParameters.class);
/**
* The meta-bean for {@code CalculationParameters}.
* @return the meta-bean, not null
*/
public static MetaBean meta() {
return META_BEAN;
}
static {
JodaBeanUtils.registerMetaBean(META_BEAN);
}
/**
* The serialization version id.
*/
private static final long serialVersionUID = 1L;
private CalculationParameters(
Map<Class<? extends CalculationParameter>, CalculationParameter> parameters) {
JodaBeanUtils.notNull(parameters, "parameters");
this.parameters = ImmutableMap.copyOf(parameters);
}
@Override
public MetaBean metaBean() {
return META_BEAN;
}
@Override
public <R> Property<R> property(String propertyName) {
return metaBean().<R>metaProperty(propertyName).createProperty(this);
}
@Override
public Set<String> propertyNames() {
return metaBean().metaPropertyMap().keySet();
}
//-----------------------------------------------------------------------
/**
* Gets the parameters, keyed by query type.
* @return the value of the property, not null
*/
public ImmutableMap<Class<? extends CalculationParameter>, CalculationParameter> getParameters() {
return parameters;
}
//-----------------------------------------------------------------------
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj.getClass() == this.getClass()) {
CalculationParameters other = (CalculationParameters) obj;
return JodaBeanUtils.equal(parameters, other.parameters);
}
return false;
}
@Override
public int hashCode() {
int hash = getClass().hashCode();
hash = hash * 31 + JodaBeanUtils.hashCode(parameters);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append("CalculationParameters{");
buf.append("parameters").append('=').append(JodaBeanUtils.toString(parameters));
buf.append('}');
return buf.toString();
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}