/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.protocol;
import java.io.Serializable;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.core.communication.common.InstanceNodeSessionId;
import de.rcenvironment.core.communication.common.SerializationException;
import de.rcenvironment.core.communication.model.NetworkRequest;
import de.rcenvironment.core.communication.model.NetworkResponse;
import de.rcenvironment.core.communication.model.impl.NetworkResponseImpl;
import de.rcenvironment.core.communication.protocol.ProtocolConstants.ResultCode;
import de.rcenvironment.core.communication.utils.MessageUtils;
import de.rcenvironment.core.utils.common.StringUtils;
/**
* Convenience factory for {@link NetworkResponse}s.
*
* @author Robert Mischke
*/
public final class NetworkResponseFactory {
private NetworkResponseFactory() {}
/**
* Creates a response using raw response bytes.
*
* @param request the associated request
* @param responseBody the byte array to send as response payload
* @return the generated response
*/
public static NetworkResponse generateSuccessResponse(NetworkRequest request, byte[] responseBody) {
return new NetworkResponseImpl(responseBody, request.getRequestId(), ProtocolConstants.ResultCode.SUCCESS);
}
/**
* Creates a response using a Serializable response object.
*
* @param request the associated request
* @param responseBody the {@link Serializable} to send as response payload
* @return the generated response
* @throws SerializationException on serialization failure
*/
public static NetworkResponse generateSuccessResponse(NetworkRequest request, Serializable responseBody) throws SerializationException {
byte[] contentBytes = MessageUtils.serializeObject(responseBody);
return new NetworkResponseImpl(contentBytes, request.getRequestId(), ProtocolConstants.ResultCode.SUCCESS);
}
/**
* Creates a response (typically on the caller side) from a received result code, and raw response bytes.
*
* @param request the associated request
* @param responseBody the byte array to use as the response payload
* @param resultCode the numeric result code
* @return the generated response
*/
public static NetworkResponse generateResponseWithResultCode(NetworkRequest request, byte[] responseBody, int resultCode) {
ResultCode resultCodeEnum = ResultCode.fromCode(resultCode); // may return INVALID RESULT_CODE if the code is unknown
return new NetworkResponseImpl(responseBody, request.getRequestId(), resultCodeEnum);
}
/**
* Generates a {@link NetworkResponse} indicating that a node did not find a valid route to forward the received request to.
*
* @param request the request
* @param localNodeId the id of the node where the failure occurred
* @return the generated response
*/
public static NetworkResponse generateResponseForNoRouteWhileForwarding(NetworkRequest request, InstanceNodeSessionId localNodeId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.NO_ROUTE_TO_DESTINATION_WHILE_FORWARDING, localNodeId, null);
}
/**
* Generates a {@link NetworkResponse} indicating that was no valid route to the destination at the initial sender.
*
* @param request the request
* @param localNodeId the id of the node where the failure occurred
* @return the generated response
*/
public static NetworkResponse generateResponseForNoRouteAtSender(NetworkRequest request, InstanceNodeSessionId localNodeId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.NO_ROUTE_TO_DESTINATION_AT_SENDER, localNodeId, null);
}
/**
* Generates a {@link NetworkResponse} indicating that an exception has occurred at the final destination of the request.
*
* @param request the request
* @param errorId the exception
* @return the generated response
*/
public static NetworkResponse generateResponseForInternalErrorAtRecipient(NetworkRequest request, String errorId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.EXCEPTION_AT_DESTINATION, request.accessMetaData()
.getFinalRecipient(), errorId);
}
/**
* Generates a {@link NetworkResponse} indicating that an exception has occured while forwarding/routing the request to its final
* destination.
*
* @param request the request
* @param eventNodeId the id of the node where the exception occured
* @param errorId an (optional) error id
* @return the generated response
*/
public static NetworkResponse generateResponseForErrorDuringDelivery(NetworkRequest request, InstanceNodeSessionId eventNodeId,
String errorId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.EXCEPTION_DURING_DELIVERY, eventNodeId, errorId);
}
/**
* Generates a {@link NetworkResponse} indicating that message forwarding/routing failed because one of the channels along the route has
* been marked as broken, but was not removed from the routing topology yet when the channel was selected (e.g. because of asynchronous
* queueing).
*
* @param request the request
* @param eventNodeId the id of the node where the exception occured
* @param errorId an (optional) error id
* @return the generated response
*/
public static NetworkResponse generateResponseForCloseOrBrokenChannelDuringRequestDelivery(NetworkRequest request,
InstanceNodeSessionId eventNodeId, String errorId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.CHANNEL_CLOSED_OR_BROKEN_BEFORE_SENDING_REQUEST, eventNodeId,
errorId);
}
/**
* Generates a {@link NetworkResponse} indicating that the request was successfully sent or forwarded, but that the local message
* channel was closed while waiting for the reponse.
*
* @param request the request
* @param eventNodeId the id of the node where the exception occured
* @param errorId an (optional) error id
* @return the generated response
*/
public static NetworkResponse generateResponseForChannelCloseWhileWaitingForResponse(NetworkRequest request,
InstanceNodeSessionId eventNodeId, String errorId) {
return generateErrorResponse(request,
ProtocolConstants.ResultCode.CHANNEL_OR_RESPONSE_LISTENER_SHUT_DOWN_WHILE_WAITING_FOR_RESPONSE, eventNodeId, errorId);
}
/**
* Generates a {@link NetworkResponse} indicating that a timeout occurred while waiting for the response after sending the request to
* the next hop.
*
* @param request the request
* @param eventNodeId the id of the node where the timeout occurred
* @return the generated response
*/
public static NetworkResponse generateResponseForTimeoutWaitingForResponse(NetworkRequest request, InstanceNodeSessionId eventNodeId) {
return generateErrorResponse(request, ProtocolConstants.ResultCode.TIMEOUT_WAITING_FOR_RESPONSE, eventNodeId, null);
}
private static NetworkResponse generateErrorResponse(NetworkRequest request, ResultCode resultCode,
InstanceNodeSessionId reporterNodeId, String errorId) {
errorId = StringUtils.nullSafe(errorId);
final String nodeIdString;
if (reporterNodeId != null) {
nodeIdString = StringUtils.nullSafe(reporterNodeId.getInstanceNodeSessionIdString());
} else {
nodeIdString = "<null>";
LogFactory.getLog(NetworkRequestFactory.class).warn("Observed <null> reporterNodeId");
}
// wrap into pre-defined format string
String errorInfoPayload = StringUtils.escapeAndConcat(errorId, nodeIdString);
// generate response
return new NetworkResponseImpl(MessageUtils.serializeSafeObject(errorInfoPayload), request.getRequestId(), resultCode);
}
private static String representErrorLocationAsString(InstanceNodeSessionId localNodeId) {
// note: there is a minimal information leak here by revealing what name the intermediate node assigns to itself; it's
// very unlikely that this a secret, yet the sender is allowed to route across this node, though - misc_ro
return localNodeId.toString(); // TODO before using this method again, check whether this should be a different conversion now
}
}