use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.
the class DefaultArtifactManager method createAndGetClassLoader.
private CloseableClassLoader createAndGetClassLoader(HttpRequest httpRequest, ArtifactInfo artifactInfo, @Nullable ClassLoader parentClassLoader) throws IOException {
HttpResponse httpResponse = remoteClient.execute(httpRequest);
if (httpResponse.getResponseCode() == HttpResponseStatus.NOT_FOUND.getCode()) {
throw new IOException("Could not get artifact detail, endpoint not found");
}
if (httpResponse.getResponseCode() == 200) {
String path = httpResponse.getResponseBodyAsString();
Location location = Locations.getLocationFromAbsolutePath(locationFactory, path);
if (!location.exists()) {
throw new IOException(String.format("Artifact Location does not exist %s for artifact %s version %s", path, artifactInfo.getName(), artifactInfo.getVersion()));
}
File unpackedDir = DirUtils.createTempDir(tmpDir);
BundleJarUtil.unJar(location, unpackedDir);
DirectoryClassLoader directoryClassLoader = new DirectoryClassLoader(unpackedDir, parentClassLoader == null ? bootstrapClassLoader : parentClassLoader);
return new CloseableClassLoader(directoryClassLoader, new ClassLoaderCleanup(directoryClassLoader, unpackedDir));
} else {
throw new IOException(String.format("Exception while getting artifacts list %s", httpResponse.getResponseBodyAsString()));
}
}
use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.
the class ArtifactInspector method inspectArtifact.
/**
* Inspect the given artifact to determine the classes contained in the artifact.
*
* @param artifactId the id of the artifact to inspect
* @param artifactFile the artifact file
* @param parentClassLoader the parent classloader to use when inspecting plugins contained in the artifact.
* For example, a ProgramClassLoader created from the artifact the input artifact extends
* @return metadata about the classes contained in the artifact
* @throws IOException if there was an exception opening the jar file
* @throws InvalidArtifactException if the artifact is invalid. For example, if the application main class is not
* actually an Application.
*/
ArtifactClasses inspectArtifact(Id.Artifact artifactId, File artifactFile, @Nullable ClassLoader parentClassLoader) throws IOException, InvalidArtifactException {
Path tmpDir = Paths.get(cConf.get(Constants.CFG_LOCAL_DATA_DIR), cConf.get(Constants.AppFabric.TEMP_DIR)).toAbsolutePath();
Files.createDirectories(tmpDir);
Location artifactLocation = Locations.toLocation(artifactFile);
Path stageDir = Files.createTempDirectory(tmpDir, artifactFile.getName());
try {
File unpackedDir = BundleJarUtil.unJar(artifactLocation, Files.createTempDirectory(stageDir, "unpacked-").toFile());
try (CloseableClassLoader artifactClassLoader = artifactClassLoaderFactory.createClassLoader(unpackedDir);
PluginInstantiator pluginInstantiator = new PluginInstantiator(cConf, parentClassLoader == null ? artifactClassLoader : parentClassLoader, Files.createTempDirectory(stageDir, "plugins-").toFile(), false)) {
pluginInstantiator.addArtifact(artifactLocation, artifactId.toArtifactId());
ArtifactClasses.Builder builder = inspectApplications(artifactId, ArtifactClasses.builder(), artifactLocation, artifactClassLoader);
return inspectPlugins(builder, artifactFile, artifactId.toArtifactId(), pluginInstantiator).build();
}
} catch (EOFException | ZipException e) {
throw new InvalidArtifactException("Artifact " + artifactId + " is not a valid zip file.", e);
} finally {
try {
DirUtils.deleteDirectoryContents(stageDir.toFile());
} catch (IOException e) {
LOG.warn("Exception raised while deleting directory {}", stageDir, e);
}
}
}
use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.
the class DefaultArtifactRepository method addArtifact.
@Override
public ArtifactDetail addArtifact(final Id.Artifact artifactId, final File artifactFile, @Nullable Set<ArtifactRange> parentArtifacts, @Nullable Set<PluginClass> additionalPlugins, Map<String, String> properties) throws Exception {
if (additionalPlugins != null) {
validatePluginSet(additionalPlugins);
}
parentArtifacts = parentArtifacts == null ? Collections.emptySet() : parentArtifacts;
CloseableClassLoader parentClassLoader = null;
EntityImpersonator entityImpersonator = new EntityImpersonator(artifactId.toEntityId(), impersonator);
if (!parentArtifacts.isEmpty()) {
validateParentSet(artifactId, parentArtifacts);
parentClassLoader = createParentClassLoader(artifactId, parentArtifacts, entityImpersonator);
}
try {
ArtifactClasses artifactClasses = inspectArtifact(artifactId, artifactFile, additionalPlugins, parentClassLoader);
ArtifactMeta meta = new ArtifactMeta(artifactClasses, parentArtifacts, properties);
ArtifactDetail artifactDetail = artifactStore.write(artifactId, meta, Files.newInputStreamSupplier(artifactFile), entityImpersonator);
ArtifactDescriptor descriptor = artifactDetail.getDescriptor();
// info hides some fields that are available in detail, such as the location of the artifact
ArtifactInfo artifactInfo = new ArtifactInfo(descriptor.getArtifactId(), artifactDetail.getMeta().getClasses(), artifactDetail.getMeta().getProperties());
// add system metadata for artifacts
writeSystemMetadata(artifactId.toEntityId(), artifactInfo);
return artifactDetail;
} finally {
Closeables.closeQuietly(parentClassLoader);
}
}
use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.
the class AbstractArtifactManager method createClassLoader.
/**
* Create a class loader with artifact jar unpacked contents and parent for this classloader is the supplied
* parentClassLoader, if that parent classloader is null, bootstrap classloader is used as parent.
* This is a closeable classloader, caller should call close when he is done using it, during close directory
* cleanup will be performed.
*
* @param artifactInfo artifact info whose artifact will be unpacked to create classloader
* @param parentClassLoader optional parent classloader, if null bootstrap classloader will be used
* @return CloseableClassLoader call close on this CloseableClassLoader for cleanup
* @throws IOException if artifact is not found or there were any error while getting artifact
*/
@Override
public CloseableClassLoader createClassLoader(ArtifactInfo artifactInfo, @Nullable ClassLoader parentClassLoader) throws IOException {
File unpackedDir = DirUtils.createTempDir(tmpDir);
BundleJarUtil.unJar(getArtifactLocation(artifactInfo), unpackedDir);
DirectoryClassLoader directoryClassLoader = new DirectoryClassLoader(unpackedDir, parentClassLoader == null ? bootstrapClassLoader : parentClassLoader, "lib");
return new CloseableClassLoader(directoryClassLoader, new ClassLoaderCleanup(directoryClassLoader, unpackedDir));
}
use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.
the class ConfiguratorTest method testAppWithConfig.
@Test
public void testAppWithConfig() throws Exception {
LocationFactory locationFactory = new LocalLocationFactory(TMP_FOLDER.newFolder());
Location appJar = AppJarHelper.createDeploymentJar(locationFactory, ConfigTestApp.class);
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.DEFAULT, ConfigTestApp.class.getSimpleName(), "1.0.0");
CConfiguration cConf = CConfiguration.create();
ArtifactRepository baseArtifactRepo = new DefaultArtifactRepository(conf, null, null, new DummyProgramRunnerFactory(), new DefaultImpersonator(cConf, null));
ArtifactRepository artifactRepo = new AuthorizationArtifactRepository(baseArtifactRepo, authEnforcer, authenticationContext);
ConfigTestApp.ConfigClass config = new ConfigTestApp.ConfigClass("myStream", "myTable");
// Create a configurator that is testable. Provide it an application.
try (CloseableClassLoader artifactClassLoader = artifactRepo.createArtifactClassLoader(appJar, new EntityImpersonator(artifactId.getNamespace().toEntityId(), new DefaultImpersonator(cConf, null)))) {
Configurator configuratorWithConfig = new InMemoryConfigurator(conf, Id.Namespace.DEFAULT, artifactId, ConfigTestApp.class.getName(), artifactRepo, artifactClassLoader, null, null, new Gson().toJson(config));
ListenableFuture<ConfigResponse> result = configuratorWithConfig.config();
ConfigResponse response = result.get(10, TimeUnit.SECONDS);
Assert.assertNotNull(response);
ApplicationSpecificationAdapter adapter = ApplicationSpecificationAdapter.create(new ReflectionSchemaGenerator());
ApplicationSpecification specification = adapter.fromJson(response.get());
Assert.assertNotNull(specification);
Assert.assertTrue(specification.getStreams().size() == 1);
Assert.assertTrue(specification.getStreams().containsKey("myStream"));
Assert.assertTrue(specification.getDatasets().size() == 1);
Assert.assertTrue(specification.getDatasets().containsKey("myTable"));
Configurator configuratorWithoutConfig = new InMemoryConfigurator(conf, Id.Namespace.DEFAULT, artifactId, ConfigTestApp.class.getName(), artifactRepo, artifactClassLoader, null, null, null);
result = configuratorWithoutConfig.config();
response = result.get(10, TimeUnit.SECONDS);
Assert.assertNotNull(response);
specification = adapter.fromJson(response.get());
Assert.assertNotNull(specification);
Assert.assertTrue(specification.getStreams().size() == 1);
Assert.assertTrue(specification.getStreams().containsKey(ConfigTestApp.DEFAULT_STREAM));
Assert.assertTrue(specification.getDatasets().size() == 1);
Assert.assertTrue(specification.getDatasets().containsKey(ConfigTestApp.DEFAULT_TABLE));
Assert.assertNotNull(specification.getProgramSchedules().get(ConfigTestApp.SCHEDULE_NAME));
ProgramStatusTrigger trigger = (ProgramStatusTrigger) specification.getProgramSchedules().get(ConfigTestApp.SCHEDULE_NAME).getTrigger();
Assert.assertEquals(trigger.getProgramId().getProgram(), ConfigTestApp.WORKFLOW_NAME);
}
}
Aggregations