/*
* Copyright 2002-2014 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;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.util.Assert;
import org.springframework.xd.dirt.core.BaseDefinition;
import org.springframework.xd.dirt.server.admin.deployment.DeploymentException;
import org.springframework.xd.dirt.server.admin.deployment.DeploymentHandler;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
import org.springframework.xd.store.DomainRepository;
/**
* Base support class for deployers that know how to deal with {@link BaseInstance instances} of a
* {@link BaseDefinition definition}.
*
* @param D the kind of definition this deployer deals with
* @param I the corresponding instance type
*
* @author Eric Bottard
* @author Ilayaperumal Gopinathan
*/
public abstract class AbstractInstancePersistingDeployer<D extends BaseDefinition, I extends BaseInstance<D>> extends
AbstractDeployer<D> {
private static final Logger logger = LoggerFactory.getLogger(AbstractInstancePersistingDeployer.class);
protected final DomainRepository<I, String> instanceRepository;
protected final DeploymentHandler deploymentHandler;
protected AbstractInstancePersistingDeployer(ZooKeeperConnection zkConnection,
PagingAndSortingRepository<D, String> definitionRespository,
DomainRepository<I, String> instanceRepository, XDParser parser,
DeploymentHandler deploymentHandler, ParsingContext definitionKind) {
super(zkConnection, definitionRespository, parser, definitionKind);
this.instanceRepository = instanceRepository;
this.deploymentHandler = deploymentHandler;
}
@Override
protected void beforeDelete(D definition) {
validateBeforeDelete(definition.getName());
if (instanceRepository.exists(definition.getName())) {
undeploy(definition.getName());
}
}
@Override
public void undeploy(String name) {
validateBeforeUndeploy(name);
logger.trace("Undeploying {}", name);
instanceRepository.delete(instanceRepository.findOne(name));
undeployResource(name);
}
@Override
public void deploy(String name, Map<String, String> properties) {
validateBeforeDeploy(name, properties);
final D definition = basicDeploy(name, properties);
final I instance = makeInstance(definition);
instanceRepository.save(instance);
deployResource(name);
}
@Override
public void undeployAll() {
for (D definition : findAll()) {
String name = definition.getName();
// Make sure we un-deploy only the resources that are already deployed.
if (instanceRepository.exists(name)) {
undeploy(name);
}
}
}
@Override
public void deleteAll() {
// Make sure to un-deploy before delete.
undeployAll();
super.deleteAll();
}
/**
* Query deployment information about definitions whose ids range from {@code first} to {@code last}.
*/
public Iterable<I> deploymentInfo(String first, String last) {
return instanceRepository.findAllInRange(first, true, last, true);
}
/**
* Query deployment information about the definition whose ID is provided.
*/
public BaseInstance<D> deploymentInfo(String id) {
return instanceRepository.findOne(id);
}
/**
* Create an running instance out of the given definition;
*/
protected abstract I makeInstance(D definition);
/**
* Deploy the deployment unit with the given name.
*
* @param deploymentUnitName the deployment unit name
*/
protected final void deployResource(String deploymentUnitName) {
try {
deploymentHandler.deploy(deploymentUnitName);
}
catch (Exception e) {
throw new DeploymentException(deploymentUnitName, e);
}
}
/**
* Un-deploy the deployment unit with the given name
*
* @param deploymentUnitName the deployment unit name
*/
protected final void undeployResource(String deploymentUnitName) {
try {
deploymentHandler.undeploy(deploymentUnitName);
}
catch (Exception e) {
throw new DeploymentException(deploymentUnitName, e);
}
}
@Override
public void validateBeforeUndeploy(String name) {
Assert.hasText(name, "name cannot be blank or null");
D definition = getDefinitionRepository().findOne(name);
if (definition == null) {
throwNoSuchDefinitionException(name);
}
final I instance = instanceRepository.findOne(name);
if (instance == null) {
throwNotDeployedException(name);
}
}
@Override
public void validateBeforeDeploy(String name, Map<String, String> properties) {
Assert.hasText(name, "name cannot be blank or null");
Assert.notNull(properties, "properties cannot be null");
D definition = getDefinitionRepository().findOne(name);
if (definition == null) {
throwNoSuchDefinitionException(name);
}
if (instanceRepository.exists(name)) {
throwAlreadyDeployedException(name);
}
}
}