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

org.mapfish.print.processor.AbstractProcessor Maven / Gradle / Ivy

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 org.slf4j.MDC;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.function.Supplier;
import javax.annotation.Nonnull;

/**
 * Basic functionality of a processor.  Mostly utility methods.
 *
 * @param  A Java bean input parameter object of the execute method. Object is populated from the
 *         {@link org.mapfish.print.output.Values} object.
 * @param  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 implements Processor {
    private final BiMap inputMapper = HashBiMap.create();
    private final BiMap outputMapper = HashBiMap.create();

    private final Class 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 outputType) {
        this.outputType = outputType;
    }

    @Override
    public final Class getOutputType() {
        return this.outputType;
    }

    @Override
    @Nonnull
    public final BiMap 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;
    }

    @Override
    public final String getInputPrefix() {
        return this.inputPrefix == null ? this.prefix : this.inputPrefix;
    }

    /**
     * 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 getOutputPrefix() {
        return this.outputPrefix == null ? this.prefix : this.outputPrefix;
    }

    /**
     * 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 void toString(final StringBuilder builder, final int indent, final String parent) {
        int spaces = (indent) * 2;
        for (int i = 0; i < spaces; i++) {
            builder.append(' ');
        }
        builder.append("\"");
        builder.append(parent.replace("\"", "\\\""));
        builder.append("\" -> \"");
        builder.append(toString().replace("\"", "\\\""));
        builder.append("\";\n");
    }

    /**
     * The input mapper.
     *
     * @param inputMapper the values.
     */
    public final void setInputMapper(@Nonnull final Map inputMapper) {
        this.inputMapper.putAll(inputMapper);
    }

    @Nonnull
    @Override
    public final BiMap getOutputMapperBiMap() {
        return this.outputMapper;
    }

    /**
     * The output mapper.
     *
     * @param outputMapper the values.
     */
    public final void setOutputMapper(@Nonnull final Map outputMapper) {
        this.outputMapper.putAll(outputMapper);
    }

    @Override
    public final void validate(final List errors, final Configuration configuration) {
        final In inputParameter = createInputParameter();
        final Set 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 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(
            List validationErrors, Configuration configuration);

    // CHECKSTYLE:OFF
    @Override
    public String toString() {
        String result = getClass().getSimpleName();
        final String inPrefix = getInputPrefix();
        if (inPrefix != null) {
            result += " in=" + inPrefix;
        }
        final String outPrefix = getOutputPrefix();
        if (outPrefix != null) {
            result += " out=" + outPrefix;
        }
        return result;
    }
    // CHECKSTYLE:ON

    /**
     * Default implementation of {@link ExecutionContext}.
     */
    public static final class Context implements ExecutionContext {
        private final String jobId;
        private volatile boolean canceled = false;
        private ExecutionStats stats = new ExecutionStats();

        /**
         * @param jobId The job ID.
         */
        public Context(final String jobId) {
            this.jobId = jobId;
        }


        /**
         * Sets the canceled flag.
         */
        public void cancel() {
            this.canceled = true;
        }

        @Override
        public void stopIfCanceled() {
            if (this.canceled) {
                throw new CancellationException("task was canceled");
            }
        }

        @Override
        public ExecutionStats getStats() {
            return this.stats;
        }

        @Override
        public String getJobId() {
            return this.jobId;
        }

        @Override
        public  T mdcContext(final Supplier action) {
            this.stopIfCanceled();
            final String prev = MDC.get(MDC_JOB_ID_KEY);
            boolean changed = prev == null || (jobId != null && jobId.equals(prev));
            if (changed) {
                MDC.put(MDC_JOB_ID_KEY, this.jobId);
            }
            try {
                return action.get();
            } finally {
                if (changed) {
                    if (prev != null) {
                        MDC.put(MDC_JOB_ID_KEY, prev);
                    } else {
                        MDC.remove(MDC_JOB_ID_KEY);
                    }
                }
            }
        }

        @Override
        public  T mdcContextEx(final Callable action) throws Exception {
            this.stopIfCanceled();
            final String prev = MDC.get(MDC_JOB_ID_KEY);
            boolean mdcChanged = prev == null || jobId.equals(prev);
            if (mdcChanged) {
                MDC.put(MDC_JOB_ID_KEY, this.jobId);
            }
            try {
                return action.call();
            } finally {
                if (mdcChanged) {
                    if (prev != null) {
                        MDC.put(MDC_JOB_ID_KEY, prev);
                    } else {
                        MDC.remove(MDC_JOB_ID_KEY);
                    }
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy