/** * Copyright 2016 vip.com. * <p> * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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. * </p> */ package com.vip.saturn.job.console.repository.zookeeper.impl; import java.nio.charset.Charset; import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.CuratorFrameworkFactory.Builder; import org.apache.curator.framework.api.ACLProvider; import org.apache.curator.framework.api.transaction.CuratorTransactionFinal; import org.apache.curator.framework.api.transaction.CuratorTransactionResult; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.utils.CloseableUtils; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.KeeperException.NodeExistsException; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; import com.google.common.base.Strings; import com.vip.saturn.job.console.exception.JobConsoleException; import com.vip.saturn.job.console.repository.zookeeper.CuratorRepository; import com.vip.saturn.job.console.utils.BooleanWrapper; import com.vip.saturn.job.console.utils.ThreadLocalCuratorClient; @Repository public class CuratorRepositoryImpl implements CuratorRepository { protected static Logger log = LoggerFactory.getLogger(CuratorRepositoryImpl.class); private static final int WAITING_SECONDS = 2; /** * 会话超时和连接超时时间 */ private static int CONNECTION_TIMEOUT = 10 * 1000; @Override public CuratorFramework connect(final String connectString, final String namespace, final String digest) { Builder builder = CuratorFrameworkFactory.builder().connectString(connectString) .sessionTimeoutMs(CONNECTION_TIMEOUT) .connectionTimeoutMs(CONNECTION_TIMEOUT) .retryPolicy(new RetryOneTime(1000)); if (namespace != null) { builder.namespace(namespace); } if (!Strings.isNullOrEmpty(digest)) { builder.authorization("digest", digest.getBytes()) .aclProvider(new ACLProvider() { @Override public List<ACL> getDefaultAcl() { return ZooDefs.Ids.CREATOR_ALL_ACL; } @Override public List<ACL> getAclForPath(final String path) { return ZooDefs.Ids.CREATOR_ALL_ACL; } }); } CuratorFramework client = builder.build(); client.start(); boolean established = false; try { established = client.blockUntilConnected(WAITING_SECONDS, TimeUnit.SECONDS); } catch (final InterruptedException ex) { Thread.currentThread().interrupt(); } if (established) { return client; } CloseableUtils.closeQuietly(client); return null; } class CuratorFrameworkOpImpl implements CuratorFrameworkOp { private CuratorFramework curatorFramework; public CuratorFrameworkOpImpl(CuratorFramework curatorFramework) { this.curatorFramework = curatorFramework; } @Override public boolean checkExists(final String znode) { try { return null != curatorFramework.checkExists().forPath(znode); //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public String getData(final String znode) { try { if (checkExists(znode)) { byte[] getZnodeData = curatorFramework.getData().forPath(znode); if (getZnodeData == null) {// executor的分片可能存在全部飘走的情况,sharding节点有可能获取到的是null,需要对null做判断,否则new String时会报空指针异常 return null; } return new String(getZnodeData, Charset.forName("UTF-8")); } else { return null; } } catch (final NoNodeException ex) { return null; //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public List<String> getChildren(final String znode) { try { return curatorFramework.getChildren().forPath(znode); //CHECKSTYLE:OFF } catch (final NoNodeException ex) { return null; //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public void create(final String znode) { create(znode, ""); } @Override public void create(final String znode, Object data) { try { curatorFramework.create().creatingParentsIfNeeded().forPath(znode, data.toString().getBytes()); } catch (final NodeExistsException ex) { //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } public void update(final String znode, final Object value) { try { if (this.checkExists(znode)) { curatorFramework.inTransaction().check().forPath(znode).and().setData().forPath(znode, value.toString().getBytes(Charset.forName("UTF-8"))).and().commit(); } else { this.create(znode, value); } } catch (final NoNodeException ex) { //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public void delete(final String znode) { try { if (null != curatorFramework.checkExists().forPath(znode)) { curatorFramework.delete().forPath(znode); } } catch (final NoNodeException ex) { //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public void deleteRecursive(final String znode) { try { if (null != curatorFramework.checkExists().forPath(znode)) { curatorFramework.delete().deletingChildrenIfNeeded().forPath(znode); } } catch (final NoNodeException ex) { ex.printStackTrace(); //CHECKSTYLE:OFF } catch (final Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } /** * 如果节点不存在则填充节点数据. * * @param node 作业节点名称 * @param value 作业节点数据值 */ @Override public void fillJobNodeIfNotExist(final String node, final Object value) { if (null == value) { log.info("job node value is null, node:{}", node); return; } if (!checkExists(node)) { try { curatorFramework.create().creatingParentsIfNeeded().forPath(node, value.toString().getBytes()); } catch (Exception e) { log.error(e.getMessage(), e); } } } /** * 默认会check根路径 */ @Override public CuratorTransactionOp inTransaction() { try { return new CuratorTransactionOpImpl(curatorFramework); } catch (Exception ex) { //CHECKSTYLE:ON throw new JobConsoleException(ex); } } class CuratorTransactionOpImpl implements CuratorTransactionOp { private CuratorTransactionFinal curatorTransactionFinal; private CuratorFramework curatorClient; public CuratorTransactionOpImpl(CuratorFramework curatorClient) { this.curatorClient = curatorClient; try { curatorTransactionFinal = curatorClient.inTransaction().check().forPath("/").and(); } catch (final Exception ex) { throw new JobConsoleException(ex); } } private boolean checkExists(String znode) throws Exception { return curatorClient.checkExists().forPath(znode) != null; } private CuratorTransactionOpImpl create(String znode, byte[] data) throws Exception { curatorTransactionFinal = curatorTransactionFinal.create().forPath(znode, data).and(); return this; } private byte[] getData(String znode) throws Exception { return curatorClient.getData().forPath(znode); } private byte[] toData(Object value) { return (value == null ? "" : value.toString()).getBytes(Charset.forName("UTF-8")); } private boolean bytesEquals(byte[] a, byte[] b) { if (a == null || b == null) { if (a == null && b == null) { return true; } else { return false; } } if (a.length != b.length) { return false; } for (int i = 0, size = a.length; i < size; i++) { if (a[i] != b[i]) { return false; } } return true; } public CuratorTransactionOpImpl replaceIfchanged(String znode, Object value) throws Exception { return replaceIfchanged(znode, value, new BooleanWrapper(false)); } public CuratorTransactionOpImpl replaceIfchanged(String znode, Object value, BooleanWrapper ifChanged) throws Exception { byte[] newData = toData(value); if (this.checkExists(znode)) { byte[] oldData = this.getData(znode); if (!bytesEquals(newData, oldData)) { curatorTransactionFinal = curatorTransactionFinal.check().forPath(znode).and().setData().forPath(znode, newData).and(); ifChanged.setValue(true); } } else { this.create(znode, newData); } return this; } @Override public CuratorTransactionOpImpl create(String znode) throws Exception { curatorTransactionFinal = curatorTransactionFinal.create().forPath(znode).and(); return this; } @Override public Collection<CuratorTransactionResult> commit() throws Exception { return curatorTransactionFinal.commit(); } } @Override public long getMtime(String node) { try { Stat stat = curatorFramework.checkExists().forPath(node); if (stat != null) { return stat.getMtime(); } else { return 0l; } } catch (final Exception ex) { // CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public long getCtime(String node) { try { Stat stat = curatorFramework.checkExists().forPath(node); if (stat != null) { return stat.getCtime(); } else { return 0l; } } catch (final Exception ex) { // CHECKSTYLE:ON throw new JobConsoleException(ex); } } @Override public CuratorFramework getCuratorFramework() { return curatorFramework; } } @Override public CuratorFrameworkOp inSessionClient() { return new CuratorFrameworkOpImpl(ThreadLocalCuratorClient.getCuratorClient()); } @Override public CuratorFrameworkOp newCuratorFrameworkOp(CuratorFramework curatorFramework) { return new CuratorFrameworkOpImpl(curatorFramework); } }