/** * 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.protocol.cluster; import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.LearnerContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.ProposerContext; import org.neo4j.cluster.timeout.Timeouts; import org.neo4j.helpers.Listeners; import org.neo4j.kernel.impl.util.StringLogger; import org.neo4j.kernel.logging.Loggers; import org.neo4j.kernel.logging.Logging; /** * Context for cluster API state machine * * @see ClusterState */ public class ClusterContext { URI me; Iterable<ClusterListener> listeners = Listeners.newListeners(); ProposerContext proposerContext; LearnerContext learnerContext; public ClusterConfiguration configuration; public final Timeouts timeouts; private Executor executor; private Logging logging; public ClusterContext( ProposerContext proposerContext, LearnerContext learnerContext, ClusterConfiguration configuration, Timeouts timeouts, Executor executor, Logging logging ) { this.proposerContext = proposerContext; this.learnerContext = learnerContext; this.configuration = configuration; this.timeouts = timeouts; this.executor = executor; this.logging = logging; } // Cluster API public void addClusterListener( ClusterListener listener ) { listeners = Listeners.addListener( listener, listeners ); } public void removeClusterListener( ClusterListener listener ) { listeners = Listeners.removeListener( listener, listeners ); } // Implementation public void created( String name ) { configuration = new ClusterConfiguration( name, Collections.singleton( me ) ); Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.enteredCluster( configuration ); } } ); } public void acquiredConfiguration( final List<URI> memberList, final Map<String, URI> roles ) { configuration.setMembers( memberList ); configuration.setRoles( roles ); } public void joined() { configuration.joined( me ); Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.enteredCluster( configuration ); } } ); } public void left() { timeouts.cancelAllTimeouts(); configuration.left(); Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.leftCluster(); } } ); } public void joined( final URI node ) { if ( configuration.getMembers().contains( node ) ) { return; // Already know that this node is in - ignore } configuration.joined( node ); if ( configuration.getMembers().contains( me ) ) { // Make sure this node is in cluster before notifying of others joining and leaving Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.joinedCluster( node ); } } ); } else { // This typically happens in situations when several nodes join at once, and the ordering // of join messages is a little out of whack. } } public void left( final URI node ) { configuration.left( node ); Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.leftCluster( node ); } } ); } public void elected( final String name, final URI node ) { if ( !node.equals( configuration.getElected( name ) ) ) { configuration.elected( name, node ); Listeners.notifyListeners( listeners, executor, new Listeners.Notification<ClusterListener>() { @Override public void notify( ClusterListener listener ) { listener.elected( name, node ); } } ); } } public synchronized void setMe( URI me ) { this.me = me; } public URI getMe() { return me; } public ClusterConfiguration getConfiguration() { return configuration; } public synchronized boolean isMe( URI server ) { return me.equals( server ); } public boolean isElectedAs( String roleName ) { return me.equals( configuration.getElected( roleName ) ); } public boolean isInCluster() { return !configuration.getMembers().isEmpty(); } public StringLogger getLogger() { return logging.getLogger( Loggers.CLUSTER ); } @Override public String toString() { return "Me: " + me + " Config:" + configuration; } }