/*************************************************************************** * Copyright (C) by Fabrizio Montesi * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * For details about the authors of this software, see the AUTHORS file. * ***************************************************************************/ package jolie.net; import java.io.Serializable; import java.util.concurrent.atomic.AtomicLong; import jolie.lang.parse.ast.InterfaceDefinition; import jolie.runtime.FaultException; import jolie.runtime.Value; /** * A <code>CommMessage</code> represents a generic communication message. * A message is composed by the following parts: * <ul> * <li>a numeric identifier, which can be used to relate a response to its request;</li> * <li>an operation name, * to identify the operation that the message is meant for * (in case of a request) or the operation that generated the message * (in case of a response);</li> * <li>a resource path, used for redirection;</li> * <li>a value, holding the message data;</li> * <li>potentially, a fault.</li> * </ul> * * Message instances destined to be used in a Request-Response pattern * should always be created using the static methods * {@link #createRequest(java.lang.String, java.lang.String, jolie.runtime.Value) createRequest} * and {@link #createResponse(jolie.net.CommMessage, jolie.runtime.Value) createResponse}. * * @author Fabrizio Montesi */ public class CommMessage implements Serializable { private static final long serialVersionUID = 1L; private static final AtomicLong idCounter = new AtomicLong( 1L ); public static final long GENERIC_ID = 0L; public static final CommMessage UNDEFINED_MESSAGE = new CommMessage( GENERIC_ID, "", "/", Value.UNDEFINED_VALUE, null ); private final long id; private final String operationName; private final String resourcePath; private final Value value; private final InterfaceDefinition iface; private final String destination; private final FaultException fault; /** * Returns the resource path of this message. * @return the resource path of this message */ public String resourcePath() { return resourcePath; } /** * Returns the destination name of the message, can be null. * @return the name of the port/location associated with this message or null */ public String getDestination(){ return destination; } /** * Returns the interface of the message, can be null. * @return the interface of the this message or null */ public InterfaceDefinition getInterfaceDefinition(){ return iface; } /** * Returns <code>true</code> if this message has a generic identifier, <code>false</code> otherwise. * * A message with a generic identifier cannot be related to other messages. * * A message can have a generic identifier if it is meant to be used in a Notification. * Also, communication channels not supporting message identifiers could be generating * messages equipped with a generic identifier every time. * @return <code>true</code> if this message has a generic identifier, <code>false</code> otherwise */ public boolean hasGenericId() { return id == GENERIC_ID; } /** * Returns the identifier of this message. * @return the identifier of this message */ public long id() { return id; } private static long getNewMessageId() { return idCounter.getAndIncrement(); } /** * Creates a request message. * @param operationName the name of the operation this request is meant for * @param resourcePath the resource path of this message * @param value the message data * @return a request message as per specified by the parameters */ public static CommMessage createRequest( String operationName, String resourcePath, Value value ) { return new CommMessage( getNewMessageId(), operationName, resourcePath, Value.createDeepCopy( value ), null ); } public static CommMessage createRequest(String operationName, String resourcePath,InterfaceDefinition iface, String destination, Value value) { return new CommMessage(getNewMessageId(), operationName, resourcePath,iface, destination,Value.createDeepCopy(value), null); } /** * Creates an empty (i.e. without data) response for the passed request. * @param request the request message that caused this response * @return an empty response for the passed request */ public static CommMessage createEmptyResponse( CommMessage request ) { return createResponse( request, Value.create() ); } /** * Creates a response for the passed request. * @param request the request message that caused this response * @param value the data to equip the response with * @return a response for the passed request */ public static CommMessage createResponse( CommMessage request, Value value ) { //TODO support resourcePath return new CommMessage( request.id, request.operationName, "/", Value.createDeepCopy( value ), null ); } /** * Creates a response message equipped with the passed fault. * @param request the request message that caused this response * @param fault the fault to equip the response with * @return a response message equipped with the specified fault */ public static CommMessage createFaultResponse( CommMessage request, FaultException fault ) { //TODO support resourcePath return new CommMessage( request.id, request.operationName, "/", Value.create(), fault ); } /** * Constructor * @param id the identifier for this message * @param operationName the operation name for this message * @param resourcePath the resource path for this message * @param value the message data to equip the message with * @param fault the fault to equip the message with */ public CommMessage( long id, String operationName, String resourcePath, Value value, FaultException fault ) { this.id = id; this.operationName = operationName; this.resourcePath = resourcePath; this.value = value; this.fault = fault; this.iface = null; this.destination = null; } /** * Constructor * @param id the identifier for this message * @param operationName the operation name for this message * @param resourcePath the resource path for this message * @param iface the interface for this message. * @param destination the destination id for this message * @param value the message data to equip the message with * @param fault the fault to equip the message with */ public CommMessage( long id, String operationName, String resourcePath,InterfaceDefinition iface, String destination, Value value, FaultException fault ) { this.id = id; this.operationName = operationName; this.resourcePath = resourcePath; this.value = value; this.destination = destination; this.fault = fault; this.iface = iface; } /** * Constructor. The identifier of this message will be generic. * @param operationName the operation name for this message * @param resourcePath the resource path for this message * @param value the message data to equip the message with * @param fault the fault to equip the message with */ /*private CommMessage( String operationName, String resourcePath, Value value, FaultException f ) { this( GENERIC_ID, operationName, resourcePath, value, f ); }*/ /** * Constructor. The identifier of this message will be generic. * @param operationName the operation name of this message * @param resourcePath the resource path of this message */ /*private CommMessage( String operationName, String resourcePath ) { this( GENERIC_ID, operationName, resourcePath, Value.create(), null ); } private CommMessage( long id, String operationName, String resourcePath, Value value ) { this( id, operationName, resourcePath, value, null ); } private CommMessage( long id, String operationName, String resourcePath, FaultException fault ) { this( id, operationName, resourcePath, Value.create(), fault ); }*/ /** * Constructor. The identifier of this message will be generic. * @param operationName the operation name for this message * @param resourcePath the resource path for this message * @param value the message data to equip the message with */ /*private CommMessage( String operationName, String resourcePath, Value value ) { this( GENERIC_ID, operationName, resourcePath, value, null ); }*/ /** * Returns the value representing the data contained in this message. * @return the value representing the data contained in this message */ public Value value() { return value; } /** * The operation name of this message. * @return the operation name of this message */ public String operationName() { return operationName; } /** * Returns <code>true</code> if this message contains a fault, <code>false</code> otherwise. * @return <code>true</code> if this message contains a fault, <code>false</code> otherwise */ public boolean isFault() { return ( fault != null ); } /** * Returns the fault contained in this message. * * If this message does not contain a fault, <code>null</code> is returned. * @return the fault contained in this message */ public FaultException fault() { return fault; } }