1616 */
1717package com .helger .phase4 .hredelivery ;
1818
19+ import java .nio .charset .StandardCharsets ;
1920import java .security .cert .X509Certificate ;
2021import java .time .OffsetDateTime ;
2122import java .util .function .BiFunction ;
4647import com .helger .peppolid .IParticipantIdentifier ;
4748import com .helger .peppolid .IProcessIdentifier ;
4849import com .helger .phase4 .CAS4Version ;
50+ import com .helger .phase4 .client .AS4ClientSentMessage ;
4951import com .helger .phase4 .ebms3header .Ebms3Error ;
5052import com .helger .phase4 .ebms3header .Ebms3SignalMessage ;
5153import com .helger .phase4 .marshaller .Ebms3SignalMessageMarshaller ;
@@ -101,6 +103,7 @@ public class Phase4HREdeliverySendingReport
101103 private OffsetDateTime m_aAS4SendingDT ;
102104
103105 // AS4 response details
106+ private AS4ClientSentMessage <byte []> m_aRawHttpResponse ;
104107 private EAS4UserMessageSendResult m_eAS4SendingResult ;
105108 private Exception m_aAS4SendingException ;
106109 private Ebms3SignalMessage m_aAS4ReceivedSignalMsg ;
@@ -579,60 +582,37 @@ public void setAS4SendingDT (@Nullable final OffsetDateTime a)
579582 }
580583
581584 /**
582- * @return The synchronously received AS4 Signal Message from C3. May be <code>null</code>.
583- * @since 4.2.0
585+ * @return The raw HTTP response message received from the other side. This is only emitted in
586+ * case of non-success. May be <code>null</code>.
587+ * @since 4.2.3
584588 */
585589 @ Nullable
586- public Ebms3SignalMessage getAS4ReceivedSignalMsg ()
590+ public AS4ClientSentMessage < byte []> getRawHttpResponse ()
587591 {
588- return m_aAS4ReceivedSignalMsg ;
592+ return m_aRawHttpResponse ;
589593 }
590594
591595 /**
592- * @return The list of AS4 EBMS errors received from C3. May be <code>null </code> or empty .
593- * @since 4.2.0
596+ * @return <code>true</code> if a raw response is present, <code>false </code> if not .
597+ * @since 4.2.3
594598 */
595- @ Nullable
596- @ ReturnsMutableObject
597- public ICommonsList <Ebms3Error > getAS4ReceivedErrors ()
598- {
599- return m_aAS4ResponseErrors ;
600- }
601-
602- public boolean hasAS4ReceivedSignalMsg ()
599+ public boolean hasRawHttpResponse ()
603600 {
604- return m_aAS4ReceivedSignalMsg != null ;
605- }
606-
607- public boolean hasAS4ResponseErrors ()
608- {
609- return m_aAS4ResponseErrors != null && m_aAS4ResponseErrors .isNotEmpty ();
601+ return m_aRawHttpResponse != null ;
610602 }
611603
612604 /**
613- * Remember the synchronously received AS4 Signal Message from C3.
605+ * Set the raw HTTP response message received from the other side. This is only emitted in case of
606+ * non-success.
614607 *
615- * @param a
616- * The parsed AS4 Signal Message. May be <code>null</code>.
608+ * @param aRawHttpResponse
609+ * The raw response to use. May be <code>null</code> to explicit state that it should not
610+ * be part of the sending report.
611+ * @since 4.2.3
617612 */
618- public void setAS4ReceivedSignalMsg (@ Nullable final Ebms3SignalMessage a )
613+ public void setRawHttpResponse (@ Nullable final AS4ClientSentMessage < byte []> aRawHttpResponse )
619614 {
620- m_aAS4ReceivedSignalMsg = a ;
621- if (a != null )
622- {
623- if (a .hasErrorEntries ())
624- {
625- m_aAS4ResponseErrors = new CommonsArrayList <> (a .getError ());
626- m_bAS4ResponseError = true ;
627- }
628- else
629- m_bAS4ResponseError = false ;
630- }
631- else
632- {
633- m_aAS4ResponseErrors = null ;
634- m_bAS4ResponseError = false ;
635- }
615+ m_aRawHttpResponse = aRawHttpResponse ;
636616 }
637617
638618 /**
@@ -650,6 +630,11 @@ public boolean hasAS4SendingResult ()
650630 return m_eAS4SendingResult != null ;
651631 }
652632
633+ public boolean hasUnsuccessfulAS4SendingResult ()
634+ {
635+ return m_eAS4SendingResult != null && m_eAS4SendingResult .isFailure ();
636+ }
637+
653638 /**
654639 * Remember the overall AS4 sending result.
655640 *
@@ -687,6 +672,63 @@ public void setAS4SendingException (@Nullable final Exception e)
687672 m_aAS4SendingException = e ;
688673 }
689674
675+ /**
676+ * @return The synchronously received AS4 Signal Message from C3. May be <code>null</code>.
677+ * @since 4.2.0
678+ */
679+ @ Nullable
680+ public Ebms3SignalMessage getAS4ReceivedSignalMsg ()
681+ {
682+ return m_aAS4ReceivedSignalMsg ;
683+ }
684+
685+ /**
686+ * @return The list of AS4 EBMS errors received from C3. May be <code>null</code> or empty.
687+ * @since 4.2.0
688+ */
689+ @ Nullable
690+ @ ReturnsMutableObject
691+ public ICommonsList <Ebms3Error > getAS4ReceivedErrors ()
692+ {
693+ return m_aAS4ResponseErrors ;
694+ }
695+
696+ public boolean hasAS4ReceivedSignalMsg ()
697+ {
698+ return m_aAS4ReceivedSignalMsg != null ;
699+ }
700+
701+ public boolean hasAS4ResponseErrors ()
702+ {
703+ return m_aAS4ResponseErrors != null && m_aAS4ResponseErrors .isNotEmpty ();
704+ }
705+
706+ /**
707+ * Remember the synchronously received AS4 Signal Message from C3.
708+ *
709+ * @param a
710+ * The parsed AS4 Signal Message. May be <code>null</code>.
711+ */
712+ public void setAS4ReceivedSignalMsg (@ Nullable final Ebms3SignalMessage a )
713+ {
714+ m_aAS4ReceivedSignalMsg = a ;
715+ if (a != null )
716+ {
717+ if (a .hasErrorEntries ())
718+ {
719+ m_aAS4ResponseErrors = new CommonsArrayList <> (a .getError ());
720+ m_bAS4ResponseError = true ;
721+ }
722+ else
723+ m_bAS4ResponseError = false ;
724+ }
725+ else
726+ {
727+ m_aAS4ResponseErrors = null ;
728+ m_bAS4ResponseError = false ;
729+ }
730+ }
731+
690732 /**
691733 * @return The overall duration it took to perform the lookup and sending process.
692734 * @since 4.2.0
@@ -809,6 +851,47 @@ public IJsonObject getAsJsonObject ()
809851 if (hasAS4SendingDT ())
810852 aJson .add ("as4SendingDateTime" , PDTWebDateHelper .getAsStringXSD (m_aAS4SendingDT ));
811853
854+ // Don't render Raw response in case of success, as the Signal Message is contained anyway
855+ if (hasRawHttpResponse () && hasUnsuccessfulAS4SendingResult ())
856+ {
857+ final IJsonObject aRawHttpResponse = new JsonObject ();
858+ if (m_aRawHttpResponse .hasResponseStatusLine ())
859+ aRawHttpResponse .add ("statusLine" , m_aRawHttpResponse .getResponseStatusLine ().toString ());
860+
861+ {
862+ final IJsonArray aHeaders = new JsonArray ();
863+ for (final var aHeader : m_aRawHttpResponse .getResponseHeaders ())
864+ {
865+ final IJsonObject aJsonHeader = new JsonObject ().add ("name" , aHeader .getKey ());
866+ switch (aHeader .getValue ().size ())
867+ {
868+ case 0 :
869+ break ;
870+ case 1 :
871+ aJsonHeader .add ("value" , aHeader .getValue ().getFirstOrNull ());
872+ break ;
873+ default :
874+ aJsonHeader .add ("value" , new JsonArray ().addAll (aHeader .getValue ()));
875+ break ;
876+ }
877+ aHeaders .add (aJsonHeader );
878+ }
879+ aRawHttpResponse .add ("headers" , aHeaders );
880+ }
881+
882+ if (m_aRawHttpResponse .hasResponseContent ())
883+ {
884+ // Does not clone
885+ final byte [] aBytes = m_aRawHttpResponse .getResponseContent ();
886+ aRawHttpResponse .add ("contentLength" , aBytes .length );
887+ aRawHttpResponse .add ("content" , new String (aBytes , StandardCharsets .UTF_8 ));
888+ }
889+ else
890+ aRawHttpResponse .add ("contentLength" , 0 );
891+
892+ aJson .add ("rawHttpResponse" , aRawHttpResponse );
893+ }
894+
812895 if (hasAS4SendingResult ())
813896 aJson .add ("sendingResult" , m_eAS4SendingResult .name ());
814897 if (hasAS4SendingException ())
@@ -940,6 +1023,37 @@ public IMicroElement getAsMicroElement (@Nullable final String sNamespaceURI,
9401023 ret .addElementNS (sNamespaceURI , "AS4SendingDateTime" )
9411024 .addText (PDTWebDateHelper .getAsStringXSD (m_aAS4SendingDT ));
9421025
1026+ // Don't render Raw response in case of success, as the Signal Message is contained anyway
1027+ if (hasRawHttpResponse () && hasUnsuccessfulAS4SendingResult ())
1028+ {
1029+ final IMicroElement aRawHttpResponse = ret .addElementNS (sNamespaceURI , "RawHttpResponse" );
1030+ if (m_aRawHttpResponse .hasResponseStatusLine ())
1031+ aRawHttpResponse .addElementNS (sNamespaceURI , "StatusLine" )
1032+ .addText (m_aRawHttpResponse .getResponseStatusLine ().toString ());
1033+
1034+ {
1035+ final IMicroElement aHeaders = aRawHttpResponse .addElementNS (sNamespaceURI , "Headers" );
1036+ for (final var aHeader : m_aRawHttpResponse .getResponseHeaders ())
1037+ {
1038+ final IMicroElement aHeaderEl = aHeaders .addElementNS (sNamespaceURI , "Header" );
1039+ aHeaderEl .setAttribute ("name" , aHeader .getKey ());
1040+
1041+ for (final String sValue : aHeader .getValue ())
1042+ aHeaderEl .addElementNS (sNamespaceURI , "Value" ).addText (sValue );
1043+ }
1044+ }
1045+
1046+ if (m_aRawHttpResponse .hasResponseContent ())
1047+ {
1048+ // Does not clone
1049+ final byte [] aBytes = m_aRawHttpResponse .getResponseContent ();
1050+ aRawHttpResponse .addElementNS (sNamespaceURI , "ContentLength" ).addText (aBytes .length );
1051+ aRawHttpResponse .addElementNS (sNamespaceURI , "Content" ).addText (new String (aBytes , StandardCharsets .UTF_8 ));
1052+ }
1053+ else
1054+ aRawHttpResponse .addElementNS (sNamespaceURI , "ContentLength" ).addText (0 );
1055+ }
1056+
9431057 if (hasAS4SendingResult ())
9441058 ret .addElementNS (sNamespaceURI , "AS4SendingResult" ).addText (m_eAS4SendingResult .name ());
9451059 if (hasAS4SendingException ())
0 commit comments