All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.botronsoft.cmj.spitools.workflow.AbstractWorkflowParticipantHandler Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
package com.botronsoft.cmj.spitools.workflow;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;

import org.apache.log4j.Logger;

import com.botronsoft.cmj.spi.annotations.PublicApi;
import com.botronsoft.cmj.spi.configuration.ExportContext;
import com.botronsoft.cmj.spi.configuration.ImportContext;
import com.botronsoft.cmj.spi.configuration.workflow.WorkflowParticipantHandler;
import com.botronsoft.cmj.spitools.dsl.ArgumentContainerDescriptor;
import com.botronsoft.cmj.spitools.dsl.ArgumentDescriptor;
import com.botronsoft.cmj.spitools.impl.JiraManagersService;
import com.botronsoft.cmj.spitools.impl.JiraManagersServiceImpl;
import com.botronsoft.cmj.spitools.impl.dsl.ArgumentContainerDescriptorImpl;
import com.botronsoft.cmj.spitools.impl.transformation.ArgumentProcessor;
import com.botronsoft.cmj.spitools.impl.transformation.ArgumentProcessorFactory;

/**
 * Base class for {@link WorkflowParticipantHandler} implementations that want to use the DSL for describing the syntax of transition
 * participant arguments. Transition participants are conditions, validators and post-functions. Extend this class and implement the
 * {@link #describeArguments()} method to describe the syntax of all arguments by invoking the {@link #condition(String)},
 * {@link #validator(String)}, {@link #postFunction(String)} methods.
 */
@PublicApi
public abstract class AbstractWorkflowParticipantHandler implements WorkflowParticipantHandler {

	private static final Logger log = Logger.getLogger(AbstractWorkflowParticipantHandler.class);

	private final ArgumentProcessorFactory argumentProcessorFactory;
	private final Map argumentContainerDescriptorsMap = new HashMap<>();

	/**
	 * Non-argument constructor for implementations.
	 */
	public AbstractWorkflowParticipantHandler() {
		this(new JiraManagersServiceImpl());
	}

	AbstractWorkflowParticipantHandler(JiraManagersService jiraManagersService) {
		this.argumentProcessorFactory = new ArgumentProcessorFactory(jiraManagersService);

		describeArguments();
	}

	@Override
	public Map transformArgumentsForExport(String className, Map args, ExportContext exportContext) {
		return transformArguments(className, args,
				(value, argumentProcessor) -> argumentProcessor.processArgumentForExport(value, exportContext));
	}

	@Override
	public Map transformArgumentsForImport(String className, Map args, ImportContext importContext) {
		return transformArguments(className, args,
				(value, argumentProcessor) -> argumentProcessor.processArgumentForImport(value, importContext));
	}

	/**
	 * Implement this method to describe the syntax of transition participant arguments.
	 * 
	 * @see {@link #condition(String)}, {@link #validator(String)}, {@link #postFunction(String)}.
	 */
	protected abstract void describeArguments();

	/**
	 * This method will be invoked when an exception is caught during processing of an argument. The default implementation is to log an
	 * error - in this case the original value will be preserved.
	 *
	 * @param className
	 *            the fully qualified class name of the currently exported workflow transition participant.
	 * @param argumentName
	 *            the name of the argument that failed to export.
	 * @param t
	 *            throwable when an object is not found.
	 */
	protected void handleError(String className, String argumentName, Throwable t) {
		log.error("Failed to transform argument with name " + argumentName + " belonging to participant with class name " + className + "!",
				t);
	}

	/**
	 * This method will be invoked for each argument that has not been described in {@link #describeArguments()}. The default behavior is to
	 * return the same value.
	 * 
	 * @param className
	 *            the fully qualified class name of the currently exported workflow transition participant.
	 * @param argName
	 *            the name of the argument.
	 * @param argValue
	 *            the raw value of the argument.
	 * @param exportContext
	 *            the context of the export operation.
	 * @return the transformed value of the argument.
	 */
	protected String transformUnhandledArgumentForExport(String className, String argName, String argValue, ExportContext exportContext) {
		// default behavior is to return the same argument value
		return argValue;
	}

	/**
	 * This method will be invoked for each argument that has not been described in {@link #describeArguments()}. The default behavior is to
	 * return the same value.
	 * 
	 * @param className
	 *            the fully qualified class name of the currently imported workflow transition participant.
	 * @param argName
	 *            the name of the argument.
	 * @param argValue
	 *            the value of the argument.
	 * @param importContext
	 *            the context of the import operation.
	 * @return the transformed value of the argument that will be effectively stored for the corresponding transition participant.
	 */
	protected String transformUnhandledArgumentForImport(String className, String argName, String argValue, ImportContext importContext) {
		// default behavior is to return the same argument value
		return argValue;
	}

	/**
	 * Describes the syntax of the different arguments of a condition.
	 * 
	 * @param className
	 *            the fully qualified class name of the condition.
	 * @return the descriptor which can be used to further describe the arguments.
	 */
	protected final ArgumentContainerDescriptor condition(String className) {
		return getOrCreateArgumentDescriptor(className);
	}

	/**
	 * Describes the syntax of the different arguments of a validator.
	 * 
	 * @param className
	 *            the fully qualified class name of the validator.
	 * @return the descriptor which can be used to further describe the arguments.
	 */
	protected final ArgumentContainerDescriptor validator(String className) {
		return getOrCreateArgumentDescriptor(className);
	}

	/**
	 * Describes the syntax of the different arguments of a post-function.
	 * 
	 * @param className
	 *            the fully qualified class name of the post-function.
	 * @return the descriptor which can be used to further describe the arguments.
	 */
	protected final ArgumentContainerDescriptor postFunction(String className) {
		return getOrCreateArgumentDescriptor(className);
	}

	private ArgumentContainerDescriptor getOrCreateArgumentDescriptor(String className) {
		ArgumentContainerDescriptor argumentContainerDescriptor = argumentContainerDescriptorsMap.get(className);
		if (argumentContainerDescriptor == null) {
			argumentContainerDescriptor = new ArgumentContainerDescriptorImpl();
			argumentContainerDescriptorsMap.put(className, argumentContainerDescriptor);
		}

		return argumentContainerDescriptor;
	}

	private Map transformArguments(String className, Map args,
			ArgumentProcessorInvoker argumentProcessorInvoker) {
		Map transformedArgs = new LinkedHashMap<>();

		for (Entry entry : args.entrySet()) {
			try {
				ArgumentProcessor argumentProcessor = createArgumentHandler(className, entry.getKey());
				String transformedValue = argumentProcessorInvoker.invoke(entry.getValue(), argumentProcessor);

				transformedArgs.put(entry.getKey(), transformedValue);
			} catch (Throwable t) {
				handleError(className, entry.getKey(), t);
				transformedArgs.put(entry.getKey(), entry.getValue());
			}
		}

		return transformedArgs;

	}

	private ArgumentProcessor createArgumentHandler(String className, String argName) {
		ArgumentContainerDescriptor argumentContainerDescriptor = argumentContainerDescriptorsMap.get(className);
		if (argumentContainerDescriptor != null) {
			Optional> argumentDescriptorOptional = ((ArgumentContainerDescriptorImpl) argumentContainerDescriptor)
					.getArgumentDescriptor(argName);
			if (argumentDescriptorOptional.isPresent()) {
				return argumentProcessorFactory.createProcessor(argumentDescriptorOptional.get());
			}
		}

		return new DefaultArgumentProcessor(className, argName);
	}

	private interface ArgumentProcessorInvoker {
		String invoke(String argValue, ArgumentProcessor argumentProcessor);
	}

	private final class DefaultArgumentProcessor implements ArgumentProcessor {

		private final String className;
		private final String argName;

		private DefaultArgumentProcessor(String className, String argName) {
			this.className = className;
			this.argName = argName;
		}

		@Override
		public String processArgumentForExport(String value, ExportContext exportContext) {
			return transformUnhandledArgumentForExport(className, argName, value, exportContext);
		}

		@Override
		public String processArgumentForImport(String value, ImportContext importContext) {
			return transformUnhandledArgumentForImport(className, argName, value, importContext);
		}

	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy