/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.fudgemsg; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.fudgemsg.FudgeField; import org.fudgemsg.FudgeMsg; import org.fudgemsg.MutableFudgeMsg; import org.fudgemsg.mapping.FudgeBuilder; import org.fudgemsg.mapping.FudgeDeserializer; import org.fudgemsg.mapping.FudgeSerializer; import org.fudgemsg.mapping.GenericFudgeBuilderFor; import org.fudgemsg.wire.types.FudgeWireType; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.engine.target.ComputationTargetType; import com.opengamma.engine.target.ComputationTargetTypeVisitor; import com.opengamma.id.UniqueIdentifiable; import com.opengamma.util.ClassUtils; /** * Fudge message builder for {@link ComputationTargetType}. * * <pre> * message ComputationTargetType { * optional repeated string computationTargetType; // name of the type * optional repeated message computationTargetType; // alternative type choices * // The computationTargetType field is repeated for nested types, the outermost first. When a message is present instead * // of a field, the message contains alternative type choices. Each may be a string which is the name of the type or is a * // ComputationTargetType message. * } * </pre> */ @GenericFudgeBuilderFor(ComputationTargetType.class) public class ComputationTargetTypeFudgeBuilder implements FudgeBuilder<ComputationTargetType> { private static class CommonByName { private static final Map<String, ComputationTargetType> s_data = new HashMap<String, ComputationTargetType>(); static { try { final Class<?> c = ComputationTargetType.class; for (final Field field : c.getDeclaredFields()) { if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()) && field.isSynthetic() == false && c.isAssignableFrom(field.getType())) { final ComputationTargetType type = (ComputationTargetType) field.get(null); s_data.put(type.toString(), type); } } } catch (final IllegalAccessException e) { throw new OpenGammaRuntimeException("Can't initialise", e); } } public static ComputationTargetType get(final String name) { return s_data.get(name); } } /** * Fudge field name. */ private static final String TYPE_FIELD_NAME = "computationTargetType"; @SuppressWarnings({"unchecked", "rawtypes" }) public static ComputationTargetType fromString(final String str) { final ComputationTargetType common = CommonByName.get(str); if (common != null) { return common; } else { return ComputationTargetType.of((Class) ClassUtils.loadClassRuntime(str)); } } private static final ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean> s_baseEncoder = new ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean>() { @Override public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final MutableFudgeMsg data) { // Add a sub-message containing the choices final MutableFudgeMsg msg = data.addSubMessage(TYPE_FIELD_NAME, null); for (final ComputationTargetType type : types) { if (type.accept(s_choiceEncoder, msg)) { msg.add(null, null, FudgeWireType.STRING, type.toString()); } } return Boolean.FALSE; } @Override public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final MutableFudgeMsg data) { // Add fields in order for (final ComputationTargetType type : types) { if (type.accept(s_baseEncoder, data)) { data.add(TYPE_FIELD_NAME, null, FudgeWireType.STRING, type.toString()); } } return Boolean.FALSE; } @Override public Boolean visitNullComputationTargetType(final MutableFudgeMsg data) { return Boolean.TRUE; } @Override public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final MutableFudgeMsg data) { return Boolean.TRUE; } }; private static final ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean> s_choiceEncoder = new ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean>() { @Override public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final MutableFudgeMsg data) { throw new IllegalArgumentException(); } @Override public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final MutableFudgeMsg data) { // Add a sub-message which encodes the types in the correct order final MutableFudgeMsg msg = data.addSubMessage(null, null); for (final ComputationTargetType type : types) { if (type.accept(s_nestedEncoder, msg)) { msg.add(null, null, FudgeWireType.STRING, type.toString()); } } return Boolean.FALSE; } @Override public Boolean visitNullComputationTargetType(final MutableFudgeMsg data) { return Boolean.TRUE; } @Override public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final MutableFudgeMsg data) { return Boolean.TRUE; } }; private static final ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean> s_nestedEncoder = new ComputationTargetTypeVisitor<MutableFudgeMsg, Boolean>() { @Override public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final MutableFudgeMsg data) { // Add a sub-message containing the choices final MutableFudgeMsg msg = data.addSubMessage(null, null); for (final ComputationTargetType type : types) { if (type.accept(s_choiceEncoder, msg)) { msg.add(null, null, FudgeWireType.STRING, type.toString()); } } return Boolean.FALSE; } @Override public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final MutableFudgeMsg data) { throw new IllegalArgumentException(); } @Override public Boolean visitNullComputationTargetType(final MutableFudgeMsg data) { return Boolean.TRUE; } @Override public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final MutableFudgeMsg data) { return Boolean.TRUE; } }; public static void buildMessageImpl(final MutableFudgeMsg msg, final ComputationTargetType object) { if (object.accept(s_baseEncoder, msg)) { msg.add(TYPE_FIELD_NAME, null, FudgeWireType.STRING, object.toString()); } } @Override public MutableFudgeMsg buildMessage(final FudgeSerializer serializer, final ComputationTargetType object) { final MutableFudgeMsg msg = serializer.newMessage(); buildMessageImpl(msg, object); return msg; } @SuppressWarnings({"rawtypes", "unchecked" }) private static ComputationTargetType decodeAlternativeType(final ComputationTargetType current, final FudgeField field) throws Exception { if (field.getValue() instanceof String) { final String name = (String) field.getValue(); final ComputationTargetType common = CommonByName.get(name); if (common != null) { if (current == null) { return common; } else { return current.or(common); } } else { final Class clazz = ClassUtils.loadClass(name); if (current == null) { return ComputationTargetType.of(clazz); } else { return current.or(clazz); } } } else if (field.getValue() instanceof FudgeMsg) { ComputationTargetType type = null; for (final FudgeField field2 : (FudgeMsg) field.getValue()) { type = decodeNestedType(type, field2); } if (type != null) { if (current == null) { return type; } else { return current.or(type); } } else { return current; } } else { return current; } } @SuppressWarnings({"rawtypes", "unchecked" }) private static ComputationTargetType decodeNestedType(final ComputationTargetType outer, final FudgeField field) throws Exception { if (field.getValue() instanceof String) { final String name = (String) field.getValue(); final ComputationTargetType common = CommonByName.get(name); if (common != null) { if (outer == null) { return common; } else { return outer.containing(common); } } else { final Class clazz = ClassUtils.loadClass(name); if (outer == null) { return ComputationTargetType.of(clazz); } else { return outer.containing(clazz); } } } else if (field.getValue() instanceof FudgeMsg) { ComputationTargetType type = null; for (final FudgeField field2 : (FudgeMsg) field.getValue()) { type = decodeAlternativeType(type, field2); } if (type != null) { if (outer == null) { return type; } else { return outer.containing(type); } } else { return outer; } } else { return outer; } } public static ComputationTargetType buildObjectImpl(final FudgeMsg msg) { try { ComputationTargetType result = null; for (final FudgeField field : msg) { if (TYPE_FIELD_NAME.equals(field.getName())) { result = decodeNestedType(result, field); } } return result; } catch (final Exception e) { throw new OpenGammaRuntimeException("Can't decode message", e); } } @Override public ComputationTargetType buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { return buildObjectImpl(message); } }