package org.mapfish.print.processor.http; import com.google.common.collect.Lists; import org.mapfish.print.config.Configuration; import org.mapfish.print.http.MfClientHttpRequestFactory; import org.mapfish.print.output.Values; import org.mapfish.print.processor.AbstractProcessor; import org.mapfish.print.processor.ProcessorUtils; import java.util.List; import javax.annotation.Nullable; /** * <p>A processor that wraps several {@link AbstractClientHttpRequestFactoryProcessor}s.</p> * <p> * This makes it more convenient to configure multiple processors that modify * {@link org.mapfish.print.http.MfClientHttpRequestFactory} objects. *</p> * <p> * Consider the case where you need to: * </p> * <ul> * <li>Restrict allowed URIS using the !restrictUris processor</li> * <li>Forward all headers from print request to all requests using !forwardHeaders</li> * <li>Change the url using the !mapUri processor</li> * </ul> * <p> * In this case the !mapUri processor must execute before the !restrictUris processor but it is difficult to enforce this, the * inputMapping and outputMapping must be carefully designed in order to do it. The following should work but compare it with * the example below: * </p> * <pre><code> * - !mapUri * mapping: * (http)://localhost(.*) : "$1://127.0.0.1$2" * outputMapper: {clientHttpRequestFactoryProvider: clientHttpRequestFactoryMapped} * - !forwardHeaders * all: true * inputMapper: {clientHttpRequestFactoryMapped :clientHttpRequestFactoryProvider} * outputMapper: {clientHttpRequestFactoryProvider: clientHttpRequestFactoryWithHeaders} * - !restrictUris * matchers: [!localMatch {}] * inputMapper: {clientHttpRequestFactoryWithHeaders:clientHttpRequestFactoryProvider} * </code></pre> * * <p> * The recommended way to write the above configuration is as follows: * </p> * <pre><code> * - !configureHttpRequests * httpProcessors: * - !mapUri * mapping: * (http)://localhost(.*) : "$1://127.0.0.1$2" * - !forwardHeaders * all: true * - !restrictUris * matchers: [!localMatch {}] * </code></pre> * [[examples=http_processors]] */ public final class CompositeClientHttpRequestFactoryProcessor extends AbstractProcessor<CompositeClientHttpRequestFactoryProcessor.Input, Void> implements HttpProcessor<CompositeClientHttpRequestFactoryProcessor.Input> { private List<HttpProcessor> httpProcessors = Lists.newArrayList(); /** * Constructor. */ protected CompositeClientHttpRequestFactoryProcessor() { super(Void.class); } /** * Sets all the http processors that will executed by this processor. * * @param httpProcessors the sub processors */ public void setHttpProcessors(final List<HttpProcessor> httpProcessors) { this.httpProcessors = httpProcessors; } @SuppressWarnings("unchecked") @Override public MfClientHttpRequestFactory createFactoryWrapper( final Input input, final MfClientHttpRequestFactory requestFactory) { MfClientHttpRequestFactory finalRequestFactory = requestFactory; // apply the parts in reverse so that the last part is the inner most wrapper (will be last to be called) for (int i = this.httpProcessors.size() - 1; i > -1; i--) { final HttpProcessor processor = this.httpProcessors.get(i); Object populatedInput = ProcessorUtils.populateInputParameter(processor, input.values); finalRequestFactory = processor.createFactoryWrapper(populatedInput, finalRequestFactory); } return finalRequestFactory; } @Override protected void extraValidation( final List<Throwable> validationErrors, final Configuration configuration) { if (this.httpProcessors.isEmpty()) { validationErrors.add(new IllegalStateException("There are no composite elements for this " + "processor")); } else { for (Object part : this.httpProcessors) { if (!(part instanceof HttpProcessor)) { validationErrors.add(new IllegalStateException("One of the parts of " + getClass() .getSimpleName() + " is not a " + HttpProcessor.class.getSimpleName())); } } } } @Nullable @Override public Input createInputParameter() { return new Input(); } @Nullable @Override public Void execute( final Input values, final ExecutionContext context) throws Exception { values.clientHttpRequestFactoryProvider.set(createFactoryWrapper( values, values.clientHttpRequestFactoryProvider.get())); return null; } /** * The input. */ public class Input extends ClientHttpFactoryProcessorParam { /** * The values. */ public Values values; } }