/** *Copyright 2016 zhaojie * *Licensed under the Apache License, Version 2.0 (the "License"); *you may not use this file except in compliance with the License. *You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * *Unless required by applicable law or agreed to in writing, software *distributed under the License is distributed on an "AS IS" BASIS, *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *See the License for the specific language governing permissions and *limitations under the License. */ package com.api6.zkclient.leader; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.zookeeper.Watcher.Event.KeeperState; import com.api6.zkclient.ZKClient; import com.api6.zkclient.exception.ZKException; import com.api6.zkclient.listener.ZKStateListener; import com.api6.zkclient.lock.ZKDistributedLock; /** * 选举Leader * @author: zhaojie/[email protected] * @version: 2016年6月29日 下午8:51:03 */ public class ZKLeaderSelector implements LeaderSelector { private final String id; private final ZKClient client; private final ZKDistributedLock lock; private final String leaderPath; private final ExecutorService executorService; private final ZKLeaderSelectorListener listener; private final ZKStateListener stateListener; private final AtomicBoolean isInterrupted = new AtomicBoolean(false); private final AtomicBoolean autoRequeue = new AtomicBoolean(false); private final AtomicReference<Future<?>> ourTask = new AtomicReference<Future<?>>(null); private final AtomicReference<State> state = new AtomicReference<State>(State.LATENT); private enum State { LATENT, STARTED, CLOSED } /** * 创建Leader选举对象 * ZKLeaderSelector. * * @param id 每个Leader选举的参与者都有一个ID标识,用于区分各个参与者。 * @param autoRequue 是否在由于网络问题造成与服务器断开连接后,自动参与到选举队列中。 * @param client ZKClient * @param leaderPath 选举的路径 * @param listener 成为Leader后执行的的监听器 */ public ZKLeaderSelector(String id,Boolean autoRequue,ZKClient client, String leaderPath, ZKLeaderSelectorListener listener) { this.id = id; this.client = client; this.autoRequeue.set(autoRequue); this.leaderPath = leaderPath; this.lock = ZKDistributedLock.newInstance(client, leaderPath); this.lock.setLockNodeData(this.id); this.executorService = Executors.newSingleThreadExecutor(); this.listener = listener; this.stateListener = new ZKStateListener() { @Override public void handleStateChanged(KeeperState state) throws Exception { if(state == KeeperState.SyncConnected){//如果重新连接 if(isInterrupted.get() == false) { requeue(); } } } @Override public void handleSessionError(Throwable error) throws Exception { //ignore } @Override public void handleNewSession() throws Exception { //ignore } }; } /** * 启动参与选举Leader * @return void */ @Override public void start() { if (!state.compareAndSet(State.LATENT, State.STARTED)) { throw new ZKException("Cannot be started more than once"); } client.listenStateChanges(stateListener); requeue(); } /** * 重新添加当前线程到选举队列 * @return void */ @Override public synchronized void requeue() { if (state.get() != State.STARTED) { throw new ZKException("close() has already been called"); } isInterrupted.set(false); if(ourTask.get() != null) { ourTask.get().cancel(true); } Future<Void> task = executorService.submit(new Callable<Void>() { @Override public Void call() throws Exception { lock.lock(); listener.takeLeadership(client,ZKLeaderSelector.this); return null; } }); ourTask.set(task); } /** * 获得 * @return * @return String */ @Override public String getLeader() { if(lock.getParticipantNodes().size()>0){ return client.getData(leaderPath+"/"+lock.getParticipantNodes().get(0)); } return null; } @Override public boolean isLeader(){ if (client.getCurrentState() == KeeperState.SyncConnected ){ if(lock.getParticipantNodes().size()>0){ return id.equals(client.getData(leaderPath+"/"+lock.getParticipantNodes().get(0))); } } return false; } /** * 获得当前的所有参与者的路径名 * @return * @return List<String> */ @Override public List<String> getParticipantNodes(){ return lock.getParticipantNodes(); } /** * 终止等待成为Leader * @return void */ @Override public synchronized void interruptLeadership(){ Future<?> task = ourTask.get(); if ( task != null ) { task.cancel(true); } isInterrupted.set(true); } /** * 关闭Leader选举 * @return void */ @Override public synchronized void close() { if(!state.compareAndSet(State.STARTED, State.CLOSED)){ throw new ZKException("Already closed or has not been started"); } lock.unlock(); client.unlistenStateChanges(stateListener); executorService.shutdown(); ourTask.set(null); } }