package org.ow2.choreos.ee;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import org.ow2.choreos.chors.EnactmentException;
import org.ow2.choreos.ee.services.update.ServiceUpdater;
import org.ow2.choreos.services.ServiceNotFoundException;
import org.ow2.choreos.services.ServiceNotModifiedException;
import org.ow2.choreos.services.UnhandledModificationException;
import org.ow2.choreos.services.datamodel.DeployableService;
import org.ow2.choreos.services.datamodel.DeployableServiceSpec;
import org.ow2.choreos.utils.Concurrency;
public class UpdateDeploymentPreparing {
private String chorId;
private Map<DeployableService, DeployableServiceSpec> toUpdate;
private List<DeployableService> configuredServices;
private Logger logger = Logger.getLogger(UpdateDeploymentPreparing.class);
public UpdateDeploymentPreparing(String chorId, Map<DeployableService, DeployableServiceSpec> toUpdate) {
this.chorId = chorId;
this.toUpdate = toUpdate;
}
public List<DeployableService> prepare() throws EnactmentException {
if (toUpdate.size() == 0)
return new ArrayList<DeployableService>();
logger.info("Request to configure nodes; creating services; setting up Chef");
updateExistingServices();
checkStatus();
return configuredServices;
}
private void checkStatus() throws EnactmentException {
if (configuredServices == null || configuredServices.isEmpty()) {
logger.error("No services configured in chor " + chorId + "!");
throw new EnactmentException();
}
}
private void updateExistingServices() {
final int TIMEOUT = 10;
final int N = toUpdate.size();
ExecutorService executor = Executors.newFixedThreadPool(N);
List<Future<DeployableService>> futures = new ArrayList<Future<DeployableService>>();
for (Entry<DeployableService, DeployableServiceSpec> entry : toUpdate.entrySet()) {
DeployableService service = entry.getKey();
DeployableServiceSpec spec = entry.getValue();
logger.debug("Requesting update of " + spec);
ServiceUpdateInvoker invoker = new ServiceUpdateInvoker(service, spec);
Future<DeployableService> future = executor.submit(invoker);
futures.add(future);
}
Concurrency.waitExecutor(executor, TIMEOUT, "Could not properly update all the services of chor" + chorId);
configuredServices = new ArrayList<DeployableService>();
for (Future<DeployableService> future : futures) {
try {
DeployableService service = Concurrency.checkAndGetFromFuture(future);
if (service != null) {
configuredServices.add(service);
}
} catch (Exception e) {
logger.error("Could not get service from future: " + e.getMessage());
}
}
}
private class ServiceUpdateInvoker implements Callable<DeployableService> {
private DeployableServiceSpec serviceSpec;
private DeployableService service;
public ServiceUpdateInvoker(DeployableService service, DeployableServiceSpec serviceSpec) {
this.serviceSpec = serviceSpec;
this.service = service;
}
@Override
public DeployableService call() throws UnhandledModificationException, ServiceNotFoundException,
ServiceNotModifiedException {
ServiceUpdater servicesManager = new ServiceUpdater(service, serviceSpec);
try {
servicesManager.updateService();
logger.debug("Service updated: " + service);
return service;
} catch (UnhandledModificationException e) {
logger.error(e.getMessage());
throw e;
}
}
}
}