Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example of dbnalliance client #247

Merged
merged 4 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/