/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.communication.protocol; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import de.rcenvironment.core.communication.common.InstanceNodeSessionId; import de.rcenvironment.core.communication.model.NetworkRequest; import de.rcenvironment.core.communication.model.impl.NetworkRequestImpl; /** * Central factory for {@link NetworkRequest} instances. Encapsulates metadata generation and reconstruction of {@link NetworkRequest}s from * received metadata. * * @author Robert Mischke */ public final class NetworkRequestFactory { // TODO add consistent requestId handling private NetworkRequestFactory() {} /** * Generates a new {@link NetworkRequest} for sending. * * @param contentBytes the serialized message body * @param messageType the message type; see {@link ProtocolConstants} * @param sender the sender * @param finalRecipient the final receiver/destination of the request; can be null if no forwarding is required * @return the generated {@link NetworkRequest} */ public static NetworkRequest createNetworkRequest(byte[] contentBytes, String messageType, InstanceNodeSessionId sender, InstanceNodeSessionId finalRecipient) { MessageMetaData metaData = MessageMetaData.create(); metaData.setMessageType(messageType); metaData.setSender(sender); if (finalRecipient != null) { metaData.setFinalRecipient(finalRecipient); } metaData.addTraceStep(sender.getInstanceNodeSessionIdString()); // TODO refactor: remove unwrapping/wrapping return new NetworkRequestImpl(contentBytes, metaData.getInnerMap()); } /** * Generates a new {@link NetworkRequest} to forward when a {@link NetworkRequest} with a different destination than the local node was * received. * * This method takes care of hop count incrementing, route tracing, and sanity checking that the message is actually valid for * forwarding. * * @param receivedRequest the {@link NetworkRequest} that arrived at the local node * @param localNodeId the {@link InstanceNodeSessionId} of the local node (NOT the recipient!) * @return the generated {@link NetworkRequest} for forwarding */ public static NetworkRequest createNetworkRequestForForwarding(NetworkRequest receivedRequest, InstanceNodeSessionId localNodeId) { MessageMetaData newMetadata = MessageMetaData.cloneAndWrap(receivedRequest.accessRawMetaData()); // TODO check TTL? // TODO check for valid message type? newMetadata.incHopCount(); newMetadata.addTraceStep(localNodeId.getInstanceNodeSessionIdString()); // the 3.0.0 approach is to maintain the original request id; change if necessary - misc_ro String requestIdToMaintain = receivedRequest.getRequestId(); return new NetworkRequestImpl(receivedRequest.getContentBytes(), newMetadata.getInnerMap(), requestIdToMaintain); } /** * Reconstructs a {@link NetworkRequest} from the serialized body and metadata received by the transport implementation. * * @param contentBytes the serialized message body * @param metaData the message metadata as passed by the transport implementation * @return the reconstructed {@link NetworkRequest} */ public static NetworkRequest reconstructNetworkRequest(byte[] contentBytes, Map<String, String> metaData) { return new NetworkRequestImpl(contentBytes, metaData); } /** * Creates a new {@link NetworkRequest} that is independent of the original, i.e. changes to one instance will not affect the other. * Useful to avoid side effects during in-JVM testing. * * @param request the original request * @return the independent clone */ public static NetworkRequestImpl createDetachedClone(NetworkRequest request) { // clone the content array byte[] originalContent = request.getContentBytes(); final byte[] detachedContentBytes = Arrays.copyOf(originalContent, originalContent.length); // clone the metadata; a shallow copy is sufficient as it is a String/String map final Map<String, String> clonedRequestMetaData = new HashMap<String, String>(request.accessRawMetaData()); NetworkRequestImpl clonedRequest = new NetworkRequestImpl(detachedContentBytes, clonedRequestMetaData, request.getRequestId()); return clonedRequest; } /** * Creates a clone of the given {@link NetworkRequest}, but with a new, unique request id. Intended for cases where a sender is * broadcasting the same request to multiple recipients. * * Note that the payload bytes are not detached from the original request; modifications to one would affect the other. This is * irrelevant, though, as modifying the payload array after creation is neither intended nor supported. The metadata map, however, is * detached. * * @param request the original request * @return a clone with shared payload data, detached metadat properties, and a new request id within these properties */ public static NetworkRequest cloneWithNewRequestId(NetworkRequest request) { Map<String, String> newMetaData = new HashMap<String, String>(request.accessRawMetaData()); // note: the new request id is automatically assigned by the constructor return new NetworkRequestImpl(request.getContentBytes(), newMetaData); } }