use of com.helger.phase4.messaging.IAS4IncomingMessageMetadata in project phase4 by phax.
the class Phase4PeppolWebAppListener method _initAS4.
private static void _initAS4() {
AS4ServerInitializer.initAS4Server();
// Store the incoming file as is
AS4DumpManager.setIncomingDumper(new AS4IncomingDumperFileBased((aMessageMetadata, aHttpHeaderMap) -> StorageHelper.getStorageFile(aMessageMetadata, ".as4in")) {
@Override
public void onEndRequest(@Nonnull final IAS4IncomingMessageMetadata aMessageMetadata) {
// Save the metadata also to a file
final File aFile = StorageHelper.getStorageFile(aMessageMetadata, ".metadata");
if (SimpleFileIO.writeFile(aFile, AS4MessagingHelper.getIncomingMetadataAsJson(aMessageMetadata).getAsJsonString(JsonWriterSettings.DEFAULT_SETTINGS_FORMATTED), StandardCharsets.UTF_8).isFailure())
LOGGER.error("Failed to write metadata to '" + aFile.getAbsolutePath() + "'");
else
LOGGER.info("Wrote metadata to '" + aFile.getAbsolutePath() + "'");
}
});
// Store the outgoings file as well
AS4DumpManager.setOutgoingDumper(new AS4OutgoingDumperFileBased((eMsgMode, sMessageID, nTry) -> StorageHelper.getStorageFile(sMessageID, nTry, ".as4out")));
}
use of com.helger.phase4.messaging.IAS4IncomingMessageMetadata in project phase4 by phax.
the class StoringServletMessageProcessorSPI method processAS4UserMessage.
@Nonnull
public AS4MessageProcessorResult processAS4UserMessage(@Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final Ebms3UserMessage aUserMessage, @Nonnull final IPMode aPMode, @Nullable final Node aPayload, @Nullable final ICommonsList<WSS4JAttachment> aIncomingAttachments, @Nonnull final IAS4MessageState aState, @Nonnull final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
LOGGER.info("Received AS4 user message");
_dumpSoap(aMessageMetadata, aState);
// Dump all incoming attachments (but only if they are repeatable)
if (aIncomingAttachments != null) {
int nAttachmentIndex = 0;
for (final WSS4JAttachment aIncomingAttachment : aIncomingAttachments) {
if (aIncomingAttachment.isRepeatable())
_dumpIncomingAttachment(aMessageMetadata, aIncomingAttachment, nAttachmentIndex);
nAttachmentIndex++;
}
}
return AS4MessageProcessorResult.createSuccess();
}
use of com.helger.phase4.messaging.IAS4IncomingMessageMetadata in project phase4 by phax.
the class ExampleReceiveMessageProcessorSPI method processAS4UserMessage.
@Nonnull
public AS4MessageProcessorResult processAS4UserMessage(@Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final Ebms3UserMessage aUserMessage, @Nonnull final IPMode aPMode, @Nullable final Node aPayload, @Nullable final ICommonsList<WSS4JAttachment> aIncomingAttachments, @Nonnull final IAS4MessageState aState, @Nonnull final ICommonsList<Ebms3Error> aProcessingErrorMessages) {
LOGGER.info("Received AS4 user message");
_dumpSoap(aMessageMetadata, aState);
if (aIncomingAttachments != null) {
int nIndex = 1;
for (final WSS4JAttachment aIncomingAttachment : aIncomingAttachments) {
final File aFile = StorageHelper.getStorageFile(aMessageMetadata, "-" + nIndex + ".payload");
if (StreamHelper.copyInputStreamToOutputStream(aIncomingAttachment.getSourceStream(), FileHelper.getOutputStream(aFile)).isFailure())
LOGGER.error("Failed to write incoming attachment [" + nIndex + "] to '" + aFile.getAbsolutePath() + "'");
else
LOGGER.info("Wrote incoming attachment [" + nIndex + "] to '" + aFile.getAbsolutePath() + "'");
++nIndex;
}
}
return AS4MessageProcessorResult.createSuccess();
}
use of com.helger.phase4.messaging.IAS4IncomingMessageMetadata in project phase4 by phax.
the class AS4IncomingHandler method parseAS4Message.
public static void parseAS4Message(@Nonnull final IAS4IncomingAttachmentFactory aIAF, @Nonnull @WillNotClose final AS4ResourceHelper aResHelper, @Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull @WillClose final InputStream aPayloadIS, @Nonnull final HttpHeaderMap aHttpHeaders, @Nonnull final IAS4ParsedMessageCallback aCallback, @Nullable final IAS4IncomingDumper aIncomingDumper) throws Phase4Exception, IOException, MessagingException, WSSecurityException {
// Determine content type
final String sContentType = aHttpHeaders.getFirstHeaderValue(CHttpHeader.CONTENT_TYPE);
if (StringHelper.hasNoText(sContentType))
throw new Phase4Exception("Content-Type header is missing");
if (LOGGER.isDebugEnabled())
LOGGER.debug("Received Content-Type string: '" + sContentType + "'");
final IMimeType aContentType = MimeTypeParser.safeParseMimeType(sContentType);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Received Content-Type object: " + aContentType);
if (aContentType == null)
throw new Phase4Exception("Failed to parse Content-Type '" + sContentType + "'");
final IMimeType aPlainContentType = aContentType.getCopyWithoutParameters();
// Fallback to global dumper if none is provided
final IAS4IncomingDumper aRealIncomingDumper = aIncomingDumper != null ? aIncomingDumper : AS4DumpManager.getIncomingDumper();
Document aSoapDocument = null;
ESoapVersion eSoapVersion = null;
final ICommonsList<WSS4JAttachment> aIncomingAttachments = new CommonsArrayList<>();
final Wrapper<OutputStream> aDumpOSHolder = new Wrapper<>();
if (aPlainContentType.equals(AS4RequestHandler.MT_MULTIPART_RELATED)) {
// MIME message
if (LOGGER.isDebugEnabled())
LOGGER.debug("Received MIME message");
final String sBoundary = aContentType.getParameterValueWithName("boundary");
if (StringHelper.hasNoText(sBoundary))
throw new Phase4Exception("Content-Type '" + sContentType + "' misses 'boundary' parameter");
if (LOGGER.isDebugEnabled())
LOGGER.debug("MIME Boundary: '" + sBoundary + "'");
// Ensure the stream gets closed correctly
try (final InputStream aRequestIS = AS4DumpManager.getIncomingDumpAwareInputStream(aRealIncomingDumper, aPayloadIS, aMessageMetadata, aHttpHeaders, aDumpOSHolder)) {
// PARSING MIME Message via MultipartStream
final MultipartStream aMulti = new MultipartStream(aRequestIS, sBoundary.getBytes(StandardCharsets.ISO_8859_1), (MultipartProgressNotifier) null);
int nIndex = 0;
while (true) {
final boolean bHasNextPart = nIndex == 0 ? aMulti.skipPreamble() : aMulti.readBoundary();
if (!bHasNextPart)
break;
if (LOGGER.isDebugEnabled())
LOGGER.debug("Found MIME part #" + nIndex);
try (final MultipartItemInputStream aBodyPartIS = aMulti.createInputStream()) {
// Read headers AND content
final MimeBodyPart aBodyPart = new MimeBodyPart(aBodyPartIS);
if (nIndex == 0) {
// First MIME part -> SOAP document
if (LOGGER.isDebugEnabled())
LOGGER.debug("Parsing first MIME part as SOAP document");
// Read SOAP document
aSoapDocument = DOMReader.readXMLDOM(aBodyPart.getInputStream());
IMimeType aPlainPartMT = MimeTypeParser.safeParseMimeType(aBodyPart.getContentType());
if (aPlainPartMT != null)
aPlainPartMT = aPlainPartMT.getCopyWithoutParameters();
// Determine SOAP version from MIME part content type
eSoapVersion = ESoapVersion.getFromMimeTypeOrNull(aPlainPartMT);
if (eSoapVersion != null && LOGGER.isDebugEnabled())
LOGGER.debug("Determined SOAP version " + eSoapVersion + " from Content-Type");
if (eSoapVersion == null && aSoapDocument != null) {
// Determine SOAP version from the read document
eSoapVersion = ESoapVersion.getFromNamespaceURIOrNull(XMLHelper.getNamespaceURI(aSoapDocument));
if (eSoapVersion != null && LOGGER.isDebugEnabled())
LOGGER.debug("Determined SOAP version " + eSoapVersion + " from XML root element namespace URI");
}
} else {
// MIME Attachment (index is gt 0)
if (LOGGER.isDebugEnabled())
LOGGER.debug("Parsing MIME part #" + nIndex + " as attachment");
final WSS4JAttachment aAttachment = aIAF.createAttachment(aBodyPart, aResHelper);
aIncomingAttachments.add(aAttachment);
}
}
nIndex++;
}
}
if (LOGGER.isDebugEnabled())
LOGGER.debug("Read MIME message with " + aIncomingAttachments.size() + " attachment(s)");
} else {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Received plain message");
// Expect plain SOAP - read whole request to DOM
// Note: this may require a huge amount of memory for large requests
aSoapDocument = DOMReader.readXMLDOM(AS4DumpManager.getIncomingDumpAwareInputStream(aRealIncomingDumper, aPayloadIS, aMessageMetadata, aHttpHeaders, aDumpOSHolder));
if (LOGGER.isDebugEnabled())
if (aSoapDocument != null)
LOGGER.debug("Successfully parsed payload as XML");
else
LOGGER.debug("Failed to parse payload as XML");
if (aSoapDocument != null) {
// Determine SOAP version from the read document
eSoapVersion = ESoapVersion.getFromNamespaceURIOrNull(XMLHelper.getNamespaceURI(aSoapDocument));
if (eSoapVersion != null && LOGGER.isDebugEnabled())
LOGGER.debug("Determined SOAP version " + eSoapVersion + " from XML root element namespace URI");
}
if (eSoapVersion == null) {
// Determine SOAP version from content type
eSoapVersion = ESoapVersion.getFromMimeTypeOrNull(aPlainContentType);
if (eSoapVersion != null && LOGGER.isDebugEnabled())
LOGGER.debug("Determined SOAP version " + eSoapVersion + " from Content-Type");
}
}
try {
if (aSoapDocument == null) {
// We don't have a SOAP document
throw new Phase4Exception(eSoapVersion == null ? "Failed to parse incoming message!" : "Failed to parse incoming SOAP " + eSoapVersion.getVersion() + " document!");
}
if (eSoapVersion == null) {
// We're missing a SOAP version
throw new Phase4Exception("Failed to determine SOAP version of XML document!");
}
aCallback.handle(aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments);
} finally {
// Here, the incoming dump is finally ready closed and usable
if (aRealIncomingDumper != null && aDumpOSHolder.isSet())
try {
aRealIncomingDumper.onEndRequest(aMessageMetadata);
} catch (final Exception ex) {
LOGGER.error("IncomingDumper.onEndRequest failed. Dumper=" + aRealIncomingDumper + "; MessageMetadata=" + aMessageMetadata, ex);
}
}
}
use of com.helger.phase4.messaging.IAS4IncomingMessageMetadata in project phase4 by phax.
the class AS4IncomingHandler method _parseMessage.
@Nullable
private static IAS4MessageState _parseMessage(@Nonnull final IAS4CryptoFactory aCryptoFactory, @Nonnull final IPModeResolver aPModeResolver, @Nonnull final IAS4IncomingAttachmentFactory aIAF, @Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector, @Nonnull @WillNotClose final AS4ResourceHelper aResHelper, @Nullable final IPMode aSendingPMode, @Nonnull final Locale aLocale, @Nonnull final IAS4IncomingMessageMetadata aMessageMetadata, @Nonnull final HttpResponse aHttpResponse, @Nonnull final byte[] aResponsePayload, @Nullable final IAS4IncomingDumper aIncomingDumper) throws Phase4Exception {
// This wrapper will take the result
final Wrapper<IAS4MessageState> aRetWrapper = new Wrapper<>();
// Handler for the parsed message
final IAS4ParsedMessageCallback aCallback = (aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments) -> {
final ICommonsList<Ebms3Error> aErrorMessages = new CommonsArrayList<>();
// Use the sending PMode as fallback, because from the incoming
// receipt/error it is impossible to detect a PMode
final SOAPHeaderElementProcessorRegistry aRegistry = SOAPHeaderElementProcessorRegistry.createDefault(aPModeResolver, aCryptoFactory, aSendingPMode);
// Parse AS4, verify signature etc
final IAS4MessageState aState = processEbmsMessage(aResHelper, aLocale, aRegistry, aHttpHeaders, aSoapDocument, eSoapVersion, aIncomingAttachments, aAS4ProfileSelector, aErrorMessages);
if (aState.isSoapHeaderElementProcessingSuccessful()) {
// Remember the parsed signal message
aRetWrapper.set(aState);
} else {
throw new Phase4Exception("Error processing AS4 message", aState.getSoapWSS4JException());
}
};
// Create header map from response headers
final HttpHeaderMap aHttpHeaders = new HttpHeaderMap();
for (final Header aHeader : aHttpResponse.getAllHeaders()) aHttpHeaders.addHeader(aHeader.getName(), aHeader.getValue());
try (final NonBlockingByteArrayInputStream aPayloadIS = new NonBlockingByteArrayInputStream(aResponsePayload)) {
// Parse incoming message
parseAS4Message(aIAF, aResHelper, aMessageMetadata, aPayloadIS, aHttpHeaders, aCallback, aIncomingDumper);
} catch (final Phase4Exception ex) {
throw ex;
} catch (final Exception ex) {
throw new Phase4Exception("Error parsing AS4 message", ex);
}
// This one contains the result
return aRetWrapper.get();
}
Aggregations