com.botronsoft.cmj.spitools.workflow.AbstractWorkflowParticipantHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of configuration-manager-spi-tools Show documentation
Show all versions of configuration-manager-spi-tools Show documentation
Configuration Manager Service Provider Interface Tools
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