/* * 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; import co.cask.cdap.api.Admin; import co.cask.cdap.api.RuntimeContext; import co.cask.cdap.api.app.ApplicationSpecification; import co.cask.cdap.api.common.RuntimeArguments; import co.cask.cdap.api.data.DatasetContext; import co.cask.cdap.api.data.DatasetInstantiationException; import co.cask.cdap.api.dataset.Dataset; import co.cask.cdap.api.metrics.Metrics; import co.cask.cdap.api.metrics.MetricsContext; import co.cask.cdap.api.plugin.Plugin; import co.cask.cdap.api.plugin.PluginContext; import co.cask.cdap.api.plugin.PluginProperties; import co.cask.cdap.app.program.Program; import co.cask.cdap.app.runtime.Arguments; import co.cask.cdap.app.services.AbstractServiceDiscoverer; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.data.dataset.SystemDatasetInstantiator; import co.cask.cdap.data2.dataset2.DatasetFramework; import co.cask.cdap.data2.dataset2.DynamicDatasetCache; import co.cask.cdap.data2.dataset2.MultiThreadDatasetCache; import co.cask.cdap.data2.dataset2.SingleThreadDatasetCache; import co.cask.cdap.data2.metadata.lineage.AccessType; import co.cask.cdap.internal.app.program.ProgramTypeMetricTag; import co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator; import co.cask.cdap.proto.Id; import co.cask.tephra.TransactionSystemClient; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import org.apache.twill.api.RunId; import org.apache.twill.discovery.DiscoveryServiceClient; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; /** * Base class for program runtime context */ public abstract class AbstractContext extends AbstractServiceDiscoverer implements DatasetContext, RuntimeContext, PluginContext { private final Program program; private final RunId runId; private final List<Id> owners; private final Map<String, String> runtimeArguments; private final MetricsContext programMetrics; private final DiscoveryServiceClient discoveryServiceClient; private final PluginInstantiator pluginInstantiator; private final PluginContext pluginContext; private final Admin admin; private final long logicalStartTime; protected final DynamicDatasetCache datasetCache; /** * Constructs a context without plugin support. */ protected AbstractContext(Program program, RunId runId, Arguments arguments, Set<String> datasets, MetricsContext metricsContext, DatasetFramework dsFramework, TransactionSystemClient txClient, DiscoveryServiceClient discoveryServiceClient, boolean multiThreaded) { this(program, runId, arguments, datasets, metricsContext, dsFramework, txClient, discoveryServiceClient, multiThreaded, null); } /** * Constructs a context. To have plugin support, the {@code pluginInstantiator} must not be null. */ protected AbstractContext(Program program, RunId runId, Arguments arguments, Set<String> datasets, MetricsContext metricsContext, DatasetFramework dsFramework, TransactionSystemClient txClient, DiscoveryServiceClient discoveryServiceClient, boolean multiThreaded, @Nullable PluginInstantiator pluginInstantiator) { super(program.getId().toEntityId()); this.program = program; this.runId = runId; this.discoveryServiceClient = discoveryServiceClient; this.owners = createOwners(program.getId()); this.programMetrics = metricsContext; Map<String, String> runtimeArgs = new HashMap<>(arguments.asMap()); this.logicalStartTime = ProgramRunners.updateLogicalStartTime(runtimeArgs); this.runtimeArguments = Collections.unmodifiableMap(runtimeArgs); Map<String, Map<String, String>> staticDatasets = new HashMap<>(); for (String name : datasets) { staticDatasets.put(name, runtimeArguments); } SystemDatasetInstantiator instantiator = new SystemDatasetInstantiator(dsFramework, program.getClassLoader(), owners); this.datasetCache = multiThreaded ? new MultiThreadDatasetCache(instantiator, txClient, program.getId().getNamespace().toEntityId(), runtimeArguments, programMetrics, staticDatasets) : new SingleThreadDatasetCache(instantiator, txClient, program.getId().getNamespace().toEntityId(), runtimeArguments, programMetrics, staticDatasets); this.pluginInstantiator = pluginInstantiator; this.pluginContext = new DefaultPluginContext(pluginInstantiator, program.getId(), program.getApplicationSpecification().getPlugins()); this.admin = new DefaultAdmin(dsFramework, program.getId().getNamespace().toEntityId()); } private List<Id> createOwners(Id.Program programId) { ImmutableList.Builder<Id> result = ImmutableList.builder(); result.add(programId); return result.build(); } public List<Id> getOwners() { return owners; } public abstract Metrics getMetrics(); @Override public ApplicationSpecification getApplicationSpecification() { return program.getApplicationSpecification(); } @Override public String getNamespace() { return program.getNamespaceId(); } /** * Returns the {@link PluginInstantiator} used by this context or {@code null} if there is no plugin support. */ @Nullable public PluginInstantiator getPluginInstantiator() { return pluginInstantiator; } @Override public String toString() { return String.format("namespaceId=%s, applicationId=%s, program=%s, runid=%s", getNamespaceId(), getApplicationId(), getProgramName(), runId); } public MetricsContext getProgramMetrics() { return programMetrics; } public DynamicDatasetCache getDatasetCache() { return datasetCache; } @Override public <T extends Dataset> T getDataset(String name) throws DatasetInstantiationException { return getDataset(name, RuntimeArguments.NO_ARGUMENTS); } @Override public <T extends Dataset> T getDataset(String name, Map<String, String> arguments) throws DatasetInstantiationException { return getDataset(name, arguments, AccessType.UNKNOWN); } protected <T extends Dataset> T getDataset(String name, Map<String, String> arguments, AccessType accessType) throws DatasetInstantiationException { return datasetCache.getDataset(name, arguments, accessType); } @Override public void releaseDataset(Dataset dataset) { datasetCache.releaseDataset(dataset); } @Override public void discardDataset(Dataset dataset) { datasetCache.discardDataset(dataset); } public String getNamespaceId() { return program.getNamespaceId(); } public String getApplicationId() { return program.getApplicationId(); } public String getProgramName() { return program.getName(); } public Program getProgram() { return program; } @Override public RunId getRunId() { return runId; } @Override public Map<String, String> getRuntimeArguments() { return runtimeArguments; } public long getLogicalStartTime() { return logicalStartTime; } /** * Release all resources held by this context, for example, datasets. Subclasses should override this * method to release additional resources. */ public void close() { datasetCache.close(); } @Override public DiscoveryServiceClient getDiscoveryServiceClient() { return discoveryServiceClient; } public static Map<String, String> getMetricsContext(Program program, String runId) { Map<String, String> tags = Maps.newHashMap(); tags.put(Constants.Metrics.Tag.NAMESPACE, program.getNamespaceId()); tags.put(Constants.Metrics.Tag.APP, program.getApplicationId()); tags.put(ProgramTypeMetricTag.getTagName(program.getType()), program.getName()); tags.put(Constants.Metrics.Tag.RUN_ID, runId); return tags; } public abstract Map<String, Plugin> getPlugins(); @Override public PluginProperties getPluginProperties(String pluginId) { return pluginContext.getPluginProperties(pluginId); } @Override public <T> Class<T> loadPluginClass(String pluginId) { return pluginContext.loadPluginClass(pluginId); } @Override public <T> T newPluginInstance(String pluginId) throws InstantiationException { return pluginContext.newPluginInstance(pluginId); } @Override public Admin getAdmin() { return admin; } }