Search in sources :

Example 61 with PluginClass

use of co.cask.cdap.api.plugin.PluginClass in project cdap by caskdata.

the class PluginService method getPluginEndpoint.

/**
 * load and instantiate the plugin and return {@link PluginEndpoint}
 * which can be used to invoke plugin method with request object.
 *
 * @param pluginInstantiator to instantiate plugin instances.
 * @param artifact artifact of the plugin
 * @param pluginClass class having the plugin method to invoke
 * @param endpointName name of the endpoint to invoke
 * @param endpointPluginContext endpoint plugin context that can optionally be passed to the method
 * @throws IOException if there was an exception getting the classloader
 * @throws ClassNotFoundException if plugin class cannot be loaded
 * @throws NotFoundException Not Found exception thrown if no matching plugin found.
 */
private PluginEndpoint getPluginEndpoint(final PluginInstantiator pluginInstantiator, Id.Artifact artifact, PluginClass pluginClass, String endpointName, final DefaultEndpointPluginContext endpointPluginContext) throws IOException, ClassNotFoundException, NotFoundException {
    Plugin plugin = new Plugin(new ArrayList<ArtifactId>(), artifact.toArtifactId(), pluginClass, PluginProperties.builder().build());
    ClassLoader pluginClassLoader = pluginInstantiator.getPluginClassLoader(plugin);
    Class pluginClassLoaded = pluginClassLoader.loadClass(pluginClass.getClassName());
    final Object pluginInstance = pluginInstantiator.newInstanceWithoutConfig(plugin);
    Method[] methods = pluginClassLoaded.getMethods();
    for (final Method method : methods) {
        Path pathAnnotation = method.getAnnotation(Path.class);
        // method should have path annotation else continue
        if (pathAnnotation == null || !pathAnnotation.value().equals(endpointName)) {
            continue;
        }
        return new PluginEndpoint() {

            @Override
            public java.lang.reflect.Type getMethodParameterType() throws IllegalArgumentException {
                if (method.getParameterTypes().length == 0) {
                    // should not happen, checks should have happened during deploy artifact.
                    throw new IllegalArgumentException("No Method parameter type found");
                }
                return method.getGenericParameterTypes()[0];
            }

            @Override
            public java.lang.reflect.Type getResultType() {
                return method.getGenericReturnType();
            }

            @Override
            public Object invoke(Object request) throws IOException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, IllegalArgumentException {
                if (method.getParameterTypes().length == 2 && EndpointPluginContext.class.isAssignableFrom(method.getParameterTypes()[1])) {
                    return method.invoke(pluginInstance, request, endpointPluginContext);
                } else if (method.getParameterTypes().length == 1) {
                    return method.invoke(pluginInstance, request);
                } else {
                    throw new IllegalArgumentException(String.format("Only method with 1 parameter and optional EndpointPluginContext as 2nd parameter is " + "allowed in Plugin endpoint method, Found %s parameters", method.getParameterTypes().length));
                }
            }
        };
    }
    ;
    // cannot find the endpoint in plugin method. should not happen as this is checked earlier.
    throw new NotFoundException("Could not find the plugin method with the requested method endpoint {}", endpointName);
}
Also used : Path(javax.ws.rs.Path) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) EndpointPluginContext(co.cask.cdap.api.plugin.EndpointPluginContext) DefaultEndpointPluginContext(co.cask.cdap.internal.app.runtime.DefaultEndpointPluginContext) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) NotFoundException(co.cask.cdap.common.NotFoundException) Method(java.lang.reflect.Method) CloseableClassLoader(co.cask.cdap.api.artifact.CloseableClassLoader) PluginClass(co.cask.cdap.api.plugin.PluginClass) Plugin(co.cask.cdap.api.plugin.Plugin)

Example 62 with PluginClass

use of co.cask.cdap.api.plugin.PluginClass in project cdap by caskdata.

the class ArtifactRepositoryTest method testPlugin.

@Test
public void testPlugin() throws Exception {
    File pluginDir = TMP_FOLDER.newFolder();
    addPluginArtifact();
    SortedMap<ArtifactDescriptor, Set<PluginClass>> plugins = getPlugins();
    copyArtifacts(pluginDir, plugins);
    // Instantiate the plugins and execute them
    try (PluginInstantiator instantiator = new PluginInstantiator(cConf, appClassLoader, pluginDir)) {
        for (Map.Entry<ArtifactDescriptor, Set<PluginClass>> entry : plugins.entrySet()) {
            for (PluginClass pluginClass : entry.getValue()) {
                Plugin pluginInfo = new Plugin(new ArrayList<ArtifactId>(), entry.getKey().getArtifactId(), pluginClass, PluginProperties.builder().add("class.name", TEST_EMPTY_CLASS).add("nullableLongFlag", "10").add("host", "example.com").add("aBoolean", "${aBoolean}").add("aByte", "${aByte}").add("aChar", "${aChar}").add("aDouble", "${aDouble}").add("anInt", "${anInt}").add("aFloat", "${aFloat}").add("aLong", "${aLong}").add("aShort", "${aShort}").build());
                Callable<String> plugin = instantiator.newInstance(pluginInfo);
                Assert.assertEquals("example.com,false,0,\u0000,0.0,0.0,0,0,0", plugin.call());
            }
        }
    }
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) HashSet(java.util.HashSet) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) PluginInstantiator(co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator) PluginClass(co.cask.cdap.api.plugin.PluginClass) File(java.io.File) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) Plugin(co.cask.cdap.api.plugin.Plugin) TestPlugin(co.cask.cdap.internal.app.plugins.test.TestPlugin) Test(org.junit.Test)

Example 63 with PluginClass

use of co.cask.cdap.api.plugin.PluginClass in project cdap by caskdata.

the class ArtifactRepositoryTest method testPluginConfigWithNoStringValues.

@Test
public void testPluginConfigWithNoStringValues() throws Exception {
    File pluginDir = TMP_FOLDER.newFolder();
    addPluginArtifact();
    SortedMap<ArtifactDescriptor, Set<PluginClass>> plugins = getPlugins();
    copyArtifacts(pluginDir, plugins);
    String numericValue = "42";
    // Instantiate the plugins and execute them
    try (PluginInstantiator instantiator = new PluginInstantiator(cConf, appClassLoader, pluginDir)) {
        for (Map.Entry<ArtifactDescriptor, Set<PluginClass>> entry : plugins.entrySet()) {
            for (PluginClass pluginClass : entry.getValue()) {
                Plugin pluginInfo = new Plugin(new ArrayList<ArtifactId>(), entry.getKey().getArtifactId(), pluginClass, PluginProperties.builder().add("class.name", TEST_EMPTY_CLASS).add("nullableLongFlag", numericValue).add("host", "example.com").add("aBoolean", "${aBoolean}").add("aByte", numericValue).add("aChar", "${aChar}").add("aDouble", "${aDouble}").add("anInt", numericValue).add("aFloat", "${aFloat}").add("aLong", numericValue).add("aShort", numericValue).build());
                // first test with quotes ("42")
                String jsonPluginStr = GSON.toJson(pluginInfo);
                pluginInfo = GSON.fromJson(jsonPluginStr, Plugin.class);
                instantiator.newInstance(pluginInfo);
                // test without quotes (42)
                pluginInfo = GSON.fromJson(jsonPluginStr.replaceAll("\"" + numericValue + "\"", numericValue), Plugin.class);
                instantiator.newInstance(pluginInfo);
                // test with quotes and dot ("42.0")
                pluginInfo = GSON.fromJson(jsonPluginStr.replaceAll(numericValue, numericValue + ".0"), Plugin.class);
                instantiator.newInstance(pluginInfo);
                // test with dot (42.0)
                pluginInfo = GSON.fromJson(jsonPluginStr.replaceAll("\"" + numericValue + "\"", numericValue + ".0"), Plugin.class);
                instantiator.newInstance(pluginInfo);
                // test with some actual double number 42.5
                pluginInfo = GSON.fromJson(jsonPluginStr.replaceAll("\"" + numericValue + "\"", numericValue + ".5"), Plugin.class);
                try {
                    instantiator.newInstance(pluginInfo);
                    Assert.fail("Plugin instantiation should fail with value '42.5'");
                } catch (InvalidPluginConfigException e) {
                // expected
                }
            }
        }
    }
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) HashSet(java.util.HashSet) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) InvalidPluginConfigException(co.cask.cdap.internal.app.runtime.plugin.InvalidPluginConfigException) PluginInstantiator(co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator) PluginClass(co.cask.cdap.api.plugin.PluginClass) File(java.io.File) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) Plugin(co.cask.cdap.api.plugin.Plugin) TestPlugin(co.cask.cdap.internal.app.plugins.test.TestPlugin) Test(org.junit.Test)

Example 64 with PluginClass

use of co.cask.cdap.api.plugin.PluginClass in project cdap by caskdata.

the class ArtifactRepositoryTest method testAddSystemArtifacts.

@Test
public void testAddSystemArtifacts() throws Exception {
    Id.Artifact systemAppArtifactId = Id.Artifact.from(Id.Namespace.SYSTEM, "PluginTest", "1.0.0");
    File systemAppJar = createAppJar(PluginTestApp.class, new File(systemArtifactsDir1, "PluginTest-1.0.0.jar"), createManifest(ManifestFields.EXPORT_PACKAGE, PluginTestRunnable.class.getPackage().getName()));
    // write plugins jar
    Id.Artifact pluginArtifactId1 = Id.Artifact.from(Id.Namespace.SYSTEM, "APlugin", "1.0.0");
    Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
    File pluginJar1 = createPluginJar(TestPlugin.class, new File(systemArtifactsDir1, "APlugin-1.0.0.jar"), manifest);
    // write plugins config file
    Map<String, PluginPropertyField> emptyMap = Collections.emptyMap();
    Set<PluginClass> manuallyAddedPlugins1 = ImmutableSet.of(new PluginClass("typeA", "manual1", "desc", "co.cask.classname", null, emptyMap), new PluginClass("typeB", "manual2", "desc", "co.cask.otherclassname", null, emptyMap));
    File pluginConfigFile = new File(systemArtifactsDir1, "APlugin-1.0.0.json");
    ArtifactConfig pluginConfig1 = new ArtifactConfig(ImmutableSet.of(new ArtifactRange(NamespaceId.SYSTEM.getNamespace(), "PluginTest", new ArtifactVersion("0.9.0"), new ArtifactVersion("2.0.0"))), // add a dummy plugin to test explicit addition of plugins through the config file
    manuallyAddedPlugins1, ImmutableMap.of("k1", "v1", "k2", "v2"));
    try (BufferedWriter writer = Files.newWriter(pluginConfigFile, Charsets.UTF_8)) {
        writer.write(pluginConfig1.toString());
    }
    // write another plugins jar to a different directory, to test that plugins will get picked up from both directories
    Id.Artifact pluginArtifactId2 = Id.Artifact.from(Id.Namespace.SYSTEM, "BPlugin", "1.0.0");
    manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
    File pluginJar2 = createPluginJar(TestPlugin.class, new File(systemArtifactsDir2, "BPlugin-1.0.0.jar"), manifest);
    // write plugins config file
    Set<PluginClass> manuallyAddedPlugins2 = ImmutableSet.of(new PluginClass("typeA", "manual1", "desc", "co.notcask.classname", null, emptyMap), new PluginClass("typeB", "manual2", "desc", "co.notcask.otherclassname", null, emptyMap));
    pluginConfigFile = new File(systemArtifactsDir2, "BPlugin-1.0.0.json");
    ArtifactConfig pluginConfig2 = new ArtifactConfig(ImmutableSet.of(new ArtifactRange(NamespaceId.SYSTEM.getNamespace(), "PluginTest", new ArtifactVersion("0.9.0"), new ArtifactVersion("2.0.0"))), manuallyAddedPlugins2, ImmutableMap.of("k3", "v3"));
    try (BufferedWriter writer = Files.newWriter(pluginConfigFile, Charsets.UTF_8)) {
        writer.write(pluginConfig2.toString());
    }
    artifactRepository.addSystemArtifacts();
    Assert.assertTrue(systemAppJar.delete());
    Assert.assertTrue(pluginJar1.delete());
    Assert.assertTrue(pluginJar2.delete());
    try {
        // check app artifact added correctly
        ArtifactDetail appArtifactDetail = artifactRepository.getArtifact(systemAppArtifactId);
        Map<ArtifactDescriptor, Set<PluginClass>> plugins = artifactRepository.getPlugins(NamespaceId.DEFAULT, systemAppArtifactId);
        Assert.assertEquals(2, plugins.size());
        Set<PluginClass> pluginClasses = plugins.values().iterator().next();
        Set<String> pluginNames = Sets.newHashSet();
        for (PluginClass pluginClass : pluginClasses) {
            pluginNames.add(pluginClass.getName());
        }
        Assert.assertEquals(Sets.newHashSet("manual1", "manual2", "TestPlugin", "TestPlugin2"), pluginNames);
        Assert.assertEquals(systemAppArtifactId.getName(), appArtifactDetail.getDescriptor().getArtifactId().getName());
        Assert.assertEquals(systemAppArtifactId.getVersion(), appArtifactDetail.getDescriptor().getArtifactId().getVersion());
        // check plugin artifact added correctly
        ArtifactDetail pluginArtifactDetail = artifactRepository.getArtifact(pluginArtifactId1);
        Assert.assertEquals(pluginArtifactId1.getName(), pluginArtifactDetail.getDescriptor().getArtifactId().getName());
        Assert.assertEquals(pluginArtifactId1.getVersion(), pluginArtifactDetail.getDescriptor().getArtifactId().getVersion());
        // check manually added plugins are there
        Assert.assertTrue(pluginArtifactDetail.getMeta().getClasses().getPlugins().containsAll(manuallyAddedPlugins1));
        // check properties are there
        Assert.assertEquals(pluginConfig1.getProperties(), pluginArtifactDetail.getMeta().getProperties());
        // check other plugin artifact added correctly
        pluginArtifactDetail = artifactRepository.getArtifact(pluginArtifactId2);
        Assert.assertEquals(pluginArtifactId2.getName(), pluginArtifactDetail.getDescriptor().getArtifactId().getName());
        Assert.assertEquals(pluginArtifactId2.getVersion(), pluginArtifactDetail.getDescriptor().getArtifactId().getVersion());
        // check manually added plugins are there
        Assert.assertTrue(pluginArtifactDetail.getMeta().getClasses().getPlugins().containsAll(manuallyAddedPlugins2));
        // check properties are there
        Assert.assertEquals(pluginConfig2.getProperties(), pluginArtifactDetail.getMeta().getProperties());
    } finally {
        artifactRepository.clear(NamespaceId.SYSTEM);
    }
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) HashSet(java.util.HashSet) PluginTestRunnable(co.cask.cdap.internal.app.runtime.artifact.app.plugin.PluginTestRunnable) ArtifactConfig(co.cask.cdap.common.conf.ArtifactConfig) ArtifactRange(co.cask.cdap.api.artifact.ArtifactRange) Manifest(java.util.jar.Manifest) PluginPropertyField(co.cask.cdap.api.plugin.PluginPropertyField) BufferedWriter(java.io.BufferedWriter) ArtifactVersion(co.cask.cdap.api.artifact.ArtifactVersion) TestPlugin(co.cask.cdap.internal.app.plugins.test.TestPlugin) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) Id(co.cask.cdap.common.id.Id) NamespaceId(co.cask.cdap.proto.id.NamespaceId) PluginClass(co.cask.cdap.api.plugin.PluginClass) File(java.io.File) Test(org.junit.Test)

Example 65 with PluginClass

use of co.cask.cdap.api.plugin.PluginClass in project cdap by caskdata.

the class ArtifactRepositoryTest method testPluginSelector.

@Test
public void testPluginSelector() throws Exception {
    // No plugin yet
    ArtifactRange appArtifactRange = new ArtifactRange(APP_ARTIFACT_ID.getNamespace().getId(), APP_ARTIFACT_ID.getName(), APP_ARTIFACT_ID.getVersion(), true, APP_ARTIFACT_ID.getVersion(), true);
    try {
        artifactRepository.findPlugin(NamespaceId.DEFAULT, appArtifactRange, "plugin", "TestPlugin2", new PluginSelector());
        Assert.fail();
    } catch (PluginNotExistsException e) {
    // expected
    }
    File pluginDir = DirUtils.createTempDir(tmpDir);
    // Create a plugin jar. It contains two plugins, TestPlugin and TestPlugin2 inside.
    Id.Artifact artifact1Id = Id.Artifact.from(Id.Namespace.DEFAULT, "myPlugin", "1.0");
    Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
    File jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-1.0.jar"), manifest);
    // Build up the plugin repository.
    Set<ArtifactRange> parents = ImmutableSet.of(new ArtifactRange(APP_ARTIFACT_ID.getNamespace().getId(), APP_ARTIFACT_ID.getName(), new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
    artifactRepository.addArtifact(artifact1Id, jarFile, parents, null);
    // Should get the only version.
    Map.Entry<ArtifactDescriptor, PluginClass> plugin = artifactRepository.findPlugin(NamespaceId.DEFAULT, appArtifactRange, "plugin", "TestPlugin2", new PluginSelector());
    Assert.assertNotNull(plugin);
    Assert.assertEquals(new ArtifactVersion("1.0"), plugin.getKey().getArtifactId().getVersion());
    Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
    Files.copy(Locations.newInputSupplier(plugin.getKey().getLocation()), new File(pluginDir, Artifacts.getFileName(plugin.getKey().getArtifactId())));
    // Create another plugin jar with later version and update the repository
    Id.Artifact artifact2Id = Id.Artifact.from(Id.Namespace.DEFAULT, "myPlugin", "2.0");
    jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-2.0.jar"), manifest);
    artifactRepository.addArtifact(artifact2Id, jarFile, parents, null);
    // Should select the latest version
    plugin = artifactRepository.findPlugin(NamespaceId.DEFAULT, appArtifactRange, "plugin", "TestPlugin2", new PluginSelector());
    Assert.assertNotNull(plugin);
    Assert.assertEquals(new ArtifactVersion("2.0"), plugin.getKey().getArtifactId().getVersion());
    Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
    Files.copy(Locations.newInputSupplier(plugin.getKey().getLocation()), new File(pluginDir, Artifacts.getFileName(plugin.getKey().getArtifactId())));
    // Load the Plugin class from the classLoader.
    try (PluginInstantiator instantiator = new PluginInstantiator(cConf, appClassLoader, pluginDir)) {
        ClassLoader pluginClassLoader = instantiator.getArtifactClassLoader(plugin.getKey().getArtifactId());
        Class<?> pluginClass = pluginClassLoader.loadClass(TestPlugin2.class.getName());
        // Use a custom plugin selector to select with smallest version
        plugin = artifactRepository.findPlugin(NamespaceId.DEFAULT, appArtifactRange, "plugin", "TestPlugin2", new PluginSelector() {

            @Override
            public Map.Entry<ArtifactId, PluginClass> select(SortedMap<ArtifactId, PluginClass> plugins) {
                return plugins.entrySet().iterator().next();
            }
        });
        Assert.assertNotNull(plugin);
        Assert.assertEquals(new ArtifactVersion("1.0"), plugin.getKey().getArtifactId().getVersion());
        Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
        // Load the Plugin class again from the current plugin selected
        // The plugin class should be different (from different ClassLoader)
        // The empty class should be the same (from the plugin lib ClassLoader)
        pluginClassLoader = instantiator.getArtifactClassLoader(plugin.getKey().getArtifactId());
        Assert.assertNotSame(pluginClass, pluginClassLoader.loadClass(TestPlugin2.class.getName()));
        // From the pluginClassLoader, loading export classes from the template jar should be allowed
        Class<?> cls = pluginClassLoader.loadClass(PluginTestRunnable.class.getName());
        // The class should be loaded from the parent artifact's classloader
        Assert.assertSame(appClassLoader.loadClass(PluginTestRunnable.class.getName()), cls);
        // From the plugin classloader, all cdap api classes is loadable as well.
        cls = pluginClassLoader.loadClass(Application.class.getName());
        // The Application class should be the same as the one in the system classloader
        Assert.assertSame(Application.class, cls);
    }
}
Also used : PluginSelector(co.cask.cdap.api.plugin.PluginSelector) TestPlugin2(co.cask.cdap.internal.app.plugins.test.TestPlugin2) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) PluginTestRunnable(co.cask.cdap.internal.app.runtime.artifact.app.plugin.PluginTestRunnable) ArtifactRange(co.cask.cdap.api.artifact.ArtifactRange) Manifest(java.util.jar.Manifest) PluginNotExistsException(co.cask.cdap.internal.app.runtime.plugin.PluginNotExistsException) ArtifactVersion(co.cask.cdap.api.artifact.ArtifactVersion) SortedMap(java.util.SortedMap) FilterClassLoader(co.cask.cdap.common.lang.FilterClassLoader) ProgramClassLoader(co.cask.cdap.internal.app.runtime.ProgramClassLoader) TestPlugin(co.cask.cdap.internal.app.plugins.test.TestPlugin) PluginInstantiator(co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator) ArtifactId(co.cask.cdap.api.artifact.ArtifactId) Id(co.cask.cdap.common.id.Id) NamespaceId(co.cask.cdap.proto.id.NamespaceId) PluginClass(co.cask.cdap.api.plugin.PluginClass) File(java.io.File) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) Test(org.junit.Test)

Aggregations

PluginClass (co.cask.cdap.api.plugin.PluginClass)76 PluginPropertyField (co.cask.cdap.api.plugin.PluginPropertyField)46 HashMap (java.util.HashMap)37 Test (org.junit.Test)24 ArtifactId (co.cask.cdap.proto.id.ArtifactId)22 NamespaceId (co.cask.cdap.proto.id.NamespaceId)21 ArtifactRange (co.cask.cdap.api.artifact.ArtifactRange)19 ArtifactVersion (co.cask.cdap.api.artifact.ArtifactVersion)17 Id (co.cask.cdap.common.id.Id)17 Set (java.util.Set)14 ImmutableSet (com.google.common.collect.ImmutableSet)13 PluginNotExistsException (co.cask.cdap.internal.app.runtime.plugin.PluginNotExistsException)11 Map (java.util.Map)11 ArtifactNotFoundException (co.cask.cdap.common.ArtifactNotFoundException)10 SortedMap (java.util.SortedMap)10 ArtifactId (co.cask.cdap.api.artifact.ArtifactId)9 File (java.io.File)9 ApplicationClass (co.cask.cdap.api.artifact.ApplicationClass)8 HashSet (java.util.HashSet)8 ImmutableMap (com.google.common.collect.ImmutableMap)7