Search in sources :

Example 1 with InvalidPluginConfigException

use of io.cdap.cdap.api.plugin.InvalidPluginConfigException 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<>(), 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) InvalidPluginConfigException(io.cdap.cdap.api.plugin.InvalidPluginConfigException) PluginInstantiator(io.cdap.cdap.internal.app.runtime.plugin.PluginInstantiator) 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) TestPlugin(io.cdap.cdap.internal.app.plugins.test.TestPlugin) NestedConfigPlugin(io.cdap.cdap.internal.app.runtime.artifact.plugin.nested.NestedConfigPlugin) Plugin(io.cdap.cdap.api.plugin.Plugin) Test(org.junit.Test)

Example 2 with InvalidPluginConfigException

use of io.cdap.cdap.api.plugin.InvalidPluginConfigException in project cdap by caskdata.

the class PluginInstantiator method newInstance.

/**
 * Creates a new instance of the given plugin class with all property macros substituted if a MacroEvaluator is given.
 * At runtime, plugin property fields that are macro-enabled and contain macro syntax will remain in the macroFields
 * set in the plugin config.
 * @param plugin {@link Plugin}
 * @param macroEvaluator the MacroEvaluator that performs macro substitution
 * @param options macro parser options
 * @param <T> Type of the plugin
 * @return a new plugin instance with macros substituted
 * @throws IOException if failed to expand the plugin jar to create the plugin ClassLoader
 * @throws ClassNotFoundException if failed to load the given plugin class
 * @throws InvalidPluginConfigException if the PluginConfig could not be created from the plugin properties
 */
public <T> T newInstance(Plugin plugin, @Nullable MacroEvaluator macroEvaluator, @Nullable MacroParserOptions options) throws IOException, ClassNotFoundException, InvalidMacroException {
    ClassLoader classLoader = getPluginClassLoader(plugin);
    PluginClass pluginClass = plugin.getPluginClass();
    @SuppressWarnings("unchecked") TypeToken<T> pluginType = TypeToken.of((Class<T>) classLoader.loadClass(pluginClass.getClassName()));
    try {
        String configFieldName = pluginClass.getConfigFieldName();
        // Plugin doesn't have config. Simply return a new instance.
        if (configFieldName == null) {
            return instantiatorFactory.get(pluginType).create();
        }
        // Create the config instance
        Field field = Fields.findField(pluginType.getType(), configFieldName);
        TypeToken<?> configFieldType = pluginType.resolveType(field.getGenericType());
        Object config = instantiatorFactory.get(configFieldType).create();
        // perform macro substitution if an evaluator is provided, collect fields with macros only at configure time
        PluginProperties pluginProperties = substituteMacros(plugin, macroEvaluator, options);
        Set<String> macroFields = (macroEvaluator == null) ? getFieldsWithMacro(plugin) : Collections.emptySet();
        PluginProperties rawProperties = plugin.getProperties();
        ConfigFieldSetter fieldSetter = new ConfigFieldSetter(pluginClass, pluginProperties, rawProperties, macroFields);
        Reflections.visit(config, configFieldType.getType(), fieldSetter);
        if (!fieldSetter.invalidProperties.isEmpty() || !fieldSetter.missingProperties.isEmpty()) {
            throw new InvalidPluginConfigException(pluginClass, fieldSetter.missingProperties, fieldSetter.invalidProperties);
        }
        // Create the plugin instance
        return newInstance(pluginType, field, configFieldType, config);
    } catch (NoSuchFieldException e) {
        throw new InvalidPluginConfigException("Config field not found in plugin class: " + pluginClass, e);
    } catch (IllegalAccessException e) {
        throw new InvalidPluginConfigException("Failed to set plugin config field: " + pluginClass, e);
    }
}
Also used : InvalidPluginConfigException(io.cdap.cdap.api.plugin.InvalidPluginConfigException) Field(java.lang.reflect.Field) PluginPropertyField(io.cdap.cdap.api.plugin.PluginPropertyField) CombineClassLoader(io.cdap.cdap.common.lang.CombineClassLoader) PluginClass(io.cdap.cdap.api.plugin.PluginClass) PluginProperties(io.cdap.cdap.api.plugin.PluginProperties)

Example 3 with InvalidPluginConfigException

use of io.cdap.cdap.api.plugin.InvalidPluginConfigException in project cdap by caskdata.

the class ValidationUtilsTest method getPluginConfigurer.

// Mock PluginConfigurer
private PluginConfigurer getPluginConfigurer(PluginClass pluginClass) {
    return new PluginConfigurer() {

        @Override
        public <T> T usePlugin(String pluginType, String pluginName, String pluginId, PluginProperties properties, PluginSelector selector) {
            String tableName = properties.getProperties().get("tableName");
            if (tableName == null || tableName.isEmpty()) {
                throw new InvalidPluginConfigException(pluginClass, Collections.singleton("tableName"), new HashSet<>());
            }
            MockSource.Config config = new MockSource.Config();
            MockSource.ConnectionConfig connectionConfig = new MockSource.ConnectionConfig();
            String schema = properties.getProperties().get("schema");
            String sleep = properties.getProperties().get("sleepInMillis");
            connectionConfig.setTableName(tableName);
            config.setConfig(connectionConfig, schema, null, sleep == null ? null : Long.parseLong(sleep));
            return (T) new MockSource(config);
        }

        @Override
        public <T> Class<T> usePluginClass(String pluginType, String pluginName, String pluginId, PluginProperties properties, PluginSelector selector) {
            return null;
        }

        @Override
        public Map<String, String> evaluateMacros(Map<String, String> properties, MacroEvaluator evaluator, MacroParserOptions options) throws InvalidMacroException {
            return null;
        }
    };
}
Also used : MockSource(io.cdap.cdap.etl.mock.batch.MockSource) PluginSelector(io.cdap.cdap.api.plugin.PluginSelector) MacroEvaluator(io.cdap.cdap.api.macro.MacroEvaluator) InvalidPluginConfigException(io.cdap.cdap.api.plugin.InvalidPluginConfigException) MacroParserOptions(io.cdap.cdap.api.macro.MacroParserOptions) PluginConfigurer(io.cdap.cdap.api.plugin.PluginConfigurer) PluginProperties(io.cdap.cdap.api.plugin.PluginProperties) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with InvalidPluginConfigException

use of io.cdap.cdap.api.plugin.InvalidPluginConfigException in project cdap by caskdata.

the class PipelineSpecGenerator method getPlugin.

/**
 * Adds a Plugin usage to the Application and create a new instance.
 *
 * @param stageName stage name
 * @param etlPlugin plugin
 * @param pluginSelector plugin selector
 * @param type type of the plugin
 * @param pluginName plugin name
 * @param collector failure collector
 * @throws ValidationException if error while creating new plugin instance
 * @return new instance of the plugin
 */
private Object getPlugin(String stageName, ETLPlugin etlPlugin, TrackedPluginSelector pluginSelector, String type, String pluginName, FailureCollector collector) {
    Object plugin = null;
    Map<String, String> pluginProperties = etlPlugin.getProperties();
    try {
        // spec
        if (runtimeEvaluator != null) {
            pluginProperties = pluginConfigurer.evaluateMacros(etlPlugin.getProperties(), runtimeEvaluator, options);
        }
        // Call to usePlugin may throw IllegalArgumentException if the plugin with the same id is already deployed.
        // This would mean there is a bug in the app and this can not be fixed by user. That is why it is not handled as
        // a ValidationFailure.
        plugin = pluginConfigurer.usePlugin(type, pluginName, stageName, PluginProperties.builder().addAll(pluginProperties).build(), pluginSelector);
    } catch (InvalidPluginConfigException e) {
        int numFailures = 0;
        for (String missingProperty : e.getMissingProperties()) {
            collector.addFailure(String.format("Required property '%s' has no value.", missingProperty), null).withConfigProperty(missingProperty);
            numFailures++;
        }
        for (InvalidPluginProperty invalidProperty : e.getInvalidProperties()) {
            collector.addFailure(e.getMessage(), null).withConfigProperty(invalidProperty.getName());
            numFailures++;
        }
        // create a generic failure
        if (numFailures == 0) {
            collector.addFailure(e.getMessage(), null);
        }
    } catch (Exception e) {
        // TODO: Catch specific exceptions when CDAP-15744 is fixed
        collector.addFailure(e.getMessage(), null).withStacktrace(e.getStackTrace());
    }
    // throw validation exception if any error occurred while creating a new instance of the plugin
    collector.getOrThrowException();
    if (plugin == null) {
        String errorMessage = String.format("Plugin named '%s' of type '%s' not found.", pluginName, type);
        String correctiveAction = String.format("Make sure plugin '%s' of type '%s' is already deployed.", pluginName, type);
        ArtifactSelectorConfig requested = etlPlugin.getArtifactConfig();
        ArtifactId requestedArtifactId = requested == null ? null : new ArtifactId(requested.getName(), new ArtifactVersion(requested.getVersion()), ArtifactScope.valueOf(requested.getScope()));
        ArtifactSelectorConfig suggestion = pluginSelector.getSuggestion();
        ArtifactId suggestedArtifactId = null;
        if (suggestion != null) {
            suggestedArtifactId = new ArtifactId(suggestion.getName(), new ArtifactVersion(suggestion.getVersion()), ArtifactScope.valueOf(suggestion.getScope()));
        }
        collector.addFailure(errorMessage, correctiveAction).withPluginNotFound(stageName, pluginName, type, requestedArtifactId, suggestedArtifactId);
        // throw validation exception if the plugin is not initialized
        collector.getOrThrowException();
    }
    return plugin;
}
Also used : ArtifactVersion(io.cdap.cdap.api.artifact.ArtifactVersion) ArtifactSelectorConfig(io.cdap.cdap.etl.proto.ArtifactSelectorConfig) ArtifactId(io.cdap.cdap.api.artifact.ArtifactId) InvalidPluginConfigException(io.cdap.cdap.api.plugin.InvalidPluginConfigException) InvalidPluginProperty(io.cdap.cdap.api.plugin.InvalidPluginProperty) InvalidConfigPropertyException(io.cdap.cdap.etl.api.validation.InvalidConfigPropertyException) InvalidPluginConfigException(io.cdap.cdap.api.plugin.InvalidPluginConfigException) ValidationException(io.cdap.cdap.etl.api.validation.ValidationException) ConnectionBadRequestException(io.cdap.cdap.etl.proto.connection.ConnectionBadRequestException) InvalidStageException(io.cdap.cdap.etl.api.validation.InvalidStageException)

Aggregations

InvalidPluginConfigException (io.cdap.cdap.api.plugin.InvalidPluginConfigException)4 PluginClass (io.cdap.cdap.api.plugin.PluginClass)2 PluginProperties (io.cdap.cdap.api.plugin.PluginProperties)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 ArtifactId (io.cdap.cdap.api.artifact.ArtifactId)1 ArtifactVersion (io.cdap.cdap.api.artifact.ArtifactVersion)1 MacroEvaluator (io.cdap.cdap.api.macro.MacroEvaluator)1 MacroParserOptions (io.cdap.cdap.api.macro.MacroParserOptions)1 InvalidPluginProperty (io.cdap.cdap.api.plugin.InvalidPluginProperty)1 Plugin (io.cdap.cdap.api.plugin.Plugin)1 PluginConfigurer (io.cdap.cdap.api.plugin.PluginConfigurer)1 PluginPropertyField (io.cdap.cdap.api.plugin.PluginPropertyField)1 PluginSelector (io.cdap.cdap.api.plugin.PluginSelector)1 CombineClassLoader (io.cdap.cdap.common.lang.CombineClassLoader)1 InvalidConfigPropertyException (io.cdap.cdap.etl.api.validation.InvalidConfigPropertyException)1 InvalidStageException (io.cdap.cdap.etl.api.validation.InvalidStageException)1 ValidationException (io.cdap.cdap.etl.api.validation.ValidationException)1