/* * Copyright 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.server.admin.deployment.zk; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.queue.DistributedQueue; import org.apache.curator.framework.recipes.queue.QueueBuilder; import org.apache.curator.framework.recipes.queue.QueueConsumer; import org.apache.curator.framework.recipes.queue.QueueSerializer; import org.apache.curator.utils.ThreadUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.xd.dirt.server.admin.deployment.DeploymentMessage; import org.springframework.xd.dirt.zookeeper.Paths; import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; /** * This class controls the lifecycle operations of the ZK distributed queue that * holds the {@link org.springframework.xd.dirt.server.admin.deployment.DeploymentMessage}s. * * @author Ilayaperumal Gopinathan */ @SuppressWarnings({"unchecked", "rawtypes"}) public class DeploymentQueue implements InitializingBean, DisposableBean { /** * Logger. */ private static final Logger logger = LoggerFactory.getLogger(DeploymentQueue.class); /** * ZK distributed queue for holding the deployment messages */ private DistributedQueue<DeploymentMessage> distributedQueue; /** * Consumer that consumes the deployment messages out of ZK distributed queue */ private final QueueConsumer<DeploymentMessage> queueConsumer; /** * Curator framework client */ private final CuratorFramework client; /** * ZK path for ZK distributed queue */ private final String deploymentQueuePath; /** * Object writer for serialization of deployment message */ private final ObjectWriter objectWriter = new ObjectMapper().writerWithType(DeploymentMessage.class); /** * Object reader for de-serialization of deployment message */ private final ObjectReader objectReader = new ObjectMapper().reader(DeploymentMessage.class); /** * Executor service to be used by the ZK distributed queue */ private final ExecutorService executorService; /** * Construct deployment queue * @param zkConnection the ZooKeeper connection */ public DeploymentQueue(ZooKeeperConnection zkConnection) { this(zkConnection.getClient(), null, Paths.DEPLOYMENT_QUEUE, Executors.newSingleThreadScheduledExecutor(ThreadUtils.newThreadFactory("DeploymentQueue"))); } /** * Construct deployment queue * * @param client the Curator framework client * @param queueConsumer the consumer that consumes the deployment messages * @param deploymentQueuePath the ZK path for the deployment queue */ public DeploymentQueue(CuratorFramework client, QueueConsumer queueConsumer, String deploymentQueuePath, ExecutorService executorService) { this.client = client; this.queueConsumer = queueConsumer; this.deploymentQueuePath = deploymentQueuePath; this.executorService = executorService; } /** * Build and Start the ZK distributed queue. * @throws Exception */ public void start() throws Exception { if (client != null) { QueueBuilder<DeploymentMessage> builder = QueueBuilder.builder(client, queueConsumer, new DeploymentMessageSerializer(), deploymentQueuePath); this.distributedQueue = builder.executor(executorService).buildQueue(); this.distributedQueue.start(); } } /** * Get the underlying distributed queue. * @return the distributed queue */ public DistributedQueue<DeploymentMessage> getDistributedQueue() { return distributedQueue; } /** * Return the Curator client. * * @return the Curator client */ public CuratorFramework getClient() { return client; } @Override public void destroy() throws Exception { this.distributedQueue.close(); } @Override public void afterPropertiesSet() throws Exception { this.start(); } /** * The queue serializer implementation to serialize/de-serialize {@link DeploymentMessage} */ private class DeploymentMessageSerializer implements QueueSerializer<DeploymentMessage> { /** * De-serialize the byte[] to {@link DeploymentMessage} * * @param buffer byte[] * @return the deployment message */ public DeploymentMessage deserialize(byte[] buffer) { DeploymentMessage deploymentMessage = null; try { deploymentMessage = objectReader.readValue(buffer); } catch (JsonProcessingException e) { logger.error("Json processing exception when de-serializing." + e); } catch (IOException ioe) { logger.error("IO exception exception when de-serializing." + ioe); } return deploymentMessage; } /** * Serialize the deployment message * * @param message the deployment message * @return byte array */ public byte[] serialize(DeploymentMessage message) { byte[] byteArray = null; try { byteArray = objectWriter.writeValueAsBytes(message); } catch (JsonMappingException e) { logger.error("Json processing exception when serializing." + e); } catch (IOException ioe) { logger.error("IO processing exception when de-serializing." + ioe); } return byteArray; } } }