org.apache.ambari.datastore.ZookeeperDS.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ambari.datastore.ZookeeperDS.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.ambari.datastore;

import java.io.IOException;
import java.util.List;

import org.apache.ambari.common.rest.entities.ClusterDefinition;
import org.apache.ambari.common.rest.entities.ClusterState;
import org.apache.ambari.common.rest.entities.Stack;
import org.apache.ambari.common.util.JAXBUtil;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * Implementation of the data store based on Zookeeper.
 */
class ZookeeperDS implements DataStore, Watcher {

    private static final String ZOOKEEPER_ROOT_PATH = "/ambari";
    private static final String ZOOKEEPER_CLUSTERS_ROOT_PATH = ZOOKEEPER_ROOT_PATH + "/clusters";
    private static final String ZOOKEEPER_STACKS_ROOT_PATH = ZOOKEEPER_ROOT_PATH + "/stacks";

    private ZooKeeper zk;
    private String credential = null;
    private boolean zkCoonected = false;

    ZookeeperDS(String authority) {
        try {
            /*
             * Connect to ZooKeeper server
             */
            zk = new ZooKeeper(authority, 600000, this);
            if (credential != null) {
                zk.addAuthInfo("digest", credential.getBytes());
            }

            while (!this.zkCoonected) {
                System.out.println("Waiting for ZK connection!");
                Thread.sleep(2000);
            }

            /*
             * Create top level directories
             */
            createDirectory(ZOOKEEPER_ROOT_PATH, new byte[0], true);
            createDirectory(ZOOKEEPER_CLUSTERS_ROOT_PATH, new byte[0], true);
            createDirectory(ZOOKEEPER_STACKS_ROOT_PATH, new byte[0], true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() throws IOException {
        // PASS
    }

    @Override
    public boolean clusterExists(String clusterName) throws IOException {
        try {
            if (zk.exists(ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName, false) == null) {
                return false;
            }
        } catch (Exception e) {
            throw new IOException(e);
        }
        return true;
    }

    @Override
    public synchronized int storeClusterDefinition(ClusterDefinition clusterDef) throws IOException {
        /*
         * Update the cluster node
         */
        try {
            Stat stat = new Stat();
            String clusterPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterDef.getName();
            int newRev = 0;
            String clusterRevisionPath = clusterPath + "/" + newRev;
            String clusterLatestRevisionNumberPath = clusterPath + "/latestRevisionNumber";
            if (zk.exists(clusterPath, false) == null) {
                /* 
                 * create cluster path with revision 0, create cluster latest revision
                 * node storing the latest revision of cluster definition.
                 */
                createDirectory(clusterPath, new byte[0], false);
                createDirectory(clusterRevisionPath, JAXBUtil.write(clusterDef), false);
                createDirectory(clusterLatestRevisionNumberPath, (new Integer(newRev)).toString().getBytes(),
                        false);
            } else {
                String latestRevision = new String(zk.getData(clusterLatestRevisionNumberPath, false, stat));
                newRev = Integer.parseInt(latestRevision) + 1;
                clusterRevisionPath = clusterPath + "/" + newRev;
                /*
                 * If client passes the revision number of the checked out cluster 
                 * definition following code checks if you are updating the same version
                 * that you checked out.
                 */
                if (clusterDef.getRevision() != null) {
                    if (!latestRevision.equals(clusterDef.getRevision())) {
                        throw new IOException(
                                "Latest cluster definition does not match " + "the one client intends to modify!");
                    }
                }
                createDirectory(clusterRevisionPath, JAXBUtil.write(clusterDef), false);
                zk.setData(clusterLatestRevisionNumberPath, (new Integer(newRev)).toString().getBytes(), -1);
            }
            return newRev;
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e1) {
            throw new IOException(e1);
        }
    }

    @Override
    public synchronized void storeClusterState(String clusterName, ClusterState clsState) throws IOException {
        /*
         * Update the cluster state
         */
        try {
            String clusterStatePath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName + "/state";
            if (zk.exists(clusterStatePath, false) == null) {
                // create node for the cluster state
                createDirectory(clusterStatePath, JAXBUtil.write(clsState), false);
            } else {
                zk.setData(clusterStatePath, JAXBUtil.write(clsState), -1);
            }
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e1) {
            throw new IOException(e1);
        }

    }

    @Override
    public ClusterDefinition retrieveClusterDefinition(String clusterName, int revision) throws IOException {
        try {
            Stat stat = new Stat();
            String clusterRevisionPath;
            if (revision < 0) {
                String clusterLatestRevisionNumberPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName
                        + "/latestRevisionNumber";
                String latestRevisionNumber = new String(zk.getData(clusterLatestRevisionNumberPath, false, stat));
                clusterRevisionPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName + "/" + latestRevisionNumber;
            } else {
                clusterRevisionPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName + "/" + revision;
            }
            ClusterDefinition cdef = JAXBUtil.read(zk.getData(clusterRevisionPath, false, stat),
                    ClusterDefinition.class);
            return cdef;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public ClusterState retrieveClusterState(String clusterName) throws IOException {
        try {
            Stat stat = new Stat();
            String clusterStatePath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName + "/state";
            ClusterState clsState = JAXBUtil.read(zk.getData(clusterStatePath, false, stat), ClusterState.class);
            return clsState;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public int retrieveLatestClusterRevisionNumber(String clusterName) throws IOException {
        int revisionNumber;
        try {
            Stat stat = new Stat();
            String clusterLatestRevisionNumberPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName
                    + "/latestRevisionNumber";
            String latestRevisionNumber = new String(zk.getData(clusterLatestRevisionNumberPath, false, stat));
            revisionNumber = Integer.parseInt(latestRevisionNumber);
        } catch (Exception e) {
            throw new IOException(e);
        }
        return revisionNumber;
    }

    @Override
    public List<String> retrieveClusterList() throws IOException {
        try {
            List<String> children = zk.getChildren(ZOOKEEPER_CLUSTERS_ROOT_PATH, false);
            return children;
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void deleteCluster(String clusterName) throws IOException {
        String clusterPath = ZOOKEEPER_CLUSTERS_ROOT_PATH + "/" + clusterName;
        List<String> children;
        try {
            children = zk.getChildren(clusterPath, false);
            // Delete all the children and then the parent node
            for (String childPath : children) {
                try {
                    zk.delete(childPath, -1);
                } catch (KeeperException.NoNodeException ke) {
                } catch (Exception e) {
                    throw new IOException(e);
                }
            }
            zk.delete(clusterPath, -1);
        } catch (KeeperException.NoNodeException ke) {
            return;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public int storeStack(String stackName, Stack stack) throws IOException {
        try {
            Stat stat = new Stat();
            String stackPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName;
            int newRev = 0;
            String stackRevisionPath = stackPath + "/" + newRev;
            String stackLatestRevisionNumberPath = stackPath + "/latestRevisionNumber";
            if (zk.exists(stackPath, false) == null) {
                /* 
                 * create stack path with revision 0, create stack latest revision node
                 * to store the latest revision of stack definition.
                 */
                createDirectory(stackPath, new byte[0], false);
                stack.setRevision(new Integer(newRev).toString());
                createDirectory(stackRevisionPath, JAXBUtil.write(stack), false);
                createDirectory(stackLatestRevisionNumberPath, (new Integer(newRev)).toString().getBytes(), false);
            } else {
                String latestRevision = new String(zk.getData(stackLatestRevisionNumberPath, false, stat));
                newRev = Integer.parseInt(latestRevision) + 1;
                stackRevisionPath = stackPath + "/" + newRev;
                /*
                 * TODO: like cluster definition client can pass optionally the checked 
                 * out version number
                 * Following code checks if you are updating the same version that you 
                 * checked out.
                 * if (stack.getRevision() != null) {
                 *   if (!latestRevision.equals(stack.getRevision())) {
                 *     throw new IOException ("Latest cluster definition does not " + 
                 *                           "match the one client intends to modify!");
                 *   }  
                 * } 
                 */
                stack.setRevision(new Integer(newRev).toString());
                createDirectory(stackRevisionPath, JAXBUtil.write(stack), false);
                zk.setData(stackLatestRevisionNumberPath, (new Integer(newRev)).toString().getBytes(), -1);
            }
            return newRev;
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e1) {
            throw new IOException(e1);
        }
    }

    @Override
    public Stack retrieveStack(String stackName, int revision) throws IOException {
        try {
            Stat stat = new Stat();
            String stackRevisionPath;
            if (revision < 0) {
                String stackLatestRevisionNumberPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName
                        + "/latestRevisionNumber";
                String latestRevisionNumber = new String(zk.getData(stackLatestRevisionNumberPath, false, stat));
                stackRevisionPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName + "/" + latestRevisionNumber;
            } else {
                stackRevisionPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName + "/" + revision;
            }
            Stack stack = JAXBUtil.read(zk.getData(stackRevisionPath, false, stat), Stack.class);
            return stack;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public List<String> retrieveStackList() throws IOException {
        try {
            List<String> children = zk.getChildren(ZOOKEEPER_STACKS_ROOT_PATH, false);
            return children;
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }

    @Override
    public int retrieveLatestStackRevisionNumber(String stackName) throws IOException {
        int revisionNumber;
        try {
            Stat stat = new Stat();
            String stackLatestRevisionNumberPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName
                    + "/latestRevisionNumber";
            String latestRevisionNumber = new String(zk.getData(stackLatestRevisionNumberPath, false, stat));
            revisionNumber = Integer.parseInt(latestRevisionNumber);
        } catch (Exception e) {
            throw new IOException(e);
        }
        return revisionNumber;
    }

    @Override
    public void deleteStack(String stackName) throws IOException {
        String stackPath = ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName;
        List<String> children;
        try {
            children = zk.getChildren(stackPath, false);
            // Delete all the children and then the parent node
            for (String childPath : children) {
                try {
                    zk.delete(childPath, -1);
                } catch (KeeperException.NoNodeException ke) {
                } catch (Exception e) {
                    throw new IOException(e);
                }
            }
            zk.delete(stackPath, -1);
        } catch (KeeperException.NoNodeException ke) {
            return;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public boolean stackExists(String stackName) throws IOException {
        try {
            if (zk.exists(ZOOKEEPER_STACKS_ROOT_PATH + "/" + stackName, false) == null) {
                return false;
            }
        } catch (Exception e) {
            throw new IOException(e);
        }
        return true;
    }

    @Override
    public void process(WatchedEvent event) {
        if (event.getType() == Event.EventType.None) {
            // We are are being told that the state of the
            // connection has changed
            switch (event.getState()) {
            case SyncConnected:
                // In this particular example we don't need to do anything
                // here - watches are automatically re-registered with 
                // server and any watches triggered while the client was 
                // disconnected will be delivered (in order of course)
                this.zkCoonected = true;
                break;
            case Expired:
                // It's all over
                //running = false;
                //commandHandler.stop();
                break;
            }
        }

    }

    private void createDirectory(String path, byte[] initialData, boolean ignoreIfExists)
            throws KeeperException, InterruptedException {
        try {
            zk.create(path, initialData, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            if (credential != null) {
                zk.setACL(path, Ids.CREATOR_ALL_ACL, -1);
            }
            System.out.println("Created path : <" + path + ">");
        } catch (KeeperException.NodeExistsException e) {
            if (!ignoreIfExists) {
                System.out.println("Path already exists <" + path + ">");
                throw e;
            }
        } catch (KeeperException.AuthFailedException e) {
            System.out.println("Failed to authenticate for path <" + path + ">");
            throw e;
        }
    }
}