Search in sources :

Example 1 with PluginNotExistsException

use of io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException in project cdap by caskdata.

the class ArtifactStore method getPluginClasses.

/**
 * Get all plugin classes of the given type and name that extend the given parent artifact.
 * Results are returned as a map from plugin artifact to plugins in that artifact.
 *
 * @param namespace the namespace to search for plugins. The system namespace is always included.
 * @param parentArtifactRange the parent artifact range to find plugins for
 * @param type the type of plugin to look for
 * @param name the name of the plugin to look for
 * @param pluginRange the predicate for the plugins
 * @param limit the limit number of the result
 * @param order the order of the result
 * @return an unmodifiable map of plugin artifact to plugin classes of the given type and name, accessible by the
 *         given artifact. The map will never be null, and will never be empty.
 * @throws PluginNotExistsException if no plugin with the given type and name exists in the namespace
 * @throws IOException if there was an exception reading metadata from the metastore
 */
public SortedMap<ArtifactDescriptor, PluginClass> getPluginClasses(NamespaceId namespace, ArtifactRange parentArtifactRange, String type, String name, @Nullable final Predicate<io.cdap.cdap.proto.id.ArtifactId> pluginRange, int limit, ArtifactSortOrder order) throws IOException, ArtifactNotFoundException, PluginNotExistsException {
    SortedMap<ArtifactDescriptor, PluginClass> result = TransactionRunners.run(transactionRunner, context -> {
        StructuredTable artifactDataTable = getTable(context, StoreDefinition.ArtifactStore.ARTIFACT_DATA_TABLE);
        List<ArtifactDetail> parentArtifactDetails = getArtifacts(artifactDataTable, parentArtifactRange, Integer.MAX_VALUE, null);
        if (parentArtifactDetails.isEmpty()) {
            throw new ArtifactNotFoundException(parentArtifactRange.getNamespace(), parentArtifactRange.getName());
        }
        SortedMap<ArtifactDescriptor, PluginClass> plugins = order == ArtifactSortOrder.DESC ? new TreeMap<>(Collections.reverseOrder()) : new TreeMap<>();
        List<Id.Artifact> parentArtifacts = new ArrayList<>();
        for (ArtifactDetail parentArtifactDetail : parentArtifactDetails) {
            parentArtifacts.add(Id.Artifact.from(Id.Namespace.from(parentArtifactRange.getNamespace()), parentArtifactDetail.getDescriptor().getArtifactId()));
            Set<PluginClass> parentPlugins = parentArtifactDetail.getMeta().getClasses().getPlugins();
            for (PluginClass pluginClass : parentPlugins) {
                if (pluginClass.getName().equals(name) && pluginClass.getType().equals(type) && isAllowed(pluginClass)) {
                    plugins.put(parentArtifactDetail.getDescriptor(), pluginClass);
                    break;
                }
            }
        }
        // Add all plugins that extends from the given set of parents
        StructuredTable pluginTable = getTable(context, StoreDefinition.ArtifactStore.PLUGIN_DATA_TABLE);
        PluginKeyPrefix pluginKey = new PluginKeyPrefix(parentArtifactRange.getNamespace(), parentArtifactRange.getName(), type, name);
        try (CloseableIterator<StructuredRow> iterator = pluginTable.scan(Range.singleton(pluginKey.keys), Integer.MAX_VALUE)) {
            addPluginsInRangeToMap(namespace, parentArtifacts, iterator, plugins, pluginRange, limit);
        }
        // Add all universal plugins
        StructuredTable uniPluginTable = getTable(context, StoreDefinition.ArtifactStore.UNIV_PLUGIN_DATA_TABLE);
        for (String ns : Arrays.asList(namespace.getNamespace(), NamespaceId.SYSTEM.getNamespace())) {
            UniversalPluginKeyPrefix universalPluginKey = new UniversalPluginKeyPrefix(ns, type, name);
            try (CloseableIterator<StructuredRow> iterator = uniPluginTable.scan(Range.singleton(universalPluginKey.keys), Integer.MAX_VALUE)) {
                addPluginsInRangeToMap(namespace, parentArtifacts, iterator, plugins, pluginRange, limit);
            }
        }
        return Collections.unmodifiableSortedMap(plugins);
    }, IOException.class, ArtifactNotFoundException.class);
    if (result.isEmpty()) {
        throw new PluginNotExistsException(new NamespaceId(parentArtifactRange.getNamespace()), type, name);
    }
    return result;
}
Also used : StructuredTable(io.cdap.cdap.spi.data.StructuredTable) ArrayList(java.util.ArrayList) StructuredRow(io.cdap.cdap.spi.data.StructuredRow) PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) PluginClass(io.cdap.cdap.api.plugin.PluginClass) ArtifactNotFoundException(io.cdap.cdap.common.ArtifactNotFoundException)

Example 2 with PluginNotExistsException

use of io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException in project cdap by caskdata.

the class DefaultPluginConfigurer method addPlugin.

protected Plugin addPlugin(String pluginType, String pluginName, String pluginId, PluginProperties properties, PluginSelector selector) throws PluginNotExistsException {
    validateExistingPlugin(pluginId);
    final Class[] callerClasses = CallerClassSecurityManager.getCallerClasses();
    if (callerClasses.length < 3) {
        // This shouldn't happen as there should be someone calling this method.
        throw new IllegalStateException("Invalid call stack.");
    }
    Set<ArtifactId> parents = new LinkedHashSet<>();
    // 0 is the CallerClassSecurityManager, 1 is this class, hence 2 is the actual caller
    for (int i = 2; i < callerClasses.length; i++) {
        ClassLoader classloader = callerClasses[i].getClassLoader();
        if (classloader instanceof PluginClassLoader) {
            // if this is the first time we've seen this plugin artifact, it must be a new plugin parent.
            io.cdap.cdap.api.artifact.ArtifactId pluginCallerArtifactId = ((PluginClassLoader) classloader).getArtifactId();
            parents.add((pluginCallerArtifactId.getScope() == ArtifactScope.SYSTEM ? NamespaceId.SYSTEM : pluginNamespaceId).artifact(pluginCallerArtifactId.getName(), pluginCallerArtifactId.getVersion().getVersion()));
        }
    }
    PluginNotExistsException exception = null;
    for (ArtifactId parentId : Iterables.concat(parents, Collections.singleton(artifactId))) {
        try {
            Map.Entry<ArtifactDescriptor, PluginClass> pluginEntry = pluginFinder.findPlugin(pluginNamespaceId, parentId, pluginType, pluginName, selector);
            Plugin plugin = FindPluginHelper.getPlugin(Iterables.transform(parents, ArtifactId::toApiArtifactId), pluginEntry, properties, pluginInstantiator);
            plugins.put(pluginId, new PluginWithLocation(plugin, pluginEntry.getKey().getLocation()));
            return plugin;
        } catch (PluginNotExistsException e) {
            // ignore this in case the plugin extends something higher up in the call stack.
            // For example, suppose the app uses pluginA, which uses pluginB. However, pluginB is a plugin that
            // has the app as its parent and not pluginA as its parent. In this case, we want to keep going up the call
            // stack until we get to the app as the parent, which would be able to find plugin B.
            exception = e;
        }
    }
    throw exception == null ? new PluginNotExistsException(pluginNamespaceId, pluginType, pluginName) : exception;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ArtifactId(io.cdap.cdap.proto.id.ArtifactId) PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) ArtifactDescriptor(io.cdap.cdap.internal.app.runtime.artifact.ArtifactDescriptor) PluginClassLoader(io.cdap.cdap.internal.app.runtime.plugin.PluginClassLoader) PluginClass(io.cdap.cdap.api.plugin.PluginClass) PluginClass(io.cdap.cdap.api.plugin.PluginClass) HashMap(java.util.HashMap) Map(java.util.Map) PluginClassLoader(io.cdap.cdap.internal.app.runtime.plugin.PluginClassLoader) Plugin(io.cdap.cdap.api.plugin.Plugin)

Example 3 with PluginNotExistsException

use of io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException in project cdap by caskdata.

the class RemotePluginFinder method getPlugins.

/**
 * Gets a list of {@link PluginInfo} from the artifact extension endpoint.
 *
 * @param namespaceId      namespace of the call happening in
 * @param parentArtifactId the parent artifact id
 * @param pluginType       the plugin type to look for
 * @param pluginName       the plugin name to look for
 * @return a list of {@link PluginInfo}
 * @throws IOException              if it failed to get the information
 * @throws PluginNotExistsException if the given plugin type and name doesn't exist
 */
private List<PluginInfo> getPlugins(NamespaceId namespaceId, ArtifactId parentArtifactId, String pluginType, String pluginName) throws IOException, PluginNotExistsException, UnauthorizedException {
    // replace the space in the name
    // TODO: CDAP-18375 improve url encoding the our remote call
    pluginName = pluginName.replace(" ", "%20");
    HttpRequest.Builder requestBuilder = remoteClient.requestBuilder(HttpMethod.GET, String.format("namespaces/%s/artifacts/%s/versions/%s/extensions/%s/plugins/%s?scope=%s&pluginScope=%s", namespaceId.getNamespace(), parentArtifactId.getArtifact(), parentArtifactId.getVersion(), pluginType, pluginName, NamespaceId.SYSTEM.equals(parentArtifactId.getNamespaceId()) ? ArtifactScope.SYSTEM : ArtifactScope.USER, NamespaceId.SYSTEM.equals(namespaceId.getNamespaceId()) ? ArtifactScope.SYSTEM : ArtifactScope.USER));
    HttpResponse response = remoteClient.execute(requestBuilder.build());
    int responseCode = response.getResponseCode();
    if (responseCode != HttpURLConnection.HTTP_OK) {
        switch(responseCode) {
            // throw retryable error if app fabric is not available, might be due to restarting
            case HttpURLConnection.HTTP_BAD_GATEWAY:
            case HttpURLConnection.HTTP_UNAVAILABLE:
            case HttpURLConnection.HTTP_GATEWAY_TIMEOUT:
                throw new ServiceUnavailableException(Constants.Service.APP_FABRIC_HTTP, Constants.Service.APP_FABRIC_HTTP + " service is not available with status " + responseCode);
            case HttpURLConnection.HTTP_NOT_FOUND:
                throw new PluginNotExistsException(namespaceId, pluginType, pluginName);
        }
        throw new IllegalArgumentException("Failure in getting plugin information with type " + pluginType + " and name " + pluginName + " that extends " + parentArtifactId + ". Reason is " + responseCode + ": " + response.getResponseBodyAsString());
    }
    return GSON.fromJson(response.getResponseBodyAsString(), PLUGIN_INFO_LIST_TYPE);
}
Also used : HttpRequest(io.cdap.common.http.HttpRequest) PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) HttpResponse(io.cdap.common.http.HttpResponse) ServiceUnavailableException(io.cdap.cdap.common.ServiceUnavailableException)

Example 4 with PluginNotExistsException

use of io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException in project cdap by caskdata.

the class ArtifactStoreTest method testSnapshotMutability.

@Test
public void testSnapshotMutability() throws Exception {
    // write parent
    Id.Artifact parentArtifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "parent", "1.0.0");
    ArtifactMeta parentMeta = new ArtifactMeta(ArtifactClasses.builder().build());
    writeArtifact(parentArtifactId, parentMeta, "content");
    ArtifactRange parentArtifacts = new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "parent", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0"));
    // write the snapshot once
    PluginClass plugin1 = PluginClass.builder().setName("plugin1").setType("atype").setDescription("").setClassName("c.c.c.plugin1").setConfigFieldName("cfg").setProperties(ImmutableMap.of()).build();
    PluginClass plugin2 = PluginClass.builder().setName("plugin2").setType("atype").setDescription("").setClassName("c.c.c.plugin2").setConfigFieldName("cfg").setProperties(ImmutableMap.of()).build();
    Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "myplugins", "1.0.0-SNAPSHOT");
    ArtifactMeta artifactMeta = new ArtifactMeta(ArtifactClasses.builder().addPlugins(plugin1, plugin2).build(), ImmutableSet.of(parentArtifacts));
    writeArtifact(artifactId, artifactMeta, "abc123");
    // update meta and jar contents
    artifactMeta = new ArtifactMeta(ArtifactClasses.builder().addPlugin(plugin2).build(), ImmutableSet.of(parentArtifacts));
    writeArtifact(artifactId, artifactMeta, "xyz321");
    // check the metadata and contents got updated
    ArtifactDetail detail = artifactStore.getArtifact(artifactId);
    assertEqual(artifactId, artifactMeta, "xyz321", detail);
    // check that plugin1 was deleted and plugin2 remains
    Assert.assertEquals(ImmutableMap.of(detail.getDescriptor(), plugin2), artifactStore.getPluginClasses(NamespaceId.DEFAULT, parentArtifactId, plugin2.getType(), plugin2.getName(), null, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED));
    try {
        artifactStore.getPluginClasses(NamespaceId.DEFAULT, parentArtifactId, plugin1.getType(), plugin1.getName(), null, Integer.MAX_VALUE, ArtifactSortOrder.UNORDERED);
        Assert.fail();
    } catch (PluginNotExistsException e) {
    // expected
    }
}
Also used : PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) ArtifactVersion(io.cdap.cdap.api.artifact.ArtifactVersion) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) Id(io.cdap.cdap.common.id.Id) ArtifactId(io.cdap.cdap.proto.id.ArtifactId) PluginClass(io.cdap.cdap.api.plugin.PluginClass) Test(org.junit.Test)

Example 5 with PluginNotExistsException

use of io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException 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());
    Locations.linkOrCopyOverwrite(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());
    Locations.linkOrCopyOverwrite(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(io.cdap.cdap.api.plugin.PluginSelector) TestPlugin2(io.cdap.cdap.internal.app.plugins.test.TestPlugin2) ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) PluginTestRunnable(io.cdap.cdap.internal.app.runtime.artifact.app.plugin.PluginTestRunnable) ArtifactRange(io.cdap.cdap.api.artifact.ArtifactRange) Manifest(java.util.jar.Manifest) PluginNotExistsException(io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException) ArtifactVersion(io.cdap.cdap.api.artifact.ArtifactVersion) SortedMap(java.util.SortedMap) ProgramClassLoader(io.cdap.cdap.internal.app.runtime.ProgramClassLoader) FilterClassLoader(io.cdap.cdap.common.lang.FilterClassLoader) TestPlugin(io.cdap.cdap.internal.app.plugins.test.TestPlugin) PluginInstantiator(io.cdap.cdap.internal.app.runtime.plugin.PluginInstantiator) NamespaceId(io.cdap.cdap.proto.id.NamespaceId) PluginId(io.cdap.cdap.proto.id.PluginId) Id(io.cdap.cdap.common.id.Id) ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) PluginClass(io.cdap.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

PluginNotExistsException (io.cdap.cdap.internal.app.runtime.plugin.PluginNotExistsException)10 PluginClass (io.cdap.cdap.api.plugin.PluginClass)9 ArtifactVersion (io.cdap.cdap.api.artifact.ArtifactVersion)7 ArtifactId (io.cdap.cdap.proto.id.ArtifactId)6 NamespaceId (io.cdap.cdap.proto.id.NamespaceId)6 Map (java.util.Map)6 ArtifactRange (io.cdap.cdap.api.artifact.ArtifactRange)4 SortedMap (java.util.SortedMap)4 Test (org.junit.Test)4 Id (io.cdap.cdap.common.id.Id)3 ArtifactDescriptor (io.cdap.cdap.internal.app.runtime.artifact.ArtifactDescriptor)3 HashMap (java.util.HashMap)3 Predicate (com.google.common.base.Predicate)2 ArtifactId (io.cdap.cdap.api.artifact.ArtifactId)2 ArtifactSummary (io.cdap.cdap.api.artifact.ArtifactSummary)2 ArtifactVersionRange (io.cdap.cdap.api.artifact.ArtifactVersionRange)2 PluginSelector (io.cdap.cdap.api.plugin.PluginSelector)2 ArtifactNotFoundException (io.cdap.cdap.common.ArtifactNotFoundException)2 ServiceUnavailableException (io.cdap.cdap.common.ServiceUnavailableException)2 ArtifactSortOrder (io.cdap.cdap.proto.artifact.ArtifactSortOrder)2