package org.mapfish.print.processor;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.mapfish.print.config.Configuration;
import org.mapfish.print.config.ConfigurationException;
import org.mapfish.print.parser.ParserUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import javax.annotation.Nonnull;
/**
* Basic functionality of a processor. Mostly utility methods.
*
* @param <In> A Java bean input parameter object of the execute method. Object is populated from the
* {@link org.mapfish.print.output.Values} object.
* @param <Out> A Java bean output/return object from the execute method. properties will be put into the
* {@link org.mapfish.print.output.Values} object so other processor can access the values.
*/
public abstract class AbstractProcessor<In, Out> implements Processor<In, Out> {
private final BiMap<String, String> inputMapper = HashBiMap.create();
private final BiMap<String, String> outputMapper = HashBiMap.create();
private final Class<Out> outputType;
private String prefix;
private String inputPrefix;
private String outputPrefix;
/**
* Constructor.
*
* @param outputType the type of the output of this processor. Used to calculate processor dependencies.
*/
protected AbstractProcessor(final Class<Out> outputType) {
this.outputType = outputType;
}
@Override
public final Class<Out> getOutputType() {
return this.outputType;
}
@Override
@Nonnull
public final BiMap<String, String> getInputMapperBiMap() {
return this.inputMapper;
}
/**
* The prefix to apply to each value. This provides a simple way to make all output values have unique values.
* @param prefix the new prefix
*/
public final void setPrefix(final String prefix) {
this.prefix = prefix;
}
/**
* The prefix to apply to each input value. This provides a simple way to make all output values have unique values.
* @param inputPrefix the new prefix
*/
public final void setInputPrefix(final String inputPrefix) {
this.inputPrefix = inputPrefix;
}
@Override
public final String getInputPrefix() {
return this.inputPrefix == null ? this.prefix : this.inputPrefix;
}
/**
* The prefix to apply to each output value. This provides a simple way to make all output values have unique values.
* @param outputPrefix the new prefix
*/
public final void setOutputPrefix(final String outputPrefix) {
this.outputPrefix = outputPrefix;
}
@Override
public final String getOutputPrefix() {
return this.outputPrefix == null ? this.prefix : this.outputPrefix;
}
/**
* The input mapper.
*
* @param inputMapper the values.
*/
public final void setInputMapper(@Nonnull final Map<String, String> inputMapper) {
this.inputMapper.putAll(inputMapper);
}
@Nonnull
@Override
public final BiMap<String, String> getOutputMapperBiMap() {
return this.outputMapper;
}
/**
* The output mapper.
*
* @param outputMapper the values.
*/
public final void setOutputMapper(@Nonnull final Map<String, String> outputMapper) {
this.outputMapper.putAll(outputMapper);
}
@Override
public final void validate(final List<Throwable> errors, final Configuration configuration) {
final In inputParameter = createInputParameter();
final Set<String> allInputAttributeNames;
if (inputParameter != null) {
allInputAttributeNames = ParserUtils.getAllAttributeNames(inputParameter.getClass());
} else {
allInputAttributeNames = Collections.emptySet();
}
for (String inputAttributeName : this.inputMapper.values()) {
if (!allInputAttributeNames.contains(inputAttributeName)) {
errors.add(new ConfigurationException(inputAttributeName + " is not defined in processor '"
+ this + "'. Check for typos. Options are " + allInputAttributeNames));
}
}
Set<String> allOutputAttributeNames = ParserUtils.getAllAttributeNames(getOutputType());
for (String outputAttributeName : this.outputMapper.keySet()) {
if (!allOutputAttributeNames.contains(outputAttributeName)) {
errors.add(new ConfigurationException(outputAttributeName + " is not defined in processor " +
"'" + this + "' as an output attribute. Check for typos. Options are " +
allOutputAttributeNames));
}
}
extraValidation(errors, configuration);
}
/**
* Perform any extra validation a subclass may need to perform.
* @param validationErrors a list to add errors to so that all validation errors are reported as one.
* @param configuration the containing configuration
*/
protected abstract void extraValidation(final List<Throwable> validationErrors, final Configuration configuration);
/**
* Checks if the print was canceled and throws a
* {@link CancellationException} if so.
*
* @param context the execution context
* @throws CancellationException
*/
protected final void checkCancelState(final ExecutionContext context) {
if (context.isCanceled()) {
throw new CancellationException("task was canceled");
}
}
// CHECKSTYLE:OFF
@Override
public String toString() {
return getClass().getSimpleName();
}
// CHECKSTYLE:ON
/**
* Default implementation of {@link ExecutionContext}.
*/
public static final class Context implements ExecutionContext {
private volatile boolean canceled = false;
/**
* Sets the canceled flag.
*/
public void cancel() {
this.canceled = true;
}
@Override
public boolean isCanceled() {
return this.canceled;
}
}
}