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
}
}
}
}
}
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);
}
}
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;
}
};
}
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;
}
Aggregations