ConditionalConfigWorkflowOperationHandler.java

/*
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 *
 * The Apereo Foundation licenses this file to you under the Educational
 * Community License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License
 * at:
 *
 *   http://opensource.org/licenses/ecl2.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package org.opencastproject.workflow.handler.workflow;

import org.opencastproject.job.api.JobContext;
import org.opencastproject.mediapackage.MediaPackage;
import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
import org.opencastproject.workflow.api.WorkflowInstance;
import org.opencastproject.workflow.api.WorkflowOperationException;
import org.opencastproject.workflow.api.WorkflowOperationHandler;
import org.opencastproject.workflow.api.WorkflowOperationInstance;
import org.opencastproject.workflow.api.WorkflowOperationResult;
import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
import org.opencastproject.workflow.conditionparser.WorkflowConditionInterpreter;

import org.apache.commons.lang3.StringUtils;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Component(
    immediate = true,
    service = WorkflowOperationHandler.class,
    property = {
        "service.description=Set a Workflow Configuration based on Conditions Operation Handler",
        "workflow.operation=conditional-config"
    }
)
public class ConditionalConfigWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
  public static final String CONFIGURATION_NAME = "configuration-name";
  public static final String CONDITION_PREFIX = "condition-";
  public static final String VALUE_PREFIX = "value-";
  public static final String NO_MATCH = "no-match";

  private static final Logger logger = LoggerFactory.getLogger(ConditionalConfigWorkflowOperationHandler.class);

  @Activate
  @Override
  public void activate(ComponentContext cc) {
    super.activate(cc);
  }

  @Override
  public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
          throws WorkflowOperationException {
    WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
    MediaPackage mp = workflowInstance.getMediaPackage();

    Map<String, String> properties = new HashMap<>();

    // Get name of wf configuration to be set
    String wfConfigName = operation.getConfiguration(CONFIGURATION_NAME);
    if (StringUtils.isEmpty(wfConfigName)) {
      logger.warn("No workflow configuration was set because {} was not passed. Operation skipped.",
              CONFIGURATION_NAME);
      return createResult(Action.SKIP);
    }

    String value = "false";
    // Loop through all "condition-" keys
    for (String key : operation.getConfigurationKeys().stream().filter(x -> x.startsWith(CONDITION_PREFIX))
            .sorted().collect(Collectors.toList())) {
      // Evaluate condition
      String condition = operation.getConfiguration(key);
      if (StringUtils.isEmpty(condition)) {
        continue;
      }
      boolean result = false;
      try {
        result = WorkflowConditionInterpreter.interpret(condition.trim());
        logger.debug("Evaluate condition: {}, result: {}", condition, result);
      } catch (IllegalArgumentException e) {
        logger.error("Invalid condition to evaluate: {}.", condition);
        throw new WorkflowOperationException(String.format("Invalid condition: %s", condition.trim()), e);
      }
      // If condition true, set variable and return
      if (result) {
        String valuePropName = VALUE_PREFIX + key.substring(CONDITION_PREFIX.length());
        value = operation.getConfiguration(valuePropName);
        if (StringUtils.isEmpty(value)) {
          logger.error("Condition {}  evaluated to true, but no value informed to set {} variable in {}",
                  condition.trim(), wfConfigName, valuePropName);
          throw new WorkflowOperationException(
                  String.format("Condition: %s does not have a value set.", condition.trim()));
        }
         // Replace workflow configuration, even if already set.
        properties.put(wfConfigName, value.trim());
        logger.debug("Configuration key '{}' of workflow {} is set to value '{}'", wfConfigName, id, value.trim());
        return createResult(mp, properties, Action.CONTINUE, 0);
      }
    }

    // If we got here, no condition was evaluated true so we use the no-match configuration if there
    String noMatch = operation.getConfiguration(NO_MATCH);
    if (StringUtils.isNotEmpty(NO_MATCH)) {
      properties.put(wfConfigName, noMatch);
      logger.debug("Configuration key '{}' of workflow {} is set to value '{}'", wfConfigName, id, noMatch);
      return createResult(mp, properties, Action.CONTINUE, 0);
    }
    return createResult(Action.SKIP);
  }

}