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

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

There is a newer version: 3.22.0
Show newest version
package org.mapfish.print.processor;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.locationtech.jts.util.Assert;
import org.mapfish.print.ExceptionUtils;
import org.mapfish.print.output.Values;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;

/**
 * Represents one node in the Processor dependency graph ({@link ProcessorDependencyGraph}).
 * 

* * @param Same as {@link Processor} In parameter * @param Same as {@link Processor} Out parameter */ public final class ProcessorGraphNode { private static final Logger LOGGER = LoggerFactory.getLogger(ProcessorGraphNode.class); private final Processor processor; /** * The list of processors that get values from the output of this processor. */ private final Set> dependencies = new HashSet<>(); /** * The list of processors on which this processor gets its values from. */ private final Set requirements = new HashSet<>(); private final MetricRegistry metricRegistry; /** * Constructor. * * @param processor The processor associated with this node. * @param metricRegistry registry for timing the execution time of the processor. */ public ProcessorGraphNode( @Nonnull final Processor processor, @Nonnull final MetricRegistry metricRegistry) { this.processor = processor; this.metricRegistry = metricRegistry; } public Processor getProcessor() { return this.processor; } /** * Add a dependency to this node. * * @param node the dependency to add. */ public void addDependency(final ProcessorGraphNode node) { Assert.isTrue(node != this, "A processor can't depends on himself"); this.dependencies.add(node); node.addRequirement(this); } private void addRequirement(final ProcessorGraphNode node) { this.requirements.add(node); } protected Set getRequirements() { return this.requirements; } protected Set> getDependencies() { return this.dependencies; } /** * Returns true if the node has requirements, that is there are other nodes that should be run first. */ public boolean hasRequirements() { return !this.requirements.isEmpty(); } /** * Create a ForkJoinTask for running in a fork join pool. * * @param execContext the execution context, used for tracking certain aspects of the execution. * @return a task ready to be submitted to a fork join pool. */ public Optional> createTask( @Nonnull final ProcessorExecutionContext execContext) { if (!execContext.tryStart(this)) { return Optional.empty(); } else { return Optional.of(new ProcessorNodeForkJoinTask<>(this, execContext)); } } /** * Get the output mapper from processor. */ @Nonnull public BiMap getOutputMapper() { final BiMap outputMapper = this.processor.getOutputMapperBiMap(); if (outputMapper == null) { return HashBiMap.create(); } return outputMapper; } /** * Return input mapper from processor. */ @Nonnull public BiMap getInputMapper() { final BiMap inputMapper = this.processor.getInputMapperBiMap(); if (inputMapper == null) { return HashBiMap.create(); } return inputMapper; } /** * Create a string representing this node. * * @param builder the builder to add the string to. * @param indent the number of steps of indent for this node * @param parent the parent node */ public void toString(final StringBuilder builder, final int indent, final String parent) { this.processor.toString(builder, indent, parent); for (ProcessorGraphNode dependency: this.dependencies) { dependency.toString(builder, indent + 1, this.processor.toString()); } } @Override public String toString() { StringBuilder builder = new StringBuilder(); toString(builder, 0, "?"); return builder.toString(); } public String getName() { return this.processor.toString(); } /** * Create a set containing all the processor at the current node and the entire subgraph. */ public Set> getAllProcessors() { IdentityHashMap, Void> all = new IdentityHashMap<>(); all.put(this.getProcessor(), null); for (ProcessorGraphNode dependency: this.dependencies) { for (Processor p: dependency.getAllProcessors()) { all.put(p, null); } } return all.keySet(); } /** * A ForkJoinTask that will run the processor and all of its dependencies. * * @param the type of the input parameter * @param the type of the output parameter */ public static final class ProcessorNodeForkJoinTask extends RecursiveTask { private final ProcessorExecutionContext execContext; private final ProcessorGraphNode node; private ProcessorNodeForkJoinTask( final ProcessorGraphNode node, final ProcessorExecutionContext execContext) { this.node = node; this.execContext = execContext; } @Override protected Values compute() { return this.execContext.getContext().mdcContext(() -> { final Values values = this.execContext.getValues(); final Processor process = this.node.processor; final MetricRegistry registry = this.node.metricRegistry; final String name = String.format("%s.compute.%s", ProcessorGraphNode.class.getName(), process.getClass().getName()); Timer.Context timerContext = registry.timer(name).time(); try { final In inputParameter = ProcessorUtils.populateInputParameter(process, values); Out output; try { LOGGER.debug("Executing process: {}", process); output = process.execute(inputParameter, this.execContext.getContext()); LOGGER.debug("Succeeded in executing process: {}", process); } catch (Exception e) { // the processor is already canceled, so we don't care if something fails this.execContext.getContext().stopIfCanceled(); LOGGER.info("Error while executing process: {}", process); registry.counter(name + ".error").inc(); throw ExceptionUtils.getRuntimeException(e); } if (output != null) { ProcessorUtils.writeProcessorOutputToValues(output, process, values); } } finally { this.execContext.finished(this.node); final long processorTime = TimeUnit.MILLISECONDS.convert( timerContext.stop(), TimeUnit.NANOSECONDS); LOGGER.info("Time taken to run processor: '{}' was {} ms", process.getClass(), processorTime); } this.execContext.getContext().stopIfCanceled(); ProcessorDependencyGraph.tryExecuteNodes(this.node.dependencies, this.execContext, true); return values; }); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy