/*
* Copyright © 2014-2016 Cask Data, Inc.
*
* 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 co.cask.cdap.test.internal;
import co.cask.cdap.internal.AppFabricClient;
import co.cask.cdap.proto.ApplicationDetail;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.ProgramRunStatus;
import co.cask.cdap.proto.ProgramType;
import co.cask.cdap.proto.RunRecord;
import co.cask.cdap.proto.artifact.AppRequest;
import co.cask.cdap.proto.id.ProgramId;
import co.cask.cdap.test.AbstractApplicationManager;
import co.cask.cdap.test.ApplicationManager;
import co.cask.cdap.test.DefaultMapReduceManager;
import co.cask.cdap.test.DefaultSparkManager;
import co.cask.cdap.test.FlowManager;
import co.cask.cdap.test.MapReduceManager;
import co.cask.cdap.test.MetricsManager;
import co.cask.cdap.test.ServiceManager;
import co.cask.cdap.test.SparkManager;
import co.cask.cdap.test.WorkerManager;
import co.cask.cdap.test.WorkflowManager;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.apache.twill.discovery.DiscoveryServiceClient;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A default implementation of {@link ApplicationManager}.
*/
public class DefaultApplicationManager extends AbstractApplicationManager {
private final Set<Id.Program> runningProcesses = Sets.newSetFromMap(Maps.<Id.Program, Boolean>newConcurrentMap());
private final AppFabricClient appFabricClient;
private final DiscoveryServiceClient discoveryServiceClient;
private final MetricsManager metricsManager;
@Inject
public DefaultApplicationManager(DiscoveryServiceClient discoveryServiceClient,
AppFabricClient appFabricClient,
MetricsManager metricsManager,
@Assisted("applicationId") Id.Application application) {
super(application);
this.discoveryServiceClient = discoveryServiceClient;
this.appFabricClient = appFabricClient;
this.metricsManager = metricsManager;
}
@Override
public FlowManager getFlowManager(String flowName) {
Id.Program programId = Id.Program.from(application, ProgramType.FLOW, flowName);
return new DefaultFlowManager(programId, appFabricClient, this, metricsManager);
}
@Override
public MapReduceManager getMapReduceManager(String programName) {
Id.Program programId = Id.Program.from(application, ProgramType.MAPREDUCE, programName);
return new DefaultMapReduceManager(programId, this);
}
@Override
public SparkManager getSparkManager(String jobName) {
Id.Program programId = Id.Program.from(application, ProgramType.SPARK, jobName);
return new DefaultSparkManager(programId, this);
}
@Override
public WorkflowManager getWorkflowManager(String workflowName) {
Id.Program programId = Id.Program.from(application, ProgramType.WORKFLOW, workflowName);
return new DefaultWorkflowManager(programId, appFabricClient, this);
}
@Override
public ServiceManager getServiceManager(String serviceName) {
Id.Program programId = Id.Program.from(application, ProgramType.SERVICE, serviceName);
return new DefaultServiceManager(programId, appFabricClient, discoveryServiceClient, this, metricsManager);
}
@Override
public WorkerManager getWorkerManager(String workerName) {
Id.Program programId = Id.Program.from(application, ProgramType.WORKER, workerName);
return new DefaultWorkerManager(programId, appFabricClient, this);
}
@Override
public void stopAll() {
try {
for (Id.Program programId : Iterables.consumingIterable(runningProcesses)) {
// have to do a check, since mapreduce jobs could stop by themselves earlier, and appFabricServer.stop will
// throw error when you stop something that is not running.
if (isRunning(programId)) {
appFabricClient.stopProgram(application.getNamespaceId(), programId.getApplicationId(),
programId.getId(), programId.getType());
}
}
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public void stopProgram(Id.Program programId) {
String programName = programId.getId();
try {
if (runningProcesses.remove(programId)) {
appFabricClient.stopProgram(application.getNamespaceId(), application.getId(),
programName, programId.getType());
}
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public void startProgram(Id.Program programId, Map<String, String> arguments) {
// program can stop by itself, so refreshing info about its state
if (!isRunning(programId)) {
runningProcesses.remove(programId);
}
Preconditions.checkState(runningProcesses.add(programId), "Program %s is already running", programId);
try {
appFabricClient.startProgram(application.getNamespaceId(), application.getId(),
programId.getId(), programId.getType(), arguments);
} catch (Exception e) {
runningProcesses.remove(programId);
throw Throwables.propagate(e);
}
}
@Override
public boolean isRunning(Id.Program programId) {
try {
String status = appFabricClient.getStatus(application.getNamespaceId(), programId.getApplicationId(),
programId.getId(), programId.getType());
// comparing to hardcoded string is ugly, but this is how appFabricServer works now to support legacy UI
return "STARTING".equals(status) || "RUNNING".equals(status);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public List<RunRecord> getHistory(Id.Program programId, ProgramRunStatus status) {
try {
return appFabricClient.getHistory(programId, status);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public void update(AppRequest appRequest) throws Exception {
appFabricClient.updateApplication(application.toEntityId(), appRequest);
}
@Override
public void delete() throws Exception {
appFabricClient.deleteApplication(application.toEntityId());
}
@Override
public ApplicationDetail getInfo() throws Exception {
return appFabricClient.getInfo(application.toEntityId());
}
@Override
public void setRuntimeArgs(ProgramId programId, Map<String, String> args) throws Exception {
appFabricClient.setRuntimeArgs(programId, args);
}
}