org.neo4j.cluster.statemachine.StateMachine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ongdb-cluster Show documentation
Show all versions of ongdb-cluster Show documentation
Library implementing Paxos and Heartbeat components required for High Availability Neo4j
The newest version!
/*
* Copyright (c) 2018-2020 "Graph Foundation"
* Graph Foundation, Inc. [https://graphfoundation.org]
*
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of ONgDB Enterprise Edition. The included source
* code can be redistributed and/or modified under the terms of the
* GNU AFFERO GENERAL PUBLIC LICENSE Version 3
* (http://www.fsf.org/licensing/licenses/agpl-3.0.html) as found
* in the associated LICENSE.txt file.
*
* 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.
*/
package org.neo4j.cluster.statemachine;
import java.util.ArrayList;
import java.util.List;
import org.neo4j.cluster.com.message.Message;
import org.neo4j.cluster.com.message.MessageHolder;
import org.neo4j.cluster.com.message.MessageType;
import org.neo4j.logging.LogProvider;
/**
* State machine that wraps a context and a state, which can change when a Message comes in.
* Incoming messages must be of the particular type that the state understands.
* A state machine can only handle one message at a time, so the handle message is synchronized.
*/
public class StateMachine
{
private CONTEXT context;
private Class messageEnumType;
private State state;
private LogProvider logProvider;
private List listeners = new ArrayList<>();
public StateMachine( CONTEXT context, Class messageEnumType, State state,
LogProvider logProvider )
{
this.context = context;
this.messageEnumType = messageEnumType;
this.state = state;
this.logProvider = logProvider;
}
public Class getMessageType()
{
return messageEnumType;
}
public State getState()
{
return state;
}
public Object getContext()
{
return context;
}
public void addStateTransitionListener( StateTransitionListener listener )
{
List newlisteners = new ArrayList<>( listeners );
newlisteners.add( listener );
listeners = newlisteners;
}
public void removeStateTransitionListener( StateTransitionListener listener )
{
List newListeners = new ArrayList<>( listeners );
newListeners.remove( listener );
listeners = newListeners;
}
public synchronized void handle( Message message, MessageHolder outgoing )
{
try
{
// Let the old state handle the incoming message and tell us what the new state should be
State oldState = state;
State newState = oldState.handle( context, message, outgoing );
state = newState;
// Notify any listeners of the new state
StateTransition transition = new StateTransition( oldState, message, newState );
for ( StateTransitionListener listener : listeners )
{
try
{
listener.stateTransition( transition );
}
catch ( Throwable e )
{
// Ignore
logProvider.getLog( listener.getClass() ).warn( "Listener threw exception", e );
}
}
}
catch ( Throwable throwable )
{
logProvider.getLog( getClass() ).warn( "Exception in message handling", throwable );
}
}
@Override
public String toString()
{
return state.toString() + ": " + context.toString();
}
}