use of org.apache.nifi.update.attributes.Action in project nifi by apache.
the class UpdateAttribute method customValidate.
@Override
protected Collection<ValidationResult> customValidate(final ValidationContext context) {
final List<ValidationResult> reasons = new ArrayList<>(super.customValidate(context));
if (!context.getProperty(STORE_STATE).getValue().equals(DO_NOT_STORE_STATE)) {
String initValue = context.getProperty(STATEFUL_VARIABLES_INIT_VALUE).getValue();
if (initValue == null) {
reasons.add(new ValidationResult.Builder().subject(STATEFUL_VARIABLES_INIT_VALUE.getDisplayName()).valid(false).explanation("initial state value must be set if the processor is configured to store state.").build());
}
}
Criteria criteria = null;
try {
criteria = CriteriaSerDe.deserialize(context.getAnnotationData());
} catch (IllegalArgumentException iae) {
reasons.add(new ValidationResult.Builder().valid(false).explanation("Unable to deserialize the update criteria." + iae.getMessage()).build());
}
// if there is criteria, validate it
if (criteria != null) {
final List<Rule> rules = criteria.getRules();
if (rules == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation("Update criteria has been specified by no rules were found.").build());
} else {
// validate the each rule
for (final Rule rule : rules) {
if (rule.getName() == null || rule.getName().trim().isEmpty()) {
reasons.add(new ValidationResult.Builder().valid(false).explanation("A rule name was not specified.").build());
}
// validate each condition
final Set<Condition> conditions = rule.getConditions();
if (conditions == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation(String.format("No conditions for rule '%s' found.", rule.getName())).build());
} else {
for (final Condition condition : conditions) {
if (condition.getExpression() == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation(String.format("No expression for a condition in rule '%s' was found.", rule.getName())).build());
} else {
final String expression = condition.getExpression().trim();
reasons.add(StandardValidators.createAttributeExpressionLanguageValidator(AttributeExpression.ResultType.BOOLEAN, false).validate(String.format("Condition for rule '%s'.", rule.getName()), expression, context));
}
}
}
// validate each action
final Set<Action> actions = rule.getActions();
if (actions == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation(String.format("No actions for rule '%s' found.", rule.getName())).build());
} else {
for (final Action action : actions) {
if (action.getAttribute() == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation(String.format("An action in rule '%s' is missing the attribute name.", rule.getName())).build());
} else if (action.getValue() == null) {
reasons.add(new ValidationResult.Builder().valid(false).explanation(String.format("No value for attribute '%s' in rule '%s' was found.", action.getAttribute(), rule.getName())).build());
} else {
reasons.add(StandardValidators.createAttributeExpressionLanguageValidator(AttributeExpression.ResultType.STRING, true).validate(String.format("Action for rule '%s'.", rule.getName()), action.getValue(), context));
}
}
}
}
}
}
return reasons;
}
use of org.apache.nifi.update.attributes.Action in project nifi by apache.
the class UpdateAttribute method executeActions.
// Executes the specified action on the specified flowfile.
private FlowFile executeActions(final ProcessSession session, final ProcessContext context, final List<Rule> rules, final Map<String, Action> defaultActions, final FlowFile flowfile, final Map<String, String> stateInitialAttributes, final Map<String, String> stateWorkingAttributes) {
final ComponentLog logger = getLogger();
final Map<String, Action> actions = new HashMap<>(defaultActions);
final String ruleName = (rules == null || rules.isEmpty()) ? "default" : rules.get(rules.size() - 1).getName();
// if a rule matched, get its actions and possible overwrite the default ones
if (rules != null && rules.size() > 0) {
// subsequent matching rules will take precedence over previously matching rules and default values
for (final Rule rule : rules) {
for (final Action action : rule.getActions()) {
// store the action and overwrite the previous value (from the defaults or a previously matching rule)
actions.put(action.getAttribute(), action);
}
}
// add an action for the matched rule - when matching multiple rules against
// the original flowfile (use original) this will leave the last matching
// rule's name as the value of this attribute. this decision was made since
// this would be the behavior if they user chained multiple UpdateAttributes
// together with 'use clone' specified
final Action matchedRuleAction = new Action();
matchedRuleAction.setAttribute(getClass().getSimpleName() + ".matchedRule");
matchedRuleAction.setValue(ruleName);
actions.put(matchedRuleAction.getAttribute(), matchedRuleAction);
}
// attribute values that will be applied to the flow file
final Map<String, String> attributesToUpdate = new HashMap<>(actions.size());
final Set<String> attributesToDelete = new HashSet<>(actions.size());
// go through each action
boolean debugEnabled = this.debugEnabled;
for (final Action action : actions.values()) {
String attribute = action.getAttribute();
if (DELETE_ATTRIBUTES_EXPRESSION_NAME.equals(attribute)) {
try {
final String actionValue = action.getValue();
final String regex = (actionValue == null) ? null : getPropertyValue(actionValue, context).evaluateAttributeExpressions(flowfile).getValue();
if (regex != null) {
Pattern pattern = Pattern.compile(regex);
final Set<String> attributeKeys = flowfile.getAttributes().keySet();
for (final String key : attributeKeys) {
if (pattern.matcher(key).matches()) {
// log if appropriate
if (debugEnabled) {
logger.debug(String.format("%s deleting attribute '%s' for %s per regex '%s'.", this, key, flowfile, regex));
}
attributesToDelete.add(key);
}
}
// No point in updating if they will be removed
attributesToUpdate.keySet().removeAll(attributesToDelete);
}
} catch (final Exception e) {
logger.error(String.format("Unable to delete attribute '%s' while processing FlowFile '%s' .", attribute, flowfile));
throw new ProcessException(String.format("Unable to delete attribute '%s': %s.", attribute, e), e);
}
} else {
boolean notDeleted = !attributesToDelete.contains(attribute);
boolean setStatefulAttribute = stateInitialAttributes != null && !attribute.equals("UpdateAttribute.matchedRule");
if (notDeleted || setStatefulAttribute) {
try {
final String newAttributeValue = getPropertyValue(action.getValue(), context).evaluateAttributeExpressions(flowfile, null, null, stateInitialAttributes).getValue();
// log if appropriate
if (debugEnabled) {
logger.debug(String.format("%s setting attribute '%s' = '%s' for %s per rule '%s'.", this, attribute, newAttributeValue, flowfile, ruleName));
}
if (setStatefulAttribute) {
stateWorkingAttributes.put(attribute, newAttributeValue);
}
// No point in updating if it will be removed
if (notDeleted) {
attributesToUpdate.put(attribute, newAttributeValue);
}
// Capture Exception thrown when evaluating the Expression Language
} catch (final Exception e) {
logger.error(String.format("Could not evaluate the FlowFile '%s' against expression '%s' " + "defined by DynamicProperty '%s' due to '%s'", flowfile, action.getValue(), attribute, e.getLocalizedMessage()));
throw new ProcessException(String.format("Unable to evaluate new value for attribute '%s': %s.", attribute, e), e);
}
}
}
}
// If the 'alternate.identifier' attribute is added, then we want to create an ADD_INFO provenance event.
final String alternateIdentifierAdd = attributesToUpdate.get(CoreAttributes.ALTERNATE_IDENTIFIER.key());
if (alternateIdentifierAdd != null) {
try {
final URI uri = new URI(alternateIdentifierAdd);
final String namespace = uri.getScheme();
if (namespace != null) {
final String identifier = alternateIdentifierAdd.substring(Math.min(namespace.length() + 1, alternateIdentifierAdd.length() - 1));
session.getProvenanceReporter().associate(flowfile, namespace, identifier);
}
} catch (final URISyntaxException e) {
}
}
// update and delete the FlowFile attributes
FlowFile returnFlowfile = flowfile;
if (attributesToUpdate.size() > 0) {
returnFlowfile = session.putAllAttributes(returnFlowfile, attributesToUpdate);
}
if (attributesToDelete.size() > 0) {
returnFlowfile = session.removeAllAttributes(returnFlowfile, attributesToDelete);
}
return returnFlowfile;
}
use of org.apache.nifi.update.attributes.Action in project nifi by apache.
the class UpdateAttribute method search.
@Override
public Collection<SearchResult> search(final SearchContext context) {
final String term = context.getSearchTerm();
final Collection<SearchResult> results = new ArrayList<>();
if (StringUtils.isBlank(context.getAnnotationData())) {
return results;
}
try {
// parse the annotation data
final Criteria criteria = CriteriaSerDe.deserialize(context.getAnnotationData());
// ensure there are some rules
if (criteria.getRules() != null) {
final FlowFilePolicy flowFilePolicy = criteria.getFlowFilePolicy();
if (flowFilePolicy != null && StringUtils.containsIgnoreCase(flowFilePolicy.name(), term)) {
results.add(new SearchResult.Builder().label("FlowFile policy").match(flowFilePolicy.name()).build());
}
for (final Rule rule : criteria.getRules()) {
if (StringUtils.containsIgnoreCase(rule.getName(), term)) {
results.add(new SearchResult.Builder().label("Rule name").match(rule.getName()).build());
}
// ensure there are some conditions
if (rule.getConditions() != null) {
for (final Condition condition : rule.getConditions()) {
if (StringUtils.containsIgnoreCase(condition.getExpression(), term)) {
results.add(new SearchResult.Builder().label(String.format("Condition in rule '%s'", rule.getName())).match(condition.getExpression()).build());
}
}
}
// ensure there are some actions
if (rule.getActions() != null) {
for (final Action action : rule.getActions()) {
if (StringUtils.containsIgnoreCase(action.getAttribute(), term)) {
results.add(new SearchResult.Builder().label(String.format("Action in rule '%s'", rule.getName())).match(action.getAttribute()).build());
}
if (StringUtils.containsIgnoreCase(action.getValue(), term)) {
results.add(new SearchResult.Builder().label(String.format("Action in rule '%s'", rule.getName())).match(action.getValue()).build());
}
}
}
}
}
return results;
} catch (Exception e) {
return results;
}
}
use of org.apache.nifi.update.attributes.Action in project nifi by apache.
the class UpdateAttribute method onScheduled.
@OnScheduled
public void onScheduled(final ProcessContext context) throws IOException {
criteriaCache.set(CriteriaSerDe.deserialize(context.getAnnotationData()));
propertyValues.clear();
if (stateful) {
StateManager stateManager = context.getStateManager();
StateMap state = stateManager.getState(Scope.LOCAL);
HashMap<String, String> tempMap = new HashMap<>();
tempMap.putAll(state.toMap());
String initValue = context.getProperty(STATEFUL_VARIABLES_INIT_VALUE).getValue();
// Initialize the stateful default actions
for (PropertyDescriptor entry : context.getProperties().keySet()) {
if (entry.isDynamic()) {
if (!tempMap.containsKey(entry.getName())) {
tempMap.put(entry.getName(), initValue);
}
}
}
// Initialize the stateful actions if the criteria exists
final Criteria criteria = criteriaCache.get();
if (criteria != null) {
for (Rule rule : criteria.getRules()) {
for (Action action : rule.getActions()) {
if (!tempMap.containsKey(action.getAttribute())) {
tempMap.put(action.getAttribute(), initValue);
}
}
}
}
context.getStateManager().setState(tempMap, Scope.LOCAL);
}
defaultActions = getDefaultActions(context.getProperties());
debugEnabled = getLogger().isDebugEnabled();
}
Aggregations