Skip to content

Commit

Permalink
Merge pull request #247 from robinsongarciax/master
Browse files Browse the repository at this point in the history
example of dbnalliance client
  • Loading branch information
phax authored Jul 29, 2024
2 parents d73aa5e + 3a30442 commit b14fa65
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 19 deletions.
21 changes: 19 additions & 2 deletions phase4-dbnalliance-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>

</licenses>
<dependencies>
<dependency>
<groupId>com.helger.phase4</groupId>
Expand All @@ -48,6 +48,23 @@
<groupId>com.helger.phase4</groupId>
<artifactId>phase4-dynamic-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-xhe</artifactId>
<version>4.0.1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.helger.peppol</groupId>
<artifactId>peppol-commons</artifactId>
<version>${peppol-commons.version}</version>
</dependency>
<dependency>
<groupId>com.helger.peppol</groupId>
<artifactId>dbnalliance-xhe</artifactId>
<version>9.4.1-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.helger.phase4</groupId>
<artifactId>phase4-profile-dbnalliance</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,35 @@

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.datetime.XMLOffsetDateTime;
import com.helger.commons.state.ESuccess;
import com.helger.peppol.smp.ESMPTransportProfile;
import com.helger.peppol.utils.PeppolCertificateHelper;
import com.helger.peppol.xhe.DBNAlliancePayload;
import com.helger.peppol.xhe.DBNAllianceXHEData;
import com.helger.peppol.xhe.write.DBNAllianceXHEDocumentWriter;
import com.helger.peppolid.IDocumentTypeIdentifier;
import com.helger.peppolid.IParticipantIdentifier;
import com.helger.peppolid.IProcessIdentifier;
import com.helger.peppolid.factory.BDXR2IdentifierFactory;
import com.helger.phase4.CAS4;
import com.helger.phase4.attachment.AS4OutgoingAttachment;
import com.helger.phase4.crypto.ICryptoSessionKeyProvider;
import com.helger.phase4.dynamicdiscovery.AS4EndpointDetailProviderBDXR2;
import com.helger.phase4.dynamicdiscovery.AS4EndpointDetailProviderConstant;
import com.helger.phase4.dynamicdiscovery.IAS4EndpointDetailProvider;
import com.helger.phase4.mgr.MetaAS4Manager;
import com.helger.phase4.profile.dbnalliance.DBNAlliancePMode;
import com.helger.phase4.sender.AbstractAS4UserMessageBuilderMIMEPayload;
import com.helger.phase4.sender.IAS4SendingDateTimeConsumer;
import com.helger.phase4.util.Phase4Exception;
import com.helger.smpclient.bdxr2.IBDXR2ServiceMetadataProvider;
import com.helger.xhe.v10.CXHE10;
import com.helger.xhe.v10.XHE10Marshaller;
import com.helger.xhe.v10.XHE10XHEType;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.w3c.dom.Element;

/**
* This class contains all the specifics to send AS4 messages with the
Expand All @@ -56,10 +70,46 @@
@Immutable
public final class Phase4DBNAllianceSender
{
public static final BDXR2IdentifierFactory IF = BDXR2IdentifierFactory.INSTANCE;
private static final Logger LOGGER = LoggerFactory.getLogger (Phase4DBNAllianceSender.class);

private Phase4DBNAllianceSender ()
{}

@Nullable
private static XHE10XHEType _createXHE (@Nonnull final IParticipantIdentifier aSenderID,
@Nonnull final IParticipantIdentifier aReceiverID,
@Nonnull final IDocumentTypeIdentifier aDocTypeID,
@Nonnull final IProcessIdentifier aProcID,
@Nonnull final Element aPayloadElement,
final boolean bClonePayloadElement
)
{
final DBNAllianceXHEData aData = new DBNAllianceXHEData (IF);
aData.setFromParty (aSenderID.getScheme (), aSenderID.getValue ());
aData.setToParty (aReceiverID.getScheme (), aReceiverID.getValue ());
aData.setID (UUID.randomUUID ().toString ());
aData.setCreationDateAndTime (MetaAS4Manager.getTimestampMgr ().getCurrentXMLDateTime ());

final DBNAlliancePayload aPayload = new DBNAlliancePayload (IF);
aPayload.setCustomizationID (null, aDocTypeID.getValue ());
aPayload.setProfileID (aProcID.getScheme (), aProcID.getValue ());

// Not cloning the payload element is for saving memory only (if it can be
// ensured, the source payload element is not altered externally of course)
if (bClonePayloadElement)
aPayload.setPayloadContent (aPayloadElement);
else
aPayload.setPayloadContentNoClone (aPayloadElement);

aData.addPayload(aPayload);

// check with logging
if (!aData.areAllFieldsSet (true))
throw new IllegalArgumentException ("The DBNAlliance XHE data is incomplete. See logs for details.");

return DBNAllianceXHEDocumentWriter.createExchangeHeaderEnvelope (aData);
}

/**
* @return Create a new Builder for AS4 messages if the XHE payload is
Expand All @@ -83,6 +133,7 @@ public abstract static class AbstractDBNAllianceUserMessageBuilder <IMPLTYPE ext
AbstractAS4UserMessageBuilderMIMEPayload <IMPLTYPE>
{
// C4
protected IParticipantIdentifier m_aSenderID;
protected IParticipantIdentifier m_aReceiverID;
protected IDocumentTypeIdentifier m_aDocTypeID;
protected IProcessIdentifier m_aProcessID;
Expand Down Expand Up @@ -114,6 +165,24 @@ protected AbstractDBNAllianceUserMessageBuilder ()
throw new IllegalStateException ("Failed to init AS4 Client builder", ex);
}
}

/**
* Set the sender participant ID of the message. The participant ID must
* be provided prior to sending.
*
* @param aSenderID
* The sender participant ID. May not be <code>null</code>.
* @return this for chaining
*/
@Nonnull
public final IMPLTYPE senderParticipantID (@Nonnull final IParticipantIdentifier aSenderID)
{
ValueEnforcer.notNull (aSenderID, "SenderID");
if (m_aSenderID != null)
LOGGER.warn ("An existing SenderParticipantID is overridden");
m_aSenderID = aSenderID;
return thisAsT ();
}

/**
* Set the receiver participant ID of the message. The participant ID must
Expand Down Expand Up @@ -226,7 +295,9 @@ public final IMPLTYPE endpointDetailProvider (@Nonnull final IAS4EndpointDetailP
@Nonnull
public final IMPLTYPE smpClient (@Nonnull final IBDXR2ServiceMetadataProvider aSMPClient)
{
return endpointDetailProvider (new AS4EndpointDetailProviderBDXR2 (aSMPClient));
final AS4EndpointDetailProviderBDXR2 aEndpointDetailProvider = new AS4EndpointDetailProviderBDXR2 (aSMPClient);
aEndpointDetailProvider.setTransportProfile (ESMPTransportProfile.TRANSPORT_PROFILE_DBNA_AS4_v1);
return endpointDetailProvider (aEndpointDetailProvider);
}

/**
Expand Down Expand Up @@ -420,7 +491,83 @@ protected void customizeBeforeSending () throws Phase4Exception
public static class DBNAllianceUserMessageBuilder extends
AbstractDBNAllianceUserMessageBuilder <DBNAllianceUserMessageBuilder>
{

private Element m_aPayloadElement;

public DBNAllianceUserMessageBuilder ()
{}

/**
* Set the payload element to be used, if it is available as a parsed DOM
* element. Internally the DOM element will be cloned before sending it out.
* If this method is called, it overwrites any other explicitly set payload.
*
* @param aPayloadElement
* The payload element to be used. They payload element MUST have a
* namespace URI. May not be <code>null</code>.
* @return this for chaining
*/
@Nonnull
public DBNAllianceUserMessageBuilder payload (@Nonnull final Element aPayloadElement)
{
ValueEnforcer.notNull (aPayloadElement, "Payload");
ValueEnforcer.notNull (aPayloadElement.getNamespaceURI (), "Payload.NamespaceURI");
m_aPayloadElement = aPayloadElement;
return this;
}

@Override
protected ESuccess finishFields () throws Phase4Exception
{
// Ensure a DOM element is present
final Element aPayloadElement;
final boolean bClonePayloadElement;
if (m_aPayloadElement != null)
{
// Already provided as a DOM element
aPayloadElement = m_aPayloadElement;
bClonePayloadElement = true;
}
else
throw new IllegalStateException ("Unexpected - element are not present");

// Consistency check
if (CXHE10.NAMESPACE_URI_XHE.equals(aPayloadElement.getNamespaceURI ()))
throw new Phase4DBNAllianceException ("You cannot set a Exchange Header Envelope as the payload for the regular builder. The XHE is created automatically inside of this builder.");

// Optional payload validation
// _validatePayload (aPayloadElement, m_aVESRegistry, m_aVESID, m_aValidationResultHandler);

// Perform SMP lookup
if (super.finishFields ().isFailure ())
return ESuccess.FAILURE;

// Created SBDH
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("Start creating SBDH for AS4 message");

final XHE10XHEType aXHE = _createXHE (m_aSenderID,
m_aReceiverID,
m_aDocTypeID,
m_aProcessID,
aPayloadElement,
bClonePayloadElement);
if (aXHE == null)
{
// A log message was already provided
return ESuccess.FAILURE;
}

final byte [] aXHEBytes = new XHE10Marshaller ().getAsBytes (aXHE);

// Now we have the main payload
payload (AS4OutgoingAttachment.builder ()
.data (aXHEBytes)
.compressionGZIP ()
.mimeTypeXML ()
.charset (StandardCharsets.UTF_8));

return ESuccess.SUCCESS;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,24 @@
*/
package com.helger.phase4.dbnalliance;

import com.helger.peppolid.bdxr.smp2.participant.BDXR2ParticipantIdentifier;
import com.helger.peppolid.factory.SimpleIdentifierFactory;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.phase4.attachment.AS4OutgoingAttachment;
import com.helger.phase4.dump.AS4DumpManager;
import com.helger.phase4.dump.AS4IncomingDumperFileBased;
import com.helger.phase4.dump.AS4OutgoingDumperFileBased;
import com.helger.phase4.sender.AbstractAS4UserMessageBuilder.ESimpleUserMessageSendResult;
import com.helger.servlet.mock.MockServletContext;
import com.helger.smpclient.bdxr2.BDXR2ClientReadOnly;
import com.helger.smpclient.dbna.EDBNASML;
import com.helger.smpclient.url.DBNAURLProviderSMP;
import com.helger.web.scope.mgr.WebScopeManager;
import com.helger.xml.serialize.read.DOMReader;
import org.w3c.dom.Element;

public class MainPhase4DBNAllianceSenderExample
{
Expand All @@ -47,23 +51,26 @@ public static void main (final String [] args)
try
{
// Read XML payload to send
final byte [] aPayloadBytes = Files.readAllBytes (new File ("src/test/resources/external/examples/base-example.xml").toPath ());
if (aPayloadBytes == null)
final Element aPayloadElement = DOMReader.readXMLDOM (new File ("src/test/resources/external/examples/base-example.xml"))
.getDocumentElement ();
if (aPayloadElement == null)
throw new IllegalStateException ("Failed to read file to be send");

// Start configuring here
// Start configuring here
final BDXR2ParticipantIdentifier aReceiver = Phase4DBNAllianceSender.IF.createParticipantIdentifier ("us:ein", "365060483");
BDXR2ClientReadOnly aSMPClient = new BDXR2ClientReadOnly (DBNAURLProviderSMP.INSTANCE.getSMPURIOfParticipant (aReceiver,
EDBNASML.TEST.getZoneName()));
aSMPClient.setVerifySignature (false);

final ESimpleUserMessageSendResult eResult;
eResult = Phase4DBNAllianceSender.builder ()
.fromPartyID ("AS4-Sender")
.toPartyID ("AS4-Receiver")
.endpointURL ("https://receiver.example.org/dbna/as4")
.service ("AS4-Service")
.action ("AS4-Action")
.payload (AS4OutgoingAttachment.builder ()
.data (aPayloadBytes)
.compressionGZIP ()
.mimeTypeXML ()
.charset (StandardCharsets.UTF_8))
.documentTypeID (SimpleIdentifierFactory.INSTANCE.createDocumentTypeIdentifier ("bdx-docid-qns", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##DBNAlliance-1.0-data-Core"))
.processID (Phase4DBNAllianceSender.IF.createProcessIdentifier(null, "bdx:noprocess"))
.senderParticipantID (Phase4DBNAllianceSender.IF.createParticipantIdentifier ("us:ein", "365060483"))
.receiverParticipantID (aReceiver)
.fromPartyID("365060483")
.payload (aPayloadElement)
.smpClient (aSMPClient)
.sendMessageAndCheckForReceipt ();
LOGGER.info ("DBNAlliance send result: " + eResult);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# Copyright (C) 2015-2024 Philip Helger (www.helger.com)
# philip[at]helger[dot]com
#
# Licensed 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.
#

global.debug=true
global.production=false
global.nostartupinfo=true

org.apache.wss4j.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.wss4j.crypto.merlin.keystore.type=pkcs12
org.apache.wss4j.crypto.merlin.keystore.file=test-ap-2023.p12
org.apache.wss4j.crypto.merlin.keystore.password=peppol
org.apache.wss4j.crypto.merlin.keystore.alias=cert
org.apache.wss4j.crypto.merlin.keystore.private.password=peppol

org.apache.wss4j.crypto.merlin.load.cacerts=false
#org.apache.wss4j.crypto.merlin.truststore.provider=
org.apache.wss4j.crypto.merlin.truststore.type=jks
org.apache.wss4j.crypto.merlin.truststore.file=truststore/dbnalliance-truststore.jks
org.apache.wss4j.crypto.merlin.truststore.password=dbnalliance

phase4.dump.path = generated/

0 comments on commit b14fa65

Please sign in to comment.