/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.processor; import static reactor.core.publisher.Flux.error; import static reactor.core.publisher.Flux.from; import static reactor.core.publisher.Flux.just; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.Event.Builder; import org.mule.runtime.core.api.construct.FlowConstruct; import org.mule.runtime.core.api.processor.InterceptingMessageProcessor; import org.mule.runtime.core.api.processor.Processor; import org.mule.runtime.core.api.routing.filter.FilterUnacceptedException; import org.mule.runtime.core.config.i18n.CoreMessages; import org.mule.runtime.core.exception.MessagingException; import org.reactivestreams.Publisher; /** * Abstract {@link InterceptingMessageProcessor} that can be easily be extended and used for filtering message flow through a * {@link Processor} chain. The default behaviour when the filter is not accepted is to return the request event. */ public abstract class AbstractFilteringMessageProcessor extends AbstractInterceptingMessageProcessor { /** * Throw a FilterUnacceptedException when a message is rejected by the filter? */ protected boolean throwOnUnaccepted = false; protected boolean onUnacceptedFlowConstruct; /** * The <code>MessageProcessor</code> that should be used to handle messages that are not accepted by the filter. */ protected Processor unacceptedMessageProcessor; @Override public Event process(Event event) throws MuleException { boolean accepted; Builder builder = Event.builder(event); try { accepted = accept(event, builder); } catch (Exception ex) { throw filterFailureException(builder.build(), ex); } if (accepted) { return processNext(builder.build()); } else { return handleUnaccepted(builder.build()); } } @Override public Publisher<Event> apply(Publisher<Event> publisher) { // Optimize to only use concatMap is unaccepted processor is configured. if (unacceptedMessageProcessor == null) { return from(publisher).<Event>handle((event, sink) -> { Builder builder = Event.builder(event); boolean accepted; try { accepted = accept(event, builder); } catch (Exception ex) { sink.error(filterFailureException(builder.build(), ex)); return; } if (accepted) { sink.next(builder.build()); } else { if (isThrowOnUnaccepted()) { sink.error(filterUnacceptedException(builder.build())); } else { event.getContext().success(); } } }).transform(applyNext()); } else { return from(publisher).concatMap(event -> { Builder builder = Event.builder(event); try { if (accept(event, builder)) { return just(event).transform(applyNext()); } else { return just(event).transform(unacceptedMessageProcessor); } } catch (Exception ex) { return error(filterFailureException(builder.build(), ex)); } }); } } protected abstract boolean accept(Event event, Event.Builder builder); protected Event handleUnaccepted(Event event) throws MuleException { if (unacceptedMessageProcessor != null) { return unacceptedMessageProcessor.process(event); } else if (isThrowOnUnaccepted()) { throw filterUnacceptedException(event); } else { return null; } } protected MessagingException filterFailureException(Event event, Exception ex) { return new MessagingException(event, ex, this); } protected MuleException filterUnacceptedException(Event event) { return new FilterUnacceptedException(CoreMessages.messageRejectedByFilter()); } public Processor getUnacceptedMessageProcessor() { return unacceptedMessageProcessor; } public void setUnacceptedMessageProcessor(Processor unacceptedMessageProcessor) { this.unacceptedMessageProcessor = unacceptedMessageProcessor; if (unacceptedMessageProcessor instanceof FlowConstruct) { onUnacceptedFlowConstruct = true; } } public boolean isThrowOnUnaccepted() { return throwOnUnaccepted; } public void setThrowOnUnaccepted(boolean throwOnUnaccepted) { this.throwOnUnaccepted = throwOnUnaccepted; } }