/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.target; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import com.opengamma.id.UniqueIdentifiable; import com.opengamma.util.ArgumentChecker; /** * A computation target that can be of multiple underlying types. */ /* package */final class MultipleComputationTargetType extends ComputationTargetType { private static final long serialVersionUID = 1L; private final Set<ComputationTargetType> _target; private static final ComputationTargetTypeVisitor<Set<ComputationTargetType>, Boolean> s_construct = new ComputationTargetTypeVisitor<Set<ComputationTargetType>, Boolean>() { @Override public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final Set<ComputationTargetType> data) { // Flatten and accept the contents for (ComputationTargetType type : types) { if (type.accept(this, data)) { data.add(type); } } return Boolean.FALSE; } @Override public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final Set<ComputationTargetType> data) { // Accept return Boolean.TRUE; } @Override public Boolean visitNullComputationTargetType(final Set<ComputationTargetType> data) { // Invalid throw new IllegalArgumentException(); } @Override public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final Set<ComputationTargetType> data) { // Accept return Boolean.TRUE; } }; private MultipleComputationTargetType(final Set<ComputationTargetType> target) { super(MultipleComputationTargetType.class.getName().hashCode() * 31 + target.hashCode()); _target = target; } private static Set<ComputationTargetType> copy(final ComputationTargetType a, final ComputationTargetType b) { final Set<ComputationTargetType> copy = new HashSet<ComputationTargetType>(); if (a.accept(s_construct, copy)) { copy.add(a); } if (b.accept(s_construct, copy)) { copy.add(b); } ArgumentChecker.isTrue(copy.size() >= 2, "target"); return Collections.unmodifiableSet(copy); } /** * Creates a new instance. * * @param a the first alternative for the construction, not null * @param b the second alternative for the construction, not null */ public MultipleComputationTargetType(final ComputationTargetType a, final ComputationTargetType b) { this(copy(a, b)); } private static Set<ComputationTargetType> copy(final ComputationTargetType[] types) { final Set<ComputationTargetType> copy = new HashSet<ComputationTargetType>(); for (ComputationTargetType type : types) { if (type.accept(s_construct, copy)) { copy.add(type); } } ArgumentChecker.isTrue(copy.size() >= 2, "target"); return Collections.unmodifiableSet(copy); } /** * Creates a new instance. * * @param types the alternative types for the construction, not null and not containing null */ public MultipleComputationTargetType(final ComputationTargetType[] types) { this(copy(types)); } protected Set<ComputationTargetType> getTarget() { return _target; } @Override public boolean isCompatible(final UniqueIdentifiable target) { for (ComputationTargetType type : getTarget()) { if (type.isCompatible(target)) { return true; } } return false; } @Override public boolean isCompatible(final ComputationTargetType type) { for (ComputationTargetType target : getTarget()) { if (target.isCompatible(type)) { return true; } } return false; } @Override public boolean isCompatible(final Class<? extends UniqueIdentifiable> clazz) { for (ComputationTargetType target : getTarget()) { if (target.isCompatible(clazz)) { return true; } } return false; } @Override public boolean isTargetType(final ComputationTargetType type) { for (ComputationTargetType target : getTarget()) { if (target.isTargetType(type)) { return true; } } return false; } @Override public boolean isTargetType(final Class<? extends UniqueIdentifiable> type) { for (ComputationTargetType target : getTarget()) { if (target.isTargetType(type)) { return true; } } return false; } @Override public <D, T> T accept(final ComputationTargetTypeVisitor<D, T> visitor, final D data) { return visitor.visitMultipleComputationTargetTypes(getTarget(), data); } protected void toStringImpl(final StringBuilder sb) { boolean sep = false; for (ComputationTargetType type : getTarget()) { if (sep) { sb.append('|'); } else { sep = true; } type.toStringNested(sb); } } @Override public String toString() { final StringBuilder sb = new StringBuilder(); toStringImpl(sb); return sb.toString(); } @Override protected void toStringNested(final StringBuilder sb) { sb.append('('); toStringImpl(sb); sb.append(')'); } @Override public String getName() { final StringBuilder sb = new StringBuilder(); getNameImpl(sb); return sb.toString(); } @Override protected void getNameNested(final StringBuilder sb) { sb.append('('); getNameImpl(sb); sb.append(')'); } protected void getNameImpl(final StringBuilder sb) { boolean sep = false; for (ComputationTargetType type : getTarget()) { if (sep) { sb.append('|'); } else { sep = true; } type.getNameNested(sb); } } private static final ComputationTargetTypeVisitor<MultipleComputationTargetType, Boolean> s_equals = new ComputationTargetTypeVisitor<MultipleComputationTargetType, Boolean>() { @Override public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final MultipleComputationTargetType self) { return self.getTarget().equals(types); } @Override public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final MultipleComputationTargetType self) { return Boolean.FALSE; } @Override public Boolean visitNullComputationTargetType(final MultipleComputationTargetType self) { return Boolean.FALSE; } @Override public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final MultipleComputationTargetType self) { return Boolean.FALSE; } }; @Override public boolean equals(final Object o) { if (o == this) { return true; } if (o instanceof ComputationTargetType) { return ((ComputationTargetType) o).accept(s_equals, this).booleanValue(); } else { return false; } } }