All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.cluster.statemachine.StateMachine Maven / Gradle / Ivy

Go to download

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();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy