/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cluster.com.message;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* Message for state machines which can be sent out to instances in the cluster as well.
*
* These are typically produced and consumed by a {@link org.neo4j.cluster.statemachine.StateMachine}.
*/
public class Message<MESSAGETYPE extends MessageType>
implements Serializable
{
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> broadcast(MESSAGETYPE messageType)
{
return broadcast(messageType, null);
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> broadcast(MESSAGETYPE messageType, Object payload)
{
return new Message<MESSAGETYPE>(messageType, payload).setHeader( TO, BROADCAST );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> to(MESSAGETYPE messageType, Object to)
{
return to( messageType, to, null );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> to(MESSAGETYPE messageType, Object to, Object payload)
{
return new Message<MESSAGETYPE>(messageType, payload).setHeader( TO, to.toString() );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> respond(MESSAGETYPE messageType, Message<?> message, Object payload)
{
return new Message<MESSAGETYPE>(messageType, payload).setHeader( TO, message.getHeader( Message.FROM ));
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> internal(MESSAGETYPE message)
{
return internal( message, null );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> internal(MESSAGETYPE message, Object payload)
{
return new Message<MESSAGETYPE>( message, payload );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> timeout(MESSAGETYPE message, Message<?> causedBy)
{
return timeout( message, causedBy, null );
}
public static <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> timeout(MESSAGETYPE message, Message<?> causedBy, Object payload)
{
return causedBy.copyHeadersTo( new Message<MESSAGETYPE>( message, payload ), Message.CONVERSATION_ID, Message.CREATED_BY);
}
// Standard headers
public static final String CONVERSATION_ID = "conversation-id";
public static final String CREATED_BY = "created-by";
public static final String FROM = "from";
public static final String TO = "to";
public static final String BROADCAST = "*";
final private MESSAGETYPE messageType;
final private Object payload;
final private Map<String,String> headers = new HashMap<String, String>( );
protected Message( MESSAGETYPE messageType, Object payload )
{
this.messageType = messageType;
this.payload = payload;
}
public MESSAGETYPE getMessageType()
{
return messageType;
}
public <T> T getPayload()
{
return (T) payload;
}
public Message<MESSAGETYPE> setHeader(String name, String value)
{
headers.put( name, value );
return this;
}
public boolean hasHeader(String name)
{
return headers.containsKey( name );
}
public boolean isInternal()
{
return !headers.containsKey( Message.TO );
}
public boolean isBroadcast()
{
return !isInternal() && getHeader( Message.TO ).equals( BROADCAST );
}
public String getHeader(String name)
throws IllegalArgumentException
{
String value = headers.get( name );
if (value == null)
{
throw new IllegalArgumentException( "No such header:"+name );
}
return value;
}
public <MESSAGETYPE extends MessageType> Message<MESSAGETYPE> copyHeadersTo( Message<MESSAGETYPE> message, String... names )
{
if (names.length == 0)
{
for( Map.Entry<String, String> header : headers.entrySet() )
{
message.setHeader( header.getKey(), header.getValue() );
}
} else
{
for( String name : names )
{
String value = headers.get( name );
if (value != null)
message.setHeader( name, value );
}
}
return message;
}
@Override
public String toString()
{
return messageType.name()+headers+(payload != null && payload instanceof String ? ": "+payload : "");
}
}