org.opensaml.messaging.handler.AbstractMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.opensaml.messaging.handler.AbstractMessageHandler.java

Source

/*
 * Licensed to the University Corporation for Advanced Internet Development, 
 * Inc. (UCAID) under one or more contributor license agreements.  See the 
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID licenses this file to You under the Apache 
 * License, Version 2.0 (the "License"); you may not use this file except in 
 * compliance with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.opensaml.messaging.handler;

import javax.annotation.Nonnull;

import net.shibboleth.utilities.java.support.annotation.Prototype;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;

import org.opensaml.messaging.context.MessageContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

/**
 * A base abstract implementation of {@link MessageHandler}.
 * 
 * @param <MessageType> the type of message being handled
 */
@Prototype
public abstract class AbstractMessageHandler<MessageType> extends AbstractInitializableComponent
        implements MessageHandler<MessageType> {

    /** Logger. */
    private Logger log = LoggerFactory.getLogger(AbstractMessageHandler.class);

    /** Condition dictating whether to run or not. */
    @Nonnull
    private Predicate<MessageContext> activationCondition;

    /** Constructor. */
    public AbstractMessageHandler() {
        activationCondition = Predicates.alwaysTrue();
    }

    /**
     * Get activation condition indicating whether the handler should be invoked.
     * 
     * <p>
     * Defaults to a predicate which always returns <code>true</code>.
     * </p>
     * 
     * @return  activation condition
     */
    @Nonnull
    public Predicate<MessageContext> getActivationCondition() {
        return activationCondition;
    }

    /**
     * Set activation condition indicating whether the handler should be invoked.
     * 
     * <p>
     * Defaults to a predicate which always returns <code>true</code>.
     * </p>
     * 
     * @param condition predicate to apply
     */
    public void setActivationCondition(@Nonnull final Predicate<MessageContext> condition) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);

        activationCondition = Constraint.isNotNull(condition, "Predicate cannot be null");
    }

    /** {@inheritDoc} */
    @Override
    public void invoke(@Nonnull final MessageContext<MessageType> messageContext) throws MessageHandlerException {
        Constraint.isNotNull(messageContext, "Message context cannot be null");

        // The try/catch logic is designed to suppress a checked exception raised by
        // the doInvoke step by any unchecked errors in the doPostInvoke method.
        // The original exception is logged, and can be accessed from the suppressing
        // error object using the Java 7 API.

        if (doPreInvoke(messageContext)) {
            try {
                doInvoke(messageContext);
            } catch (MessageHandlerException e) {
                try {
                    doPostInvoke(messageContext, e);
                } catch (Throwable t) {
                    log.warn("{} Unchecked exception/error thrown by doPostInvoke, "
                            + "superseding a MessageHandlerException ", getLogPrefix(), e);
                    t.addSuppressed(e);
                    throw t;
                }
                throw e;
            } catch (Throwable t) {
                try {
                    doPostInvoke(messageContext);
                } catch (Throwable t2) {
                    log.warn("{} Unchecked exception/error thrown by doPostInvoke, "
                            + "superseding an unchecked exception/error ", getLogPrefix(), t);
                    t2.addSuppressed(t);
                    throw t2;
                }
                throw t;
            }

            doPostInvoke(messageContext);
        }
    }

    /**
     * Called prior to execution, handlers may override this method to perform pre-processing for a request.
     * 
     * <p>
     * The default impl applies the {@link Predicate} set via the {@link #setActivationCondition(Predicate)}.
     * </p>
     * 
     * <p>
     * If false is returned, execution will not proceed.
     * </p>
     * 
     * <p>
     * Subclasses which override this method should generally invoke the super version of this method first,
     * so that the activation condition will be applied up front, and immediately return false if the super version
     * returns false.  This avoids unnecessary execution of the remaining pre-invocation code if the handler
     * ultimately will not execute.
     * </p>
     * 
     * @param messageContext the message context on which to invoke the handler
     * @return true iff execution should proceed
     * 
     * @throws MessageHandlerException if there is a problem executing the handler pre-routine
     */
    protected boolean doPreInvoke(@Nonnull final MessageContext<MessageType> messageContext)
            throws MessageHandlerException {
        if (activationCondition.apply(messageContext)) {
            log.debug("{} Activation condition for handler returned true", getLogPrefix());
            return true;
        } else {
            log.debug("{} Activation condition for handler returned false", getLogPrefix());
            return false;
        }
    }

    /**
     * Performs the handler logic.
     * 
     * @param messageContext the message context on which to invoke the handler
     * @throws MessageHandlerException if there is an error invoking the handler on the message context
     */
    protected abstract void doInvoke(@Nonnull final MessageContext<MessageType> messageContext)
            throws MessageHandlerException;

    /**
     * Called after execution, handlers may override this method to perform post-processing for a request.
     * 
     * <p>
     * Handlers must not "fail" during this step. This method will not be called if {@link #doPreInvoke} fails, but is
     * called if an exception is raised by {@link #doInvoke}.
     * </p>
     * 
     * @param messageContext the message context on which the handler was invoked
     */
    protected void doPostInvoke(@Nonnull final MessageContext<MessageType> messageContext) {
    }

    /**
     * Called after execution, handlers may override this method to perform post-processing for a request.
     * 
     * <p>
     * Handlers must not "fail" during this step. This method will not be called if {@link #doPreInvoke} fails, but is
     * called if an exception is raised by {@link #doInvoke}.
     * </p>
     * 
     * <p>
     * This version of the method will be called if an exception is raised during execution of the handler. The overall
     * handler result will be to raise this error, so any errors inadvertently raised by this method will be logged and
     * superseded.
     * </p>
     * 
     * <p>
     * The default implementation simply calls the error-less version of this method.
     * </p>
     * 
     * @param messageContext the message context on which the handler was invoked
     * @param e an exception raised by the {@link #doInvoke} method
     */
    protected void doPostInvoke(@Nonnull final MessageContext<MessageType> messageContext,
            @Nonnull final Exception e) {
        doPostInvoke(messageContext);
    }

    /**
     * Return a prefix for logging messages for this component.
     * 
     * @return a string for insertion at the beginning of any log messages
     */
    @Nonnull
    @NotEmpty
    protected String getLogPrefix() {
        return "Message Handler: ";
    }

}