use of com.helger.phase4.servlet.spi.IAS4ServletMessageProcessorSPI in project phase4 by phax.
the class AS4RequestHandler method _invokeSPIsForResponse.
private void _invokeSPIsForResponse(@Nonnull final IAS4MessageState aState, @Nullable final IAS4ResponseFactory aResponseFactory, @Nullable final HttpEntity aHttpEntity, @Nonnull final IMimeType aMimeType, @Nonnull @Nonempty final String sResponseMessageID) {
// Get response payload as byte array for multiple processing by the SPIs
final boolean bResponsePayloadIsAvailable = aResponseFactory != null;
byte[] aResponsePayload = null;
if (aResponseFactory != null) {
final HttpEntity aRealHttpEntity = aHttpEntity != null ? aHttpEntity : aResponseFactory.getHttpEntityForSending(aMimeType);
if (aRealHttpEntity.isRepeatable()) {
int nContentLength = (int) aRealHttpEntity.getContentLength();
if (nContentLength < 0)
nContentLength = 16 * CGlobal.BYTES_PER_KILOBYTE;
try (final NonBlockingByteArrayOutputStream aBAOS = new NonBlockingByteArrayOutputStream(nContentLength)) {
aRealHttpEntity.writeTo(aBAOS);
aResponsePayload = aBAOS.getBufferOrCopy();
} catch (final IOException ex) {
LOGGER.error("Error dumping response entity", ex);
}
} else
LOGGER.warn("Response entity is not repeatable and therefore not read for SPIs");
} else
LOGGER.info("No response factory present");
// Get all processors
final ICommonsList<IAS4ServletMessageProcessorSPI> aAllProcessors = m_aProcessorSupplier.get();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to invoke the following " + aAllProcessors.size() + " SPIs on message ID '" + aState.getMessageID() + "' and response message ID '" + sResponseMessageID + ": " + aAllProcessors);
for (final IAS4ServletMessageProcessorSPI aProcessor : aAllProcessors) if (aProcessor != null)
try {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Invoking AS4 message processor " + aProcessor + " for response");
aProcessor.processAS4ResponseMessage(m_aMessageMetadata, aState, sResponseMessageID, aResponsePayload, bResponsePayloadIsAvailable);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Finished invoking AS4 message processor " + aProcessor + " for response");
} catch (final RuntimeException ex) {
// Re-throw
throw ex;
} catch (final Exception ex) {
throw new IllegalStateException("Error invoking AS4 message processor " + aProcessor + " for response", ex);
}
}
use of com.helger.phase4.servlet.spi.IAS4ServletMessageProcessorSPI in project phase4 by phax.
the class AS4RequestHandler method _invokeSPIsForIncoming.
/**
* Invoke custom SPI message processors
*
* @param aHttpHeaders
* The received HTTP headers. Never <code>null</code>.
* @param aEbmsUserMessage
* Current user message. Either this OR signal message must be
* non-<code>null</code>.
* @param aEbmsSignalMessage
* The signal message to use. Either this OR user message must be
* non-<code>null</code>.
* @param aPayloadNode
* Optional SOAP body payload (only if direct SOAP msg, not for MIME).
* May be <code>null</code>.
* @param aDecryptedAttachments
* Original attachments from source message. May be <code>null</code>.
* @param aPMode
* PMode to be used - may be <code>null</code> for Receipt messages.
* @param aState
* The current state. Never <code>null</<code></code>.
* @param aErrorMessagesTarget
* The list of error messages to be filled if something goes wrong.
* Never <code>null</code>.
* @param aResponseAttachmentsTarget
* The list of attachments to be added to the response. Never
* <code>null</code>.
* @param aSPIResult
* The result object to be filled. May not be <code>null</code>.
*/
private void _invokeSPIsForIncoming(@Nonnull final HttpHeaderMap aHttpHeaders, @Nullable final Ebms3UserMessage aEbmsUserMessage, @Nullable final Ebms3SignalMessage aEbmsSignalMessage, @Nullable final Node aPayloadNode, @Nullable final ICommonsList<WSS4JAttachment> aDecryptedAttachments, @Nullable final IPMode aPMode, @Nonnull final IAS4MessageState aState, @Nonnull final ICommonsList<Ebms3Error> aErrorMessagesTarget, @Nonnull final ICommonsList<WSS4JAttachment> aResponseAttachmentsTarget, @Nonnull final SPIInvocationResult aSPIResult) {
ValueEnforcer.isTrue(aEbmsUserMessage != null || aEbmsSignalMessage != null, "User OR Signal Message must be present");
ValueEnforcer.isFalse(aEbmsUserMessage != null && aEbmsSignalMessage != null, "Only one of User OR Signal Message may be present");
final boolean bIsUserMessage = aEbmsUserMessage != null;
final String sMessageID = bIsUserMessage ? aEbmsUserMessage.getMessageInfo().getMessageId() : aEbmsSignalMessage.getMessageInfo().getMessageId();
// Get all processors
final ICommonsList<IAS4ServletMessageProcessorSPI> aAllProcessors = m_aProcessorSupplier.get();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to invoke the following " + aAllProcessors.size() + " SPIs on message ID '" + sMessageID + "': " + aAllProcessors);
if (aAllProcessors.isEmpty())
LOGGER.error("No IAS4ServletMessageProcessorSPI is available to process an incoming message");
// Invoke ALL non-null SPIs
for (final IAS4ServletMessageProcessorSPI aProcessor : aAllProcessors) if (aProcessor != null)
try {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Invoking AS4 message processor " + aProcessor + " for incoming message");
// Main processing
final AS4MessageProcessorResult aResult;
final ICommonsList<Ebms3Error> aProcessingErrorMessages = new CommonsArrayList<>();
if (bIsUserMessage) {
aResult = aProcessor.processAS4UserMessage(m_aMessageMetadata, aHttpHeaders, aEbmsUserMessage, aPMode, aPayloadNode, aDecryptedAttachments, aState, aProcessingErrorMessages);
} else {
aResult = aProcessor.processAS4SignalMessage(m_aMessageMetadata, aHttpHeaders, aEbmsSignalMessage, aPMode, aState, aProcessingErrorMessages);
}
// Result returned?
if (aResult == null)
throw new IllegalStateException("No result object present from AS4 message processor " + aProcessor + " - this is a programming error");
if (aProcessingErrorMessages.isNotEmpty() || aResult.isFailure()) {
if (aProcessingErrorMessages.isNotEmpty()) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("AS4 message processor " + aProcessor + " had processing errors - breaking. Details: " + aProcessingErrorMessages);
if (aResult.isSuccess())
LOGGER.warn("Processing errors are present but success was returned by a previous AS4 message processor " + aProcessor + " - considering the whole processing to be failed instead");
aErrorMessagesTarget.addAll(aProcessingErrorMessages);
}
if (aResult.isFailure() && aResult.hasErrorMessage()) {
aErrorMessagesTarget.add(EEbmsError.EBMS_OTHER.getAsEbms3Error(m_aLocale, sMessageID, "Invoked AS4 message processor SPI " + aProcessor + " on '" + sMessageID + "' returned a failure: " + aResult.getErrorMessage()));
}
// Stop processing
return;
}
// SPI invocation returned success and no errors
{
final String sAsyncResultURL = aResult.getAsyncResponseURL();
if (StringHelper.hasText(sAsyncResultURL)) {
// URL present
if (aSPIResult.hasAsyncResponseURL()) {
// A second processor returned a response URL - not allowed
final String sErrorMsg = "Invoked AS4 message processor SPI " + aProcessor + " on '" + sMessageID + "' failed: the previous processor already returned an async response URL; it is not possible to handle two URLs. Please check your SPI implementations.";
LOGGER.error(sErrorMsg);
aErrorMessagesTarget.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsEbms3Error(m_aLocale, sMessageID, sErrorMsg));
// Stop processing
return;
}
aSPIResult.setAsyncResponseURL(sAsyncResultURL);
LOGGER.info("Using asynchronous response URL '" + sAsyncResultURL + "' for message ID '" + sMessageID + "'");
}
}
if (bIsUserMessage) {
// User message specific processing result handling
// empty
} else {
// Signal message specific processing result handling
assert aResult instanceof AS4SignalMessageProcessorResult;
if (aEbmsSignalMessage.getReceipt() == null) {
final Ebms3UserMessage aPullReturnUserMsg = ((AS4SignalMessageProcessorResult) aResult).getPullReturnUserMessage();
if (aSPIResult.hasPullReturnUserMsg()) {
// to the pullrequest initiator
if (aPullReturnUserMsg != null) {
final String sErrorMsg = "Invoked AS4 message processor SPI " + aProcessor + " on '" + sMessageID + "' failed: the previous processor already returned a usermessage; it is not possible to return two usermessage. Please check your SPI implementations.";
LOGGER.warn(sErrorMsg);
aErrorMessagesTarget.add(EEbmsError.EBMS_VALUE_INCONSISTENT.getAsEbms3Error(m_aLocale, sMessageID, sErrorMsg));
// Stop processing
return;
}
} else {
// Initial return user msg
if (aPullReturnUserMsg == null) {
// No message contained in the MPC
final String sErrorMsg = "Invoked AS4 message processor SPI " + aProcessor + " on '" + sMessageID + "' returned a failure: no UserMessage contained in the MPC";
LOGGER.warn(sErrorMsg);
aErrorMessagesTarget.add(EEbmsError.EBMS_EMPTY_MESSAGE_PARTITION_CHANNEL.getAsEbms3Error(m_aLocale, sMessageID, sErrorMsg));
// Stop processing
return;
}
// We have something :)
aSPIResult.setPullReturnUserMsg(aPullReturnUserMsg);
}
} else {
if (LOGGER.isDebugEnabled())
LOGGER.debug("The AS4 EbmsSignalMessage already has a Receipt");
}
}
// Add response attachments, payloads
aResult.addAllAttachmentsTo(aResponseAttachmentsTarget);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Successfully invoked AS4 message processor " + aProcessor);
} catch (final AS4DecompressException ex) {
LOGGER.error("Failed to decompress AS4 payload", ex);
// Hack for invalid GZip content from WSS4JAttachment.getSourceStream
aErrorMessagesTarget.add(EEbmsError.EBMS_DECOMPRESSION_FAILURE.getAsEbms3Error(m_aLocale, sMessageID));
return;
} catch (final RuntimeException ex) {
// Re-throw
throw ex;
} catch (final Exception ex) {
throw new IllegalStateException("Error processing incoming AS4 message with processor " + aProcessor, ex);
}
// Remember success
aSPIResult.setSuccess(true);
}
use of com.helger.phase4.servlet.spi.IAS4ServletMessageProcessorSPI in project phase4 by phax.
the class AS4DumpReader method decryptAS4In.
/**
* Utility method to decrypt dumped .as4in message late.<br>
* Note: this method was mainly created for internal use and does not win the
* prize for the most sexy piece of software in the world ;-)
*
* @param aAS4InData
* The byte array with the dumped data.
* @param aCF
* The Crypto factory to be used. This crypto factory must use use the
* private key that can be used to decrypt this particular message. May
* not be <code>null</code>.
* @param aHttpHeaderConsumer
* An optional HTTP Header map consumer. May be <code>null</code>.
* @param aDecryptedConsumer
* The consumer for the decrypted payload - whatever that is :). May
* not be <code>null</code>.
* @throws WSSecurityException
* In case of error
* @throws Phase4Exception
* In case of error
* @throws IOException
* In case of error
* @throws MessagingException
* In case of error
*/
public static void decryptAS4In(@Nonnull final byte[] aAS4InData, final IAS4CryptoFactory aCF, @Nullable final Consumer<HttpHeaderMap> aHttpHeaderConsumer, @Nonnull final Consumer<byte[]> aDecryptedConsumer) throws WSSecurityException, Phase4Exception, IOException, MessagingException {
final HttpHeaderMap hm = new HttpHeaderMap();
int nHttpStart = 0;
int nHttpEnd = -1;
boolean bLastWasCR = false;
for (int i = 0; i < aAS4InData.length; ++i) {
final byte b = aAS4InData[i];
if (b == '\n') {
if (bLastWasCR) {
nHttpEnd = i;
break;
}
bLastWasCR = true;
final String sLine = new String(aAS4InData, nHttpStart, i - nHttpStart, StandardCharsets.ISO_8859_1);
final String[] aParts = StringHelper.getExplodedArray(':', sLine, 2);
hm.addHeader(aParts[0].trim(), aParts[1].trim());
nHttpStart = i + 1;
} else {
if (b != '\r')
bLastWasCR = false;
}
}
if (aHttpHeaderConsumer != null)
aHttpHeaderConsumer.accept(hm);
LOGGER.info("Now at byte " + nHttpEnd + " having " + hm.getCount() + " HTTP headers");
WebScopeManager.onGlobalBegin(MockServletContext.create());
try (final WebScoped w = new WebScoped();
final AS4RequestHandler rh = new AS4RequestHandler(aCF, DefaultPModeResolver.DEFAULT_PMODE_RESOLVER, IAS4IncomingAttachmentFactory.DEFAULT_INSTANCE, new AS4IncomingMessageMetadata(EAS4MessageMode.REQUEST))) {
final IAS4ServletMessageProcessorSPI aSPI = new IAS4ServletMessageProcessorSPI() {
public AS4MessageProcessorResult processAS4UserMessage(final IAS4IncomingMessageMetadata aMessageMetadata, final HttpHeaderMap aHttpHeaders, final Ebms3UserMessage aUserMessage, final IPMode aPMode, final Node aPayload, final ICommonsList<WSS4JAttachment> aIncomingAttachments, final IAS4MessageState aState, final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
try {
final byte[] aDecryptedBytes = StreamHelper.getAllBytes(aIncomingAttachments.getFirst().getInputStreamProvider());
aDecryptedConsumer.accept(aDecryptedBytes);
LOGGER.info("Handled decrypted payload with " + aDecryptedBytes.length + " bytes");
return AS4MessageProcessorResult.createSuccess();
} catch (final Exception ex) {
throw new IllegalStateException(ex);
}
}
public AS4SignalMessageProcessorResult processAS4SignalMessage(final IAS4IncomingMessageMetadata aMessageMetadata, final HttpHeaderMap aHttpHeaders, final Ebms3SignalMessage aSignalMessage, final IPMode aPMode, final IAS4MessageState aState, final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
LOGGER.error("Unexpected signal msg");
return AS4SignalMessageProcessorResult.createSuccess();
}
};
rh.setProcessorSupplier(() -> new CommonsArrayList<>(aSPI));
rh.handleRequest(new NonBlockingByteArrayInputStream(aAS4InData, nHttpEnd, aAS4InData.length - nHttpEnd), hm, new IAS4ResponseAbstraction() {
public void setStatus(final int nStatusCode) {
}
public void setMimeType(final IMimeType aMimeType) {
}
public void setContent(final HttpHeaderMap aHeaderMap, final IHasInputStream aHasIS) {
}
public void setContent(final byte[] aResultBytes, final Charset aCharset) {
}
});
} finally {
WebScopeManager.onGlobalEnd();
}
}
Aggregations