/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.depgraph; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.fudgemsg.FudgeContext; 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 com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueSpecification; /** * Fudge message builder for {@code ResolutionFailure}. */ @GenericFudgeBuilderFor(ResolutionFailure.class) public class ResolutionFailureFudgeBuilder implements FudgeBuilder<ResolutionFailure> { private static final String ERROR_KEY = "Error"; private static final String VALUE_REQUIREMENT_KEY = "ValueRequirement"; private static final String FUNCTION_KEY = "Function"; private static final String DESIRED_OUTPUT_KEY = "DesiredOutput"; private static final String SATISFIED_KEY = "Satisfied"; private static final String UNSATISFIED_KEY = "Unsatisfied"; private static final String ADDITIONAL_REQUIREMENT_KEY = "AdditionalRequirement"; private static final String VALUE_SPECIFICATION_KEY = "ValueSpecification"; /** * Visitor that produces Fudge messages from {@link ResolutionFailure} objects. */ private static final class VisitorImpl extends ResolutionFailureVisitor<MutableFudgeMsg> { private final FudgeSerializer _serializer; public VisitorImpl(final FudgeSerializer serializer) { _serializer = serializer; } private MutableFudgeMsg message(final ResolutionFailure.Status error, final ValueRequirement valueRequirement) { final MutableFudgeMsg msg = _serializer.newMessage(); if (error != null) { _serializer.addToMessage(msg, ERROR_KEY, null, error.name()); } _serializer.addToMessage(msg, VALUE_REQUIREMENT_KEY, null, valueRequirement); return msg; } @Override protected MutableFudgeMsg visitCouldNotResolve(final ValueRequirement valueRequirement) { return message(ResolutionFailure.Status.COULD_NOT_RESOLVE, valueRequirement); } @Override protected MutableFudgeMsg visitNoFunctions(final ValueRequirement valueRequirement) { return message(ResolutionFailure.Status.NO_FUNCTIONS, valueRequirement); } @Override protected MutableFudgeMsg visitRecursiveRequirement(final ValueRequirement valueRequirement) { return message(ResolutionFailure.Status.RECURSIVE_REQUIREMENT, valueRequirement); } @Override protected MutableFudgeMsg visitUnsatisfied(final ValueRequirement valueRequirement) { return message(ResolutionFailure.Status.UNSATISFIED, valueRequirement); } @Override protected MutableFudgeMsg visitMarketDataMissing(final ValueRequirement valueRequirement) { return message(ResolutionFailure.Status.MARKET_DATA_MISSING, valueRequirement); } @Override protected MutableFudgeMsg visitFunction(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> satisfied, final Set<ResolutionFailure> unsatisfied, final Set<ResolutionFailure> unsatisfiedAdditional) { final MutableFudgeMsg msg = message(null, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); for (Map.Entry<ValueSpecification, ValueRequirement> input : satisfied.entrySet()) { final MutableFudgeMsg submessage = _serializer.newMessage(); _serializer.addToMessage(submessage, VALUE_SPECIFICATION_KEY, null, input.getKey()); _serializer.addToMessage(submessage, VALUE_REQUIREMENT_KEY, null, input.getValue()); msg.add(SATISFIED_KEY, null, submessage); } for (ResolutionFailure failure : unsatisfied) { for (MutableFudgeMsg submessage : failure.accept(this)) { msg.add(UNSATISFIED_KEY, null, submessage); } } for (ResolutionFailure failure : unsatisfiedAdditional) { for (MutableFudgeMsg submessage : failure.accept(this)) { msg.add(ADDITIONAL_REQUIREMENT_KEY, null, submessage); } } return msg; } @Override protected MutableFudgeMsg visitGetAdditionalRequirementsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { final MutableFudgeMsg msg = message(ResolutionFailure.Status.GET_ADDITIONAL_REQUIREMENTS_FAILED, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); for (Map.Entry<ValueSpecification, ValueRequirement> input : requirements.entrySet()) { final MutableFudgeMsg submessage = _serializer.newMessage(); _serializer.addToMessage(submessage, VALUE_SPECIFICATION_KEY, null, input.getKey()); _serializer.addToMessage(submessage, VALUE_REQUIREMENT_KEY, null, input.getValue()); msg.add(SATISFIED_KEY, null, submessage); } return msg; } @Override protected MutableFudgeMsg visitGetResultsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { final MutableFudgeMsg msg = message(ResolutionFailure.Status.GET_RESULTS_FAILED, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); for (Map.Entry<ValueSpecification, ValueRequirement> input : requirements.entrySet()) { final MutableFudgeMsg submessage = _serializer.newMessage(); _serializer.addToMessage(submessage, VALUE_SPECIFICATION_KEY, null, input.getKey()); _serializer.addToMessage(submessage, VALUE_REQUIREMENT_KEY, null, input.getValue()); msg.add(SATISFIED_KEY, null, submessage); } return msg; } @Override protected MutableFudgeMsg visitGetRequirementsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput) { final MutableFudgeMsg msg = message(ResolutionFailure.Status.GET_REQUIREMENTS_FAILED, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); return msg; } @Override protected MutableFudgeMsg visitLateResolutionFailure(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { final MutableFudgeMsg msg = message(ResolutionFailure.Status.LATE_RESOLUTION_FAILURE, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); for (Map.Entry<ValueSpecification, ValueRequirement> input : requirements.entrySet()) { final MutableFudgeMsg submessage = _serializer.newMessage(); _serializer.addToMessage(submessage, VALUE_SPECIFICATION_KEY, null, input.getKey()); _serializer.addToMessage(submessage, VALUE_REQUIREMENT_KEY, null, input.getValue()); msg.add(SATISFIED_KEY, null, submessage); } return msg; } @Override protected MutableFudgeMsg visitBlacklistSuppressed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { final MutableFudgeMsg msg = message(ResolutionFailure.Status.SUPPRESSED, valueRequirement); _serializer.addToMessage(msg, FUNCTION_KEY, null, function); _serializer.addToMessage(msg, DESIRED_OUTPUT_KEY, null, desiredOutput); for (Map.Entry<ValueSpecification, ValueRequirement> input : requirements.entrySet()) { final MutableFudgeMsg submessage = _serializer.newMessage(); _serializer.addToMessage(submessage, VALUE_SPECIFICATION_KEY, null, input.getKey()); _serializer.addToMessage(submessage, VALUE_REQUIREMENT_KEY, null, input.getValue()); msg.add(SATISFIED_KEY, null, submessage); } return msg; } } /** * Visitor that produces Fudge messages from {@link ResolutionFailure} objects. */ public static final class Visitor extends ResolutionFailureVisitor<MutableFudgeMsg> { private final FudgeContext _context; public Visitor(final FudgeContext context) { _context = context; } private VisitorImpl getUnderlying() { return new VisitorImpl(new FudgeSerializer(_context)); } @Override protected MutableFudgeMsg visitCouldNotResolve(final ValueRequirement valueRequirement) { return getUnderlying().visitCouldNotResolve(valueRequirement); } @Override protected MutableFudgeMsg visitNoFunctions(final ValueRequirement valueRequirement) { return getUnderlying().visitNoFunctions(valueRequirement); } @Override protected MutableFudgeMsg visitRecursiveRequirement(final ValueRequirement valueRequirement) { return getUnderlying().visitRecursiveRequirement(valueRequirement); } @Override protected MutableFudgeMsg visitUnsatisfied(final ValueRequirement valueRequirement) { return getUnderlying().visitUnsatisfied(valueRequirement); } @Override protected MutableFudgeMsg visitMarketDataMissing(final ValueRequirement valueRequirement) { return getUnderlying().visitMarketDataMissing(valueRequirement); } @Override protected MutableFudgeMsg visitFunction(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> satisfied, final Set<ResolutionFailure> unsatisfied, final Set<ResolutionFailure> unsatisfiedAdditional) { return getUnderlying().visitFunction(valueRequirement, function, desiredOutput, satisfied, unsatisfied, unsatisfiedAdditional); } @Override protected MutableFudgeMsg visitGetAdditionalRequirementsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { return getUnderlying().visitGetAdditionalRequirementsFailed(valueRequirement, function, desiredOutput, requirements); } @Override protected MutableFudgeMsg visitGetResultsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { return getUnderlying().visitGetResultsFailed(valueRequirement, function, desiredOutput, requirements); } @Override protected MutableFudgeMsg visitGetRequirementsFailed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput) { return getUnderlying().visitGetRequirementsFailed(valueRequirement, function, desiredOutput); } @Override protected MutableFudgeMsg visitLateResolutionFailure(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { return getUnderlying().visitLateResolutionFailure(valueRequirement, function, desiredOutput, requirements); } @Override protected MutableFudgeMsg visitBlacklistSuppressed(final ValueRequirement valueRequirement, final String function, final ValueSpecification desiredOutput, final Map<ValueSpecification, ValueRequirement> requirements) { return getUnderlying().visitBlacklistSuppressed(valueRequirement, function, desiredOutput, requirements); } } @Override public MutableFudgeMsg buildMessage(final FudgeSerializer serializer, final ResolutionFailure failure) { final Collection<MutableFudgeMsg> failures = failure.accept(new VisitorImpl(serializer)); if (failures.size() == 1) { return failures.iterator().next(); } else { final MutableFudgeMsg msg = serializer.newMessage(); for (MutableFudgeMsg submessage : failures) { msg.add(null, null, submessage); } return msg; } } private ResolutionFailure functionApplication(final FudgeDeserializer deserializer, final FudgeMsg message, final ValueRequirement valueRequirement) { final String functionId = message.getString(FUNCTION_KEY); final ValueSpecification desiredOutput = deserializer.fieldValueToObject(ValueSpecification.class, message.getByName(DESIRED_OUTPUT_KEY)); ResolutionFailure failure = ResolutionFailureImpl.functionApplication(valueRequirement, functionId, desiredOutput); List<FudgeField> fields = message.getAllByName(SATISFIED_KEY); if ((fields != null) && !fields.isEmpty()) { final Map<ValueSpecification, ValueRequirement> requirements = new HashMap<ValueSpecification, ValueRequirement>(); for (FudgeField requirement : fields) { final FudgeMsg requirementMsg = (FudgeMsg) requirement.getValue(); requirements.put(deserializer.fieldValueToObject(ValueSpecification.class, requirementMsg.getByName(VALUE_SPECIFICATION_KEY)), deserializer.fieldValueToObject(ValueRequirement.class, requirementMsg.getByName(VALUE_REQUIREMENT_KEY))); } failure = failure.requirements(requirements); } fields = message.getAllByName(UNSATISFIED_KEY); if ((fields != null) && !fields.isEmpty()) { for (FudgeField requirement : fields) { final ResolutionFailure requirementFailure = deserializer.fieldValueToObject(ResolutionFailure.class, requirement); failure = failure.requirement(requirementFailure.getValueRequirement(), requirementFailure); } } fields = message.getAllByName(ADDITIONAL_REQUIREMENT_KEY); if ((fields != null) && !fields.isEmpty()) { for (FudgeField requirement : fields) { final ResolutionFailure requirementFailure = deserializer.fieldValueToObject(ResolutionFailure.class, requirement); failure = failure.additionalRequirement(requirementFailure.getValueRequirement(), requirementFailure); } } return failure; } @Override public ResolutionFailure buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { FudgeField valueRequirementField = message.getByName(VALUE_REQUIREMENT_KEY); if (valueRequirementField == null) { ResolutionFailure failure = null; for (FudgeField field : message) { if ((field.getName() == null) && (field.getOrdinal() == null)) { final ResolutionFailure newFailure = buildObject(deserializer, (FudgeMsg) field.getValue()); if (failure == null) { failure = newFailure; } else { failure.merge(newFailure); } } } return failure; } else { final String error = message.getString(ERROR_KEY); final ValueRequirement valueRequirement = deserializer.fieldValueToObject(ValueRequirement.class, valueRequirementField); if (error != null) { switch (ResolutionFailure.Status.valueOf(error)) { case COULD_NOT_RESOLVE: return ResolutionFailureImpl.couldNotResolve(valueRequirement); case GET_ADDITIONAL_REQUIREMENTS_FAILED: return functionApplication(deserializer, message, valueRequirement).getAdditionalRequirementsFailed(); case GET_REQUIREMENTS_FAILED: return functionApplication(deserializer, message, valueRequirement).getRequirementsFailed(); case GET_RESULTS_FAILED: return functionApplication(deserializer, message, valueRequirement).getResultsFailed(); case LATE_RESOLUTION_FAILURE: return functionApplication(deserializer, message, valueRequirement).lateResolutionFailure(); case MARKET_DATA_MISSING: return ResolutionFailureImpl.marketDataMissing(valueRequirement); case NO_FUNCTIONS: return ResolutionFailureImpl.noFunctions(valueRequirement); case RECURSIVE_REQUIREMENT: return ResolutionFailureImpl.recursiveRequirement(valueRequirement); case SUPPRESSED: return functionApplication(deserializer, message, valueRequirement).suppressed(); case UNSATISFIED: return ResolutionFailureImpl.unsatisfied(valueRequirement); } throw new IllegalStateException(error); } else { return functionApplication(deserializer, message, valueRequirement); } } } }