/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.util.money;
import java.io.Serializable;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Pattern;
import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.BeanDefinition;
import org.joda.beans.ImmutableBean;
import org.joda.beans.ImmutableConstructor;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaProperty;
import org.joda.beans.Property;
import org.joda.beans.PropertyDefinition;
import org.joda.beans.impl.direct.DirectFieldsBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaBean;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import org.joda.convert.FromString;
import org.joda.convert.ToString;
import com.opengamma.id.ObjectId;
import com.opengamma.id.ObjectIdentifiable;
import com.opengamma.id.UniqueId;
import com.opengamma.id.UniqueIdentifiable;
import com.opengamma.util.ArgumentChecker;
/**
* Stores a pair of currencies without any implied ordering.
* <p>
* This acts like a two element {@code Set}, thus
* {@code UnorderedCurrencyPair(USD, EUR) == UnorderedCurrencyPair(EUR, USD)}.
*/
@BeanDefinition(builderScope = "private")
public final class UnorderedCurrencyPair implements ImmutableBean,
UniqueIdentifiable, ObjectIdentifiable, Serializable {
private static final long serialVersionUID = 1L;
/**
* The scheme to use in object identifiers.
*/
public static final String OBJECT_SCHEME = "UnorderedCurrencyPair";
/**
* One of the two currencies.
* The name 'first' has no meaning as this pair is unordered.
*/
@PropertyDefinition(get = "manual", validate = "notNull")
private final Currency _firstCurrency;
/**
* One of the two currencies.
* The name 'second' has no meaning as this pair is unordered.
*/
@PropertyDefinition(get = "manual", validate = "notNull")
private final Currency _secondCurrency;
/**
* The cached value of the identifier.
*/
private String _idValue;
/**
* Obtains an {@code UnorderedCurrencyPair} from two currencies.
*
* @param ccy1 one of the currencies, not null
* @param ccy2 one of the currencies, not null
* @return the pair, not null
*/
public static UnorderedCurrencyPair of(Currency ccy1, Currency ccy2) {
return new UnorderedCurrencyPair(ccy1, ccy2);
}
/**
* Extracts an {@code UnorderedCurrencyPair} from a unique identifier.
*
* @param uniqueId the unique identifier, not null
* @return the pair, not null
* @throws IllegalArgumentException if the input is invalid
*/
public static UnorderedCurrencyPair of(UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "unique id");
if (uniqueId.getScheme().equals(OBJECT_SCHEME)) {
Pattern validate = Pattern.compile("[A-Z]{6}");
String value = uniqueId.getValue();
if (validate.matcher(value).matches()) {
Currency ccy1 = Currency.of(value.substring(0, 3));
Currency ccy2 = Currency.of(value.substring(3));
return new UnorderedCurrencyPair(ccy1, ccy2);
}
}
throw new IllegalArgumentException("Cannot create an UnorderedCurrencyPair from this UniqueId; need an ObjectScheme of UnorderedCurrencyPair, have " + uniqueId.getScheme());
}
/**
* Parses the string to produce a {@code UnorderedCurrencyPair}.
* <p>
* This parses the {@code toString} format of '${currency1}${currency2}'
* where the currencies are in alphabetical order.
*
* @param pairStr the amount string, not null
* @return the currency amount
* @throws IllegalArgumentException if the amount cannot be parsed
*/
@FromString
public static UnorderedCurrencyPair parse(final String pairStr) {
ArgumentChecker.notNull(pairStr, "pairStr");
if (pairStr.length() != 6) {
throw new IllegalArgumentException("Unable to parse amount, invalid format: " + pairStr);
}
try {
Currency cur1 = Currency.parse(pairStr.substring(0, 3));
Currency cur2 = Currency.parse(pairStr.substring(3));
return new UnorderedCurrencyPair(cur1, cur2);
} catch (RuntimeException ex) {
throw new IllegalArgumentException("Unable to parse pair: " + pairStr, ex);
}
}
//-------------------------------------------------------------------------
/**
* Constructs a new instance.
*
* @param currency1 one of the currencies, not null
* @param currency2 one of the currencies, not null
*/
@ImmutableConstructor
private UnorderedCurrencyPair(Currency currency1, Currency currency2) {
ArgumentChecker.notNull(currency1, "currency1");
ArgumentChecker.notNull(currency2, "currency2");
if (currency1.getCode().compareTo(currency2.getCode()) <= 0) {
_firstCurrency = currency1;
_secondCurrency = currency2;
_idValue = currency1.getCode() + currency2.getCode();
} else {
_firstCurrency = currency2;
_secondCurrency = currency1;
_idValue = currency2.getCode() + currency1.getCode();
}
}
//-------------------------------------------------------------------------
/**
* Gets one of the two currencies.
* The name 'first' has no meaning as this pair is unordered.
*
* @return one of the two currencies, not null
*/
public Currency getFirstCurrency() {
return _firstCurrency;
}
/**
* Gets one of the two currencies.
* The name 'second' has no meaning as this pair is unordered.
*
* @return one of the two currencies, not null
*/
public Currency getSecondCurrency() {
return _secondCurrency;
}
//-------------------------------------------------------------------------
/**
* Gets the object identifier for the pair.
* <p>
* This uses the scheme {@link #OBJECT_SCHEME UnorderedCurrencyPair}.
*
* @return the object identifier, not null
*/
@Override
public ObjectId getObjectId() {
return ObjectId.of(OBJECT_SCHEME, _idValue);
}
/**
* Gets the unique identifier for the pair.
* <p>
* This uses the scheme {@link #OBJECT_SCHEME UnorderedCurrencyPair}.
*
* @return the unique identifier, not null
*/
@Override
public UniqueId getUniqueId() {
return UniqueId.of(OBJECT_SCHEME, _idValue);
}
//-------------------------------------------------------------------------
/**
* Checks if this unordered pair equals another unordered pair.
* <p>
* The comparison checks both currencies.
*
* @param obj the other currency, null returns false
* @return true if equal
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof UnorderedCurrencyPair) {
return _idValue.equals(((UnorderedCurrencyPair) obj)._idValue);
}
return false;
}
/**
* Returns a suitable hash code for the unordered pair.
*
* @return the hash code
*/
@Override
public int hashCode() {
return _idValue.hashCode();
}
//-----------------------------------------------------------------------
/**
* Gets the unordered pair as a string.
* <p>
* This uses the format of '${currency1}${currency2}'
* where the currencies are in alphabetical order.
*
* @return the unordered pair, not null
*/
@Override
@ToString
public String toString() {
return _idValue;
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code UnorderedCurrencyPair}.
* @return the meta-bean, not null
*/
public static UnorderedCurrencyPair.Meta meta() {
return UnorderedCurrencyPair.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(UnorderedCurrencyPair.Meta.INSTANCE);
}
@Override
public UnorderedCurrencyPair.Meta metaBean() {
return UnorderedCurrencyPair.Meta.INSTANCE;
}
@Override
public <R> Property<R> property(String propertyName) {
return metaBean().<R>metaProperty(propertyName).createProperty(this);
}
@Override
public Set<String> propertyNames() {
return metaBean().metaPropertyMap().keySet();
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code UnorderedCurrencyPair}.
*/
public static final class Meta extends DirectMetaBean {
/**
* The singleton instance of the meta-bean.
*/
static final Meta INSTANCE = new Meta();
/**
* The meta-property for the {@code firstCurrency} property.
*/
private final MetaProperty<Currency> _firstCurrency = DirectMetaProperty.ofImmutable(
this, "firstCurrency", UnorderedCurrencyPair.class, Currency.class);
/**
* The meta-property for the {@code secondCurrency} property.
*/
private final MetaProperty<Currency> _secondCurrency = DirectMetaProperty.ofImmutable(
this, "secondCurrency", UnorderedCurrencyPair.class, Currency.class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> _metaPropertyMap$ = new DirectMetaPropertyMap(
this, null,
"firstCurrency",
"secondCurrency");
/**
* Restricted constructor.
*/
private Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case -1878034719: // firstCurrency
return _firstCurrency;
case 564126885: // secondCurrency
return _secondCurrency;
}
return super.metaPropertyGet(propertyName);
}
@Override
public BeanBuilder<? extends UnorderedCurrencyPair> builder() {
return new UnorderedCurrencyPair.Builder();
}
@Override
public Class<? extends UnorderedCurrencyPair> beanType() {
return UnorderedCurrencyPair.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return _metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code firstCurrency} property.
* @return the meta-property, not null
*/
public MetaProperty<Currency> firstCurrency() {
return _firstCurrency;
}
/**
* The meta-property for the {@code secondCurrency} property.
* @return the meta-property, not null
*/
public MetaProperty<Currency> secondCurrency() {
return _secondCurrency;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case -1878034719: // firstCurrency
return ((UnorderedCurrencyPair) bean).getFirstCurrency();
case 564126885: // secondCurrency
return ((UnorderedCurrencyPair) bean).getSecondCurrency();
}
return super.propertyGet(bean, propertyName, quiet);
}
@Override
protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) {
metaProperty(propertyName);
if (quiet) {
return;
}
throw new UnsupportedOperationException("Property cannot be written: " + propertyName);
}
}
//-----------------------------------------------------------------------
/**
* The bean-builder for {@code UnorderedCurrencyPair}.
*/
private static final class Builder extends DirectFieldsBeanBuilder<UnorderedCurrencyPair> {
private Currency _firstCurrency;
private Currency _secondCurrency;
/**
* Restricted constructor.
*/
private Builder() {
}
//-----------------------------------------------------------------------
@Override
public Object get(String propertyName) {
switch (propertyName.hashCode()) {
case -1878034719: // firstCurrency
return _firstCurrency;
case 564126885: // secondCurrency
return _secondCurrency;
default:
throw new NoSuchElementException("Unknown property: " + propertyName);
}
}
@Override
public Builder set(String propertyName, Object newValue) {
switch (propertyName.hashCode()) {
case -1878034719: // firstCurrency
this._firstCurrency = (Currency) newValue;
break;
case 564126885: // secondCurrency
this._secondCurrency = (Currency) newValue;
break;
default:
throw new NoSuchElementException("Unknown property: " + propertyName);
}
return this;
}
@Override
public Builder set(MetaProperty<?> property, Object value) {
super.set(property, value);
return this;
}
@Override
public Builder setString(String propertyName, String value) {
setString(meta().metaProperty(propertyName), value);
return this;
}
@Override
public Builder setString(MetaProperty<?> property, String value) {
super.setString(property, value);
return this;
}
@Override
public Builder setAll(Map<String, ? extends Object> propertyValueMap) {
super.setAll(propertyValueMap);
return this;
}
@Override
public UnorderedCurrencyPair build() {
return new UnorderedCurrencyPair(
_firstCurrency,
_secondCurrency);
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(96);
buf.append("UnorderedCurrencyPair.Builder{");
buf.append("firstCurrency").append('=').append(JodaBeanUtils.toString(_firstCurrency)).append(',').append(' ');
buf.append("secondCurrency").append('=').append(JodaBeanUtils.toString(_secondCurrency));
buf.append('}');
return buf.toString();
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}