/*
* 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.internal.app.runtime.service;
import co.cask.cdap.app.runtime.AbstractProgramRuntimeService;
import co.cask.cdap.app.runtime.ProgramController;
import co.cask.cdap.app.runtime.ProgramRunnerFactory;
import co.cask.cdap.app.runtime.ProgramRuntimeService;
import co.cask.cdap.common.conf.CConfiguration;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.internal.app.runtime.ProgramOptionConstants;
import co.cask.cdap.internal.app.runtime.artifact.ArtifactRepository;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.InMemoryProgramLiveInfo;
import co.cask.cdap.proto.NotRunningProgramLiveInfo;
import co.cask.cdap.proto.ProgramLiveInfo;
import co.cask.cdap.proto.ProgramType;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.apache.twill.api.RunId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A {@link ProgramRuntimeService} for in memory mode. It is used for unit-test as well as in Standalone.
*/
public final class InMemoryProgramRuntimeService extends AbstractProgramRuntimeService {
private static final Logger LOG = LoggerFactory.getLogger(InMemoryProgramRuntimeService.class);
private final String hostname;
@Inject
public InMemoryProgramRuntimeService(ProgramRunnerFactory programRunnerFactory, CConfiguration cConf,
ArtifactRepository artifactRepository,
@Named(Constants.AppFabric.SERVER_ADDRESS) InetAddress hostname) {
super(cConf, programRunnerFactory, artifactRepository);
this.hostname = hostname.getCanonicalHostName();
}
@Override
public ProgramLiveInfo getLiveInfo(Id.Program programId) {
return isRunning(programId) ? new InMemoryProgramLiveInfo(programId)
: new NotRunningProgramLiveInfo(programId);
}
@Override
protected Map<String, String> getExtraProgramOptions() {
return Collections.singletonMap(ProgramOptionConstants.HOST, hostname);
}
@Override
protected void shutDown() throws Exception {
stopAllPrograms();
}
private void stopAllPrograms() {
LOG.info("Stopping all running programs.");
List<ListenableFuture<ProgramController>> futures = Lists.newLinkedList();
for (ProgramType type : ProgramType.values()) {
for (Map.Entry<RunId, RuntimeInfo> entry : list(type).entrySet()) {
RuntimeInfo runtimeInfo = entry.getValue();
if (isRunning(runtimeInfo.getProgramId())) {
futures.add(runtimeInfo.getController().stop());
}
}
}
// unchecked because we cannot do much if it fails. We will still shutdown the standalone CDAP instance.
try {
Futures.successfulAsList(futures).get(60, TimeUnit.SECONDS);
LOG.info("All programs have been stopped.");
} catch (ExecutionException e) {
// note this should not happen because we wait on a successfulAsList
LOG.warn("Got exception while waiting for all programs to stop", e.getCause());
} catch (InterruptedException e) {
LOG.warn("Got interrupted exception while waiting for all programs to stop", e);
Thread.currentThread().interrupt();
} catch (TimeoutException e) {
// can't do much more than log it. We still want to exit.
LOG.warn("Timeout while waiting for all programs to stop.");
}
}
}