package org.ow2.choreos.ee;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
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.ServiceCreator;
import org.ow2.choreos.ee.services.ServiceCreatorFactory;
import org.ow2.choreos.invoker.Invoker;
import org.ow2.choreos.invoker.InvokerFactory;
import org.ow2.choreos.services.ServiceNotCreatedException;
import org.ow2.choreos.services.datamodel.DeployableService;
import org.ow2.choreos.services.datamodel.DeployableServiceSpec;
import org.ow2.choreos.utils.Concurrency;
import org.ow2.choreos.utils.TimeoutsAndTrials;
public class NewDeploymentPreparing {
private static final String TASK_NAME = "CREATE_SERVICE";
private String chorId;
private List<DeployableServiceSpec> specs;
private ExecutorService executor;
private Map<DeployableServiceSpec, Future<DeployableService>> futures;
private List<DeployableService> configuredServices;
private int totalTimeout;
private Logger logger = Logger.getLogger(NewDeploymentPreparing.class);
public NewDeploymentPreparing(String chorId, List<DeployableServiceSpec> specs) {
this.chorId = chorId;
this.specs = specs;
int timeout = TimeoutsAndTrials.get("CREATE_SERVICE_TIMEOUT");
int trials = TimeoutsAndTrials.get("CREATE_SERVICE_TRIALS");
int pause = TimeoutsAndTrials.get("CREATE_SERVICE_PAUSE");
this.totalTimeout = (timeout + pause) * trials;
this.totalTimeout += totalTimeout * 0.2;
}
public List<DeployableService> prepare() throws EnactmentException {
if (specs.size() == 0)
return new ArrayList<DeployableService>();
logger.info("Request to configure nodes; creating services; setting up Chef; for chor " + chorId);
submitConfigureTasks();
waitConfigureTasks();
retrieveConfiguredServices();
checkStatus();
logger.info("Nodes are configured to run chef-client on chor " + chorId);
return configuredServices;
}
private void submitConfigureTasks() {
final int N = specs.size();
executor = Executors.newFixedThreadPool(N);
futures = new HashMap<DeployableServiceSpec, Future<DeployableService>>();
for (DeployableServiceSpec choreographyServiceSpec : specs) {
CreateServiceInvoker invoker = new CreateServiceInvoker(choreographyServiceSpec);
Future<DeployableService> future = executor.submit(invoker);
futures.put(choreographyServiceSpec, future);
}
}
private void waitConfigureTasks() {
Concurrency.waitExecutor(executor, totalTimeout, "Could not properly configure all the services of chor "
+ chorId);
}
private void retrieveConfiguredServices() {
configuredServices = new ArrayList<DeployableService>();
for (Entry<DeployableServiceSpec, Future<DeployableService>> entry : futures.entrySet()) {
try {
DeployableService service = Concurrency.checkAndGetFromFuture(entry.getValue());
if (service != null) {
configuredServices.add(service);
} else {
logger.error("Future returned a null service for service " + entry.getKey().getName());
}
} catch (ExecutionException e) {
logger.error("Could not get service from future for service " + entry.getKey().getName() + " because "
+ e.getMessage());
}
}
}
private void checkStatus() throws EnactmentException {
if (configuredServices == null || configuredServices.isEmpty()) {
logger.error("No services configured in chor " + chorId + "!");
throw new EnactmentException();
}
}
private class CreateServiceInvoker implements Callable<DeployableService> {
DeployableServiceSpec spec;
public CreateServiceInvoker(DeployableServiceSpec serviceSpec) {
this.spec = serviceSpec;
}
@Override
public DeployableService call() throws Exception {
CreateServiceTask task = new CreateServiceTask(spec);
InvokerFactory<DeployableService> factory = new InvokerFactory<DeployableService>();
Invoker<DeployableService> invoker = factory.geNewInvokerInstance(TASK_NAME, task);
return invoker.invoke();
}
}
private class CreateServiceTask implements Callable<DeployableService> {
DeployableServiceSpec spec;
public CreateServiceTask(DeployableServiceSpec serviceSpec) {
this.spec = serviceSpec;
}
@Override
public DeployableService call() throws Exception {
ServiceCreator serviceCreator = ServiceCreatorFactory.getNewInstance();
try {
DeployableService deployedService = serviceCreator.createService(spec);
return deployedService;
} catch (ServiceNotCreatedException e) {
logger.error("Service " + spec.getName() + " not created!");
throw e;
}
}
}
}