org.springframework.xd.dirt.stream.zookeeper.ZooKeeperStreamRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.xd.dirt.stream.zookeeper.ZooKeeperStreamRepository.java

Source

/*
 * Copyright 2014-2015 the original author or authors.
 *
 * 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 org.springframework.xd.dirt.stream.zookeeper;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.collections.CollectionUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
import org.springframework.xd.dirt.core.DeploymentUnitStatus;
import org.springframework.xd.dirt.core.StreamDeploymentsPath;
import org.springframework.xd.dirt.stream.Stream;
import org.springframework.xd.dirt.stream.StreamDefinition;
import org.springframework.xd.dirt.stream.StreamRepository;
import org.springframework.xd.dirt.util.PagingUtility;
import org.springframework.xd.dirt.zookeeper.Paths;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
import org.springframework.xd.dirt.zookeeper.ZooKeeperUtils;

/**
 * Stream instance repository. It should only return values for Streams that are deployed.
 *
 * @author Mark Fisher
 * @author Gunnar Hillert
 */
// todo: the StreamRepository abstraction can be removed once we are fully zk-enabled since we do not need to
// support multiple impls at that point
public class ZooKeeperStreamRepository implements StreamRepository, InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(ZooKeeperStreamRepository.class);

    private final ZooKeeperConnection zkConnection;

    private final PagingUtility<Stream> pagingUtility = new PagingUtility<Stream>();

    private final RepositoryConnectionListener connectionListener = new RepositoryConnectionListener();

    @Autowired
    public ZooKeeperStreamRepository(ZooKeeperConnection zkConnection) {
        this.zkConnection = zkConnection;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        zkConnection.addListener(connectionListener);
        if (zkConnection.isConnected()) {
            // already connected, invoke the callback directly
            connectionListener.onConnect(zkConnection.getClient());
        }
    }

    @Override
    public Iterable<Stream> findAll(Sort sort) {
        // todo: implement sort support
        return findAll();
    }

    @Override
    public Page<Stream> findAll(Pageable pageable) {
        return pagingUtility.getPagedData(pageable, findAll());
    }

    @Override
    public <S extends Stream> S save(S entity) {
        // stream instances are "saved" when a StreamDeploymentListener deploys a stream
        return entity;
    }

    @Override
    public <S extends Stream> Iterable<S> save(Iterable<S> entities) {
        // stream instances are "saved" when a StreamDeploymentListener deploys a stream
        return entities;
    }

    @Override
    public Stream findOne(String id) {
        CuratorFramework client = zkConnection.getClient();
        String path = Paths.build(Paths.STREAMS, id);
        try {
            Stat definitionStat = client.checkExists().forPath(path);
            if (definitionStat != null) {
                byte[] data = client.getData().forPath(path);
                Map<String, String> map = ZooKeeperUtils.bytesToMap(data);
                Stream stream = new Stream(new StreamDefinition(id, map.get("definition")));

                Stat deployStat = client.checkExists().forPath(Paths.build(Paths.STREAM_DEPLOYMENTS, id));
                if (deployStat != null) {
                    stream.setStartedAt(new Date(deployStat.getCtime()));
                    stream.setStatus(getDeploymentStatus(id));
                    return stream;
                }
            }
        } catch (Exception e) {
            throw ZooKeeperUtils.wrapThrowable(e);
        }
        return null;
    }

    @Override
    public boolean exists(String id) {
        return null != findOne(id);
    }

    @Override
    public List<Stream> findAll() {
        try {
            return findAll(zkConnection.getClient().getChildren().forPath(Paths.STREAM_DEPLOYMENTS));
        } catch (Exception e) {
            throw ZooKeeperUtils.wrapThrowable(e);
        }
    }

    @Override
    public List<Stream> findAll(Iterable<String> ids) {
        List<Stream> results = new ArrayList<Stream>();
        try {
            for (String stream : ids) {
                Stream s = findOne(stream);
                if (s != null) {
                    results.add(s);
                }
            }
        } catch (Exception e) {
            throw ZooKeeperUtils.wrapThrowable(e);
        }
        return results;
    }

    @Override
    public long count() {
        try {
            Stat stat = zkConnection.getClient().checkExists().forPath(Paths.STREAM_DEPLOYMENTS);
            return stat != null ? stat.getNumChildren() : 0;
        } catch (Exception e) {
            throw ZooKeeperUtils.wrapThrowable(e);
        }
    }

    @Override
    public void delete(String id) {
        logger.info("Undeploying stream {}", id);

        String streamDeploymentPath = Paths.build(Paths.STREAM_DEPLOYMENTS, id);
        String streamModuleDeploymentPath = Paths.build(streamDeploymentPath, Paths.MODULES);
        CuratorFramework client = zkConnection.getClient();
        Deque<String> paths = new ArrayDeque<String>();

        try {
            client.setData().forPath(Paths.build(Paths.STREAM_DEPLOYMENTS, id, Paths.STATUS), ZooKeeperUtils
                    .mapToBytes(new DeploymentUnitStatus(DeploymentUnitStatus.State.undeploying).toMap()));
        } catch (Exception e) {
            logger.warn("Exception while transitioning stream {} state to {}", id,
                    DeploymentUnitStatus.State.undeploying, e);
        }

        // Place all module deployments into a tree keyed by the
        // ZK transaction id. The ZK transaction id maintains
        // total ordering of all changes. This allows the
        // undeployment of modules in the reverse order in
        // which they were deployed.
        Map<Long, String> txMap = new TreeMap<Long, String>();
        try {
            List<String> deployments = client.getChildren().forPath(streamModuleDeploymentPath);
            for (String deployment : deployments) {
                String path = new StreamDeploymentsPath(Paths.build(streamModuleDeploymentPath, deployment))
                        .build();
                Stat stat = client.checkExists().forPath(path);
                Assert.notNull(stat);
                txMap.put(stat.getCzxid(), path);
            }
        } catch (Exception e) {
            //NoNodeException - nothing to delete
            ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NoNodeException.class);
        }

        for (String deployment : txMap.values()) {
            paths.add(deployment);
        }

        for (Iterator<String> iterator = paths.descendingIterator(); iterator.hasNext();) {
            try {
                String path = iterator.next();
                logger.trace("removing path {}", path);
                client.delete().deletingChildrenIfNeeded().forPath(path);
            } catch (Exception e) {
                ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NoNodeException.class);
            }
        }

        try {
            client.delete().deletingChildrenIfNeeded().forPath(streamDeploymentPath);
        } catch (KeeperException.NotEmptyException e) {
            List<String> children = new ArrayList<String>();
            try {
                children.addAll(client.getChildren().forPath(streamModuleDeploymentPath));
            } catch (Exception ex) {
                children.add("Could not load list of children due to " + ex);
            }
            throw new IllegalStateException(String.format("The following children were not deleted from %s: %s",
                    streamModuleDeploymentPath, children), e);
        } catch (Exception e) {
            ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NoNodeException.class);
        }
    }

    @Override
    public void delete(Stream entity) {
        Assert.notNull(entity, "stream must not be null");
        delete(entity.getDefinition().getName());
    }

    @Override
    public void delete(Iterable<? extends Stream> entities) {
        for (Stream stream : entities) {
            delete(stream);
        }
    }

    @Override
    public void deleteAll() {
        try {
            List<String> children = zkConnection.getClient().getChildren().forPath(Paths.STREAM_DEPLOYMENTS);
            for (String child : children) {
                delete(child);
            }
        } catch (Exception e) {
            //NoNodeException - nothing to delete
            ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NoNodeException.class);
        }
    }

    @Override
    public Iterable<Stream> findAllInRange(String from, boolean fromInclusive, String to, boolean toInclusive) {
        List<Stream> all = findAll();
        if (CollectionUtils.isEmpty(all)) {
            return Collections.emptyList();
        }
        Collections.sort(all);

        List<Stream> results = new ArrayList<Stream>();
        for (Stream stream : all) {
            if (stream.getDefinition().getName().compareTo(to) > 0) {
                break;
            }
            if (stream.getDefinition().getName().compareTo(from) < 0) {
                continue;
            }
            results.add(stream);
        }
        return results;
    }

    @Override
    public DeploymentUnitStatus getDeploymentStatus(String id) {
        String path = Paths.build(Paths.STREAM_DEPLOYMENTS, id, Paths.STATUS);
        byte[] statusBytes = null;

        try {
            statusBytes = zkConnection.getClient().getData().forPath(path);
        } catch (Exception e) {
            // missing node means this stream has not been deployed
            ZooKeeperUtils.wrapAndThrowIgnoring(e, KeeperException.NoNodeException.class);
        }

        return (statusBytes == null) ? new DeploymentUnitStatus(DeploymentUnitStatus.State.undeployed)
                : new DeploymentUnitStatus(ZooKeeperUtils.bytesToMap(statusBytes));
    }

}