Search in sources :

Example 1 with CloseableClassLoader

use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactRepository method addArtifact.

/**
   * Inspects and builds plugin and application information for the given artifact, adding an additional set of
   * plugin classes to the plugins found through inspection. This method is used when all plugin classes
   * cannot be derived by inspecting the artifact but need to be explicitly set. This is true for 3rd party plugins
   * like jdbc drivers.
   *
   * @param artifactId the id of the artifact to inspect and store
   * @param artifactFile the artifact to inspect and store
   * @param parentArtifacts artifacts the given artifact extends.
   *                        If null, the given artifact does not extend another artifact
   * @param additionalPlugins the set of additional plugin classes to add to the plugins found through inspection.
   *                          If null, no additional plugin classes will be added
   * @param properties properties for the artifact
   * @throws IOException if there was an exception reading from the artifact store
   * @throws ArtifactRangeNotFoundException if none of the parent artifacts could be found
   * @throws UnauthorizedException if the user is not authorized to add an artifact in the specified namespace. To add
   *                               an artifact, a user must have {@link Action#WRITE} on the namespace in which
   *                               the artifact is being added. If authorization is successful, and
   *                               the artifact is added successfully, then the user gets all {@link Action privileges}
   *                               on the added artifact.
   */
@VisibleForTesting
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.<ArtifactRange>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);
    }
}
Also used : ArtifactInfo(co.cask.cdap.api.artifact.ArtifactInfo) ArtifactClasses(co.cask.cdap.api.artifact.ArtifactClasses) EntityImpersonator(co.cask.cdap.security.impersonation.EntityImpersonator) ArtifactRange(co.cask.cdap.api.artifact.ArtifactRange) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 2 with CloseableClassLoader

use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactClassLoaderFactory method createClassLoader.

/**
 * Creates a multi level classloader where each location in the specified iterator corresponds to a classloader whose
 * parent is built from the location behind it.
 *
 * @param artifactLocations the locations of the artifact to create the classloader from
 * @return a closeable classloader based off the specified artifacts; on closing the returned {@link ClassLoader},
 *         all temporary resources created for the classloader will be removed
 * @throws IOException if there was an error copying or unpacking the artifact
 * @see #createClassLoader(File)
 */
CloseableClassLoader createClassLoader(final Iterator<Location> artifactLocations, EntityImpersonator entityImpersonator) throws IOException {
    if (!artifactLocations.hasNext()) {
        throw new IllegalArgumentException("Cannot create a classloader without an artifact.");
    }
    final Location artifactLocation = artifactLocations.next();
    if (!artifactLocations.hasNext()) {
        return createClassLoader(artifactLocation, entityImpersonator);
    }
    try {
        final File unpackDir = entityImpersonator.impersonate(new Callable<File>() {

            @Override
            public File call() throws IOException {
                return BundleJarUtil.unJar(artifactLocation, DirUtils.createTempDir(tmpDir));
            }
        });
        final CloseableClassLoader parentClassLoader = createClassLoader(artifactLocations, entityImpersonator);
        return new CloseableClassLoader(new DirectoryClassLoader(unpackDir, parentClassLoader, "lib"), new Closeable() {

            @Override
            public void close() throws IOException {
                try {
                    Closeables.closeQuietly(parentClassLoader);
                    if (unpackDir.exists()) {
                        DirUtils.deleteDirectoryContents(unpackDir);
                    }
                } catch (IOException e) {
                    LOG.warn("Failed to delete directory {}", unpackDir, e);
                }
            }
        });
    } catch (Exception e) {
        throw Throwables.propagate(e);
    }
}
Also used : DirectoryClassLoader(co.cask.cdap.common.lang.DirectoryClassLoader) Closeable(java.io.Closeable) IOException(java.io.IOException) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) File(java.io.File) IOException(java.io.IOException) Location(org.apache.twill.filesystem.Location)

Example 3 with CloseableClassLoader

use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactClassLoaderFactory method createClassLoader.

/**
 * Create a classloader that loads classes from a directory where an artifact jar has been expanded, with access to
 * packages that all program type has access to. The classloader created is only for artifact inspection purpose
 * and shouldn't be used for program execution as it doesn't have the proper class filtering for the specific
 * program type for the program being executed.
 *
 * @param unpackDir the directory where the artifact jar has been expanded
 * @return a closeable classloader based off the specified artifact; on closing the returned {@link ClassLoader},
 *         all temporary resources created for the classloader will be removed
 * @throws IOException if there was an error copying or unpacking the artifact
 */
CloseableClassLoader createClassLoader(File unpackDir) throws IOException {
    ProgramRunner programRunner = null;
    try {
        // Try to create a ProgramClassLoader from the Spark runtime system if it is available.
        // It is needed because we don't know what program types that an artifact might have.
        // TODO: CDAP-5613. We shouldn't always expose the Spark classes.
        programRunner = programRunnerFactory.create(ProgramType.SPARK);
    } catch (Exception e) {
        // If Spark is not supported, exception is expected. We'll use the default filter.
        LOG.trace("Spark is not supported. Not using ProgramClassLoader from Spark", e);
    }
    ProgramClassLoader programClassLoader = null;
    if (programRunner instanceof ProgramClassLoaderProvider) {
        programClassLoader = new ProgramClassLoader(cConf, unpackDir, ((ProgramClassLoaderProvider) programRunner).createProgramClassLoaderParent());
    }
    if (programClassLoader == null) {
        programClassLoader = new ProgramClassLoader(cConf, unpackDir, FilterClassLoader.create(getClass().getClassLoader()));
    }
    final ClassLoader finalProgramClassLoader = programClassLoader;
    final ProgramRunner finalProgramRunner = programRunner;
    return new CloseableClassLoader(programClassLoader, new Closeable() {

        @Override
        public void close() {
            Closeables.closeQuietly((Closeable) finalProgramClassLoader);
            if (finalProgramRunner instanceof Closeable) {
                Closeables.closeQuietly((Closeable) finalProgramRunner);
            }
        }
    });
}
Also used : ProgramClassLoader(co.cask.cdap.internal.app.runtime.ProgramClassLoader) ProgramClassLoaderProvider(co.cask.cdap.app.runtime.ProgramClassLoaderProvider) Closeable(java.io.Closeable) DirectoryClassLoader(co.cask.cdap.common.lang.DirectoryClassLoader) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) FilterClassLoader(co.cask.cdap.common.lang.FilterClassLoader) ProgramClassLoader(co.cask.cdap.internal.app.runtime.ProgramClassLoader) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) ProgramRunner(co.cask.cdap.app.runtime.ProgramRunner) IOException(java.io.IOException)

Example 4 with CloseableClassLoader

use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactClassLoaderFactory method createClassLoader.

/**
 * Unpack the given {@code artifactLocation} to a temporary directory and call
 * {@link #createClassLoader(File)} to create the {@link ClassLoader}.
 *
 * @param artifactLocation the location of the artifact to create the classloader from
 * @return a closeable classloader based off the specified artifact; on closing the returned {@link ClassLoader},
 *         all temporary resources created for the classloader will be removed
 * @throws IOException if there was an error copying or unpacking the artifact
 * @see #createClassLoader(File)
 */
private CloseableClassLoader createClassLoader(final Location artifactLocation, EntityImpersonator entityImpersonator) throws IOException {
    try {
        final File unpackDir = entityImpersonator.impersonate(new Callable<File>() {

            @Override
            public File call() throws IOException {
                return BundleJarUtil.unJar(artifactLocation, DirUtils.createTempDir(tmpDir));
            }
        });
        final CloseableClassLoader classLoader = createClassLoader(unpackDir);
        return new CloseableClassLoader(classLoader, new Closeable() {

            @Override
            public void close() throws IOException {
                try {
                    Closeables.closeQuietly(classLoader);
                    if (unpackDir.exists()) {
                        DirUtils.deleteDirectoryContents(unpackDir);
                    }
                } catch (IOException e) {
                    LOG.warn("Failed to delete directory {}", unpackDir, e);
                }
            }
        });
    } catch (Exception e) {
        throw Throwables.propagate(e);
    }
}
Also used : Closeable(java.io.Closeable) IOException(java.io.IOException) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) File(java.io.File) IOException(java.io.IOException)

Example 5 with CloseableClassLoader

use of co.cask.cdap.api.artifact.CloseableClassLoader in project cdap by caskdata.

the class ArtifactInspectorTest method inspectAppsAndPlugins.

@Test
public void inspectAppsAndPlugins() throws Exception {
    Manifest manifest = new Manifest();
    manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, InspectionApp.class.getPackage().getName());
    File appFile = createJar(InspectionApp.class, new File(TMP_FOLDER.newFolder(), "InspectionApp-1.0.0.jar"), manifest);
    Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "InspectionApp", "1.0.0");
    Location artifactLocation = Locations.toLocation(appFile);
    try (CloseableClassLoader artifactClassLoader = classLoaderFactory.createClassLoader(ImmutableList.of(artifactLocation).iterator(), new EntityImpersonator(artifactId.toEntityId(), new DefaultImpersonator(CConfiguration.create(), null)))) {
        ArtifactClasses classes = artifactInspector.inspectArtifact(artifactId, appFile, artifactClassLoader);
        // check app classes
        Set<ApplicationClass> expectedApps = ImmutableSet.of(new ApplicationClass(InspectionApp.class.getName(), "", new ReflectionSchemaGenerator(false).generate(InspectionApp.AConfig.class)));
        Assert.assertEquals(expectedApps, classes.getApps());
        // check plugin classes
        PluginClass expectedPlugin = new PluginClass(InspectionApp.PLUGIN_TYPE, InspectionApp.PLUGIN_NAME, InspectionApp.PLUGIN_DESCRIPTION, InspectionApp.AppPlugin.class.getName(), "pluginConf", ImmutableMap.of("y", new PluginPropertyField("y", "", "double", true, true), "isSomething", new PluginPropertyField("isSomething", "", "boolean", true, false)));
        Assert.assertEquals(ImmutableSet.of(expectedPlugin), classes.getPlugins());
    }
}
Also used : EntityImpersonator(co.cask.cdap.security.impersonation.EntityImpersonator) ApplicationClass(co.cask.cdap.api.artifact.ApplicationClass) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) Manifest(java.util.jar.Manifest) ReflectionSchemaGenerator(co.cask.cdap.internal.io.ReflectionSchemaGenerator) DefaultImpersonator(co.cask.cdap.security.impersonation.DefaultImpersonator) PluginPropertyField(co.cask.cdap.api.plugin.PluginPropertyField) ArtifactClasses(co.cask.cdap.api.artifact.ArtifactClasses) Id(co.cask.cdap.common.id.Id) PluginClass(co.cask.cdap.api.plugin.PluginClass) File(java.io.File) Location(org.apache.twill.filesystem.Location) InspectionApp(co.cask.cdap.internal.app.runtime.artifact.app.inspection.InspectionApp) Test(org.junit.Test)

Aggregations

CloseableClassLoader (co.cask.cdap.api.artifact.CloseableClassLoader)12 File (java.io.File)7 Location (org.apache.twill.filesystem.Location)7 EntityImpersonator (co.cask.cdap.security.impersonation.EntityImpersonator)6 IOException (java.io.IOException)5 ArtifactClasses (co.cask.cdap.api.artifact.ArtifactClasses)4 Id (co.cask.cdap.common.id.Id)4 DirectoryClassLoader (co.cask.cdap.common.lang.DirectoryClassLoader)4 DefaultImpersonator (co.cask.cdap.security.impersonation.DefaultImpersonator)4 Test (org.junit.Test)4 ReflectionSchemaGenerator (co.cask.cdap.internal.io.ReflectionSchemaGenerator)3 Closeable (java.io.Closeable)3 ApplicationSpecification (co.cask.cdap.api.app.ApplicationSpecification)2 ArtifactInfo (co.cask.cdap.api.artifact.ArtifactInfo)2 ConfigResponse (co.cask.cdap.app.deploy.ConfigResponse)2 Configurator (co.cask.cdap.app.deploy.Configurator)2 DummyProgramRunnerFactory (co.cask.cdap.app.runtime.DummyProgramRunnerFactory)2 CConfiguration (co.cask.cdap.common.conf.CConfiguration)2 ApplicationSpecificationAdapter (co.cask.cdap.internal.app.ApplicationSpecificationAdapter)2 ArtifactRepository (co.cask.cdap.internal.app.runtime.artifact.ArtifactRepository)2