org.opensaml.profile.action.impl.EncodeMessage Maven / Gradle / Ivy
/*
* 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.profile.action.impl;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.Constraint;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.encoder.MessageEncoder;
import org.opensaml.messaging.encoder.MessageEncodingException;
import org.opensaml.messaging.handler.MessageHandler;
import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.profile.action.AbstractProfileAction;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.action.MessageEncoderFactory;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Action that encodes an outbound response from the outbound {@link MessageContext}.
*
* The {@link MessageEncoderFactory} is used to obtain a new {@link MessageEncoder} to
* use, and the encoder is destroyed upon completion.
*
*
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_MSG_CTX}
* @event {@link EventIds#UNABLE_TO_ENCODE}
*
* @post If ProfileRequestContext.getOutboundMessageContext() != null, it will be injected and encoded.
*/
public class EncodeMessage extends AbstractProfileAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(EncodeMessage.class);
/** The factory to use to obtain an encoder. */
@NonnullAfterInit private MessageEncoderFactory encoderFactory;
/**
* An optional {@link MessageHandler} instance to be invoked after
* {@link MessageEncoder#prepareContext()} and prior to {@link MessageEncoder#encode()}.
*/
@Nullable private MessageHandler messageHandler;
/** The outbound MessageContext to encode. */
@Nullable private MessageContext msgContext;
/**
* Set the encoder factory to use.
*
* @param factory factory to use
*/
public void setMessageEncoderFactory(@Nonnull final MessageEncoderFactory factory) {
encoderFactory = Constraint.isNotNull(factory, "MessageEncoderFactory cannot be null");
}
/**
* The supplied {@link MessageHandler} will be invoked on the {@link MessageContext} after
* {@link MessageEncoder#prepareContext()}, and prior to invoking {@link MessageEncoder#encode()}.
* Its use is optional and primarily used for transport/binding-specific message handling,
* as opposed to more generalized message handling operations which would typically be invoked
* earlier than this action. For more details see {@link MessageEncoder}.
*
* @param handler a message handler
*/
public void setMessageHandler(@Nullable final MessageHandler handler) {
messageHandler = handler;
}
/** {@inheritDoc} */
@Override
protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
if (encoderFactory == null) {
throw new ComponentInitializationException("MessageEncoderFactory cannot be null");
}
}
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
msgContext = profileRequestContext.getOutboundMessageContext();
if (msgContext == null) {
log.debug("{} Outbound message context was null", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
return false;
}
return super.doPreExecute(profileRequestContext);
}
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final MessageEncoder encoder = encoderFactory.getMessageEncoder(profileRequestContext);
if (encoder == null) {
log.error("{} Unable to locate an outbound message encoder", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.UNABLE_TO_ENCODE);
return;
}
try {
log.debug("{} Encoding outbound response using message encoder of type {} for this response",
getLogPrefix(), encoder.getClass().getName());
if (!encoder.isInitialized()) {
log.debug("{} Encoder was not initialized, injecting MessageContext and initializing", getLogPrefix());
encoder.setMessageContext(msgContext);
encoder.initialize();
} else {
log.debug("{} Encoder was already initialized, skipping MessageContext injection and init",
getLogPrefix());
}
encoder.prepareContext();
if (messageHandler != null) {
log.debug("{} Invoking message handler of type {} for this response", getLogPrefix(),
messageHandler.getClass().getName());
messageHandler.invoke(msgContext);
}
encoder.encode();
log.debug("{} Outbound message encoded from a message of type {}", getLogPrefix(),
msgContext.getMessage().getClass().getName());
} catch (final MessageEncodingException | ComponentInitializationException | MessageHandlerException e) {
log.error("{} Unable to encode outbound response", getLogPrefix(), e);
ActionSupport.buildEvent(profileRequestContext, EventIds.UNABLE_TO_ENCODE);
} finally {
// TODO: do we want to destroy the encoder here?
encoder.destroy();
}
}
}