diff --git a/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClient.java b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClient.java index 626b533a..c2d0f22f 100644 --- a/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClient.java +++ b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClient.java @@ -19,21 +19,38 @@ package network.oxalis.vefa.peppol.lookup; -import network.oxalis.vefa.peppol.common.api.PotentiallySigned; -import network.oxalis.vefa.peppol.common.code.Service; -import network.oxalis.vefa.peppol.common.lang.EndpointNotFoundException; -import network.oxalis.vefa.peppol.common.model.*; -import network.oxalis.vefa.peppol.lookup.api.*; -import network.oxalis.vefa.peppol.security.api.CertificateValidator; -import network.oxalis.vefa.peppol.security.lang.PeppolSecurityException; - import java.io.FileNotFoundException; import java.net.URI; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; +import network.oxalis.vefa.peppol.common.api.PotentiallySigned; +import network.oxalis.vefa.peppol.common.code.Service; +import network.oxalis.vefa.peppol.common.lang.EndpointNotFoundException; +import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier; +import network.oxalis.vefa.peppol.common.model.Endpoint; +import network.oxalis.vefa.peppol.common.model.Header; +import network.oxalis.vefa.peppol.common.model.ParticipantIdentifier; +import network.oxalis.vefa.peppol.common.model.ProcessIdentifier; +import network.oxalis.vefa.peppol.common.model.Redirect; +import network.oxalis.vefa.peppol.common.model.ServiceInformation; +import network.oxalis.vefa.peppol.common.model.ServiceMetadata; +import network.oxalis.vefa.peppol.common.model.ServiceReference; +import network.oxalis.vefa.peppol.common.model.Signed; +import network.oxalis.vefa.peppol.common.model.TransportProfile; +import network.oxalis.vefa.peppol.lookup.api.FetcherResponse; +import network.oxalis.vefa.peppol.lookup.api.LookupException; +import network.oxalis.vefa.peppol.lookup.api.MetadataFetcher; +import network.oxalis.vefa.peppol.lookup.api.MetadataLocator; +import network.oxalis.vefa.peppol.lookup.api.MetadataProvider; +import network.oxalis.vefa.peppol.lookup.api.MetadataReader; +import network.oxalis.vefa.peppol.mode.Mode; +import network.oxalis.vefa.peppol.security.api.CertificateValidator; +import network.oxalis.vefa.peppol.security.lang.PeppolSecurityException; + public class LookupClient { private final MetadataLocator locator; @@ -42,6 +59,19 @@ public class LookupClient { private final MetadataReader reader; private final CertificateValidator validator; + public LookupClient(Mode mode, Map objectStorage) { + LookupClientBuilder builder = (LookupClientBuilder) objectStorage.get(LookupClientBuilder.class.getName()); + if (builder != null) { + this.locator = builder.metadataLocator; + this.provider = builder.metadataProvider; + this.fetcher = builder.metadataFetcher; + this.reader = builder.metadataReader; + this.validator = builder.certificateValidator; + } else { + throw new IllegalArgumentException("Object storage is expected to contain a key "+LookupClientBuilder.class.getName()+" with a reference to a builder"); + } + } + protected LookupClient(LookupClientBuilder builder) { this.locator = builder.metadataLocator; this.provider = builder.metadataProvider; diff --git a/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClientBuilder.java b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClientBuilder.java index 1d5fff2c..fb06ca4e 100644 --- a/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClientBuilder.java +++ b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/LookupClientBuilder.java @@ -19,10 +19,13 @@ package network.oxalis.vefa.peppol.lookup; +import java.util.HashMap; +import java.util.Map; + import network.oxalis.vefa.peppol.common.lang.PeppolLoadingException; -import network.oxalis.vefa.peppol.lookup.api.MetadataProvider; import network.oxalis.vefa.peppol.lookup.api.MetadataFetcher; import network.oxalis.vefa.peppol.lookup.api.MetadataLocator; +import network.oxalis.vefa.peppol.lookup.api.MetadataProvider; import network.oxalis.vefa.peppol.lookup.api.MetadataReader; import network.oxalis.vefa.peppol.mode.Mode; import network.oxalis.vefa.peppol.security.api.CertificateValidator; @@ -118,7 +121,9 @@ public LookupClient build() throws PeppolLoadingException { fetcher(mode.initiate("lookup.fetcher.class", MetadataFetcher.class)); if (metadataReader == null) reader(mode.initiate("lookup.reader.class", MetadataReader.class)); - - return new LookupClient(this); + + Map map = new HashMap(); + map.put(LookupClientBuilder.class.getName(), this); + return mode.initiate("lookup.impl.class", null, map); } } diff --git a/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClient.java b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClient.java new file mode 100644 index 00000000..5a9835b7 --- /dev/null +++ b/peppol-lookup/src/main/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClient.java @@ -0,0 +1,149 @@ +package network.oxalis.vefa.peppol.lookup.dummy; + +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.util.encoders.Base64; + +import network.oxalis.vefa.peppol.common.lang.EndpointNotFoundException; +import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier; +import network.oxalis.vefa.peppol.common.model.Endpoint; +import network.oxalis.vefa.peppol.common.model.Header; +import network.oxalis.vefa.peppol.common.model.ParticipantIdentifier; +import network.oxalis.vefa.peppol.common.model.ProcessIdentifier; +import network.oxalis.vefa.peppol.common.model.ProcessMetadata; +import network.oxalis.vefa.peppol.common.model.ServiceInformation; +import network.oxalis.vefa.peppol.common.model.ServiceMetadata; +import network.oxalis.vefa.peppol.common.model.ServiceReference; +import network.oxalis.vefa.peppol.common.model.TransportProfile; +import network.oxalis.vefa.peppol.lookup.LookupClient; +import network.oxalis.vefa.peppol.lookup.api.LookupException; +import network.oxalis.vefa.peppol.mode.Mode; +import network.oxalis.vefa.peppol.security.lang.PeppolSecurityException; + +/** + * Dummy implementation of LookupClient, which can be configured via reference.conf as: + * + *
+ 
+mode.TEST.lookup.impl.class = network.oxalis.vefa.peppol.lookup.dummy.DummyLookupClient
+
+mode.TEST.lookup.impl.dummy = {
+	uri: "http://localhost:8080/as4"
+	certificate: "MIIGkTCCBMWgAwIBA...+jUH1N7v7JJdaA="
+	transport: "peppol-transport-as4-v2_0"
+	process: "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
+	doctype: "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"
+}
+ * 
+ * + * It can be used for testing the sending process by just imitating all lookups to the same URL and profile. + */ +public class DummyLookupClient extends LookupClient { + + private URI uri; + private X509Certificate certificate; + private TransportProfile transport; + private ProcessIdentifier processIdentifier; + private DocumentTypeIdentifier docType; + + private Endpoint endpoint; + + public DummyLookupClient(Mode mode, Map objectStorage) { + super(mode, objectStorage); + init(mode); + } + + private void init(Mode mode) { + String prefix = "lookup.impl.dummy."; + + String uri = mode.getString(prefix + "uri"); + String certificateBase64 = mode.getString(prefix + "certificate"); + String transportCode = mode.getString(prefix + "transport"); + String process = mode.getString(prefix + "process"); + String doctype = mode.getString(prefix + "doctype"); + + try { + this.uri = new URI(uri); + } catch (Exception e1) { + throw new RuntimeException("Cannot build URI by " + uri, e1); + } + try { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + this.certificate = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(Base64.decode(certificateBase64))); + } catch (Exception e1) { + throw new RuntimeException("Cannot build dummy X.509 certificate by the base64 value " + certificateBase64, e1); + } + + this.transport = TransportProfile.of(transportCode); + this.endpoint = new Endpoint(this.transport, this.uri, this.certificate, null); + this.processIdentifier = ProcessIdentifier.of(process); + this.docType = DocumentTypeIdentifier.of(doctype); + } + + @Override + public List getServiceReferences(ParticipantIdentifier participantIdentifier) throws LookupException { + return Arrays.asList(ServiceReference.of(docType, this.processIdentifier)); + } + + @Override + public List getDocumentIdentifiers(ParticipantIdentifier participantIdentifier) throws LookupException { + return Arrays.asList(this.docType); + } + + @Override + public ServiceMetadata getServiceMetadata(ParticipantIdentifier participantIdentifier, DocumentTypeIdentifier documentTypeIdentifier) throws LookupException, PeppolSecurityException { + List> processes = Arrays.asList(ProcessMetadata.of(this.processIdentifier, this.endpoint)); + ServiceInformation serviceInformation = ServiceInformation.of(participantIdentifier, documentTypeIdentifier, processes); + return ServiceMetadata.of(serviceInformation); + } + + @Override + public Endpoint getEndpoint(ServiceMetadata serviceMetadata, ProcessIdentifier processIdentifier, TransportProfile... transportProfiles) throws PeppolSecurityException, EndpointNotFoundException { + return Endpoint.of(getFirstOrDefault(transportProfiles), uri, certificate); + } + + @Override + public Endpoint getEndpoint(ParticipantIdentifier participantIdentifier, DocumentTypeIdentifier documentTypeIdentifier, ProcessIdentifier processIdentifier, TransportProfile... transportProfiles) throws LookupException, PeppolSecurityException, EndpointNotFoundException { + return Endpoint.of(getFirstOrDefault(transportProfiles), uri, certificate); + } + + @Override + public Endpoint getEndpoint(Header header, TransportProfile... transportProfiles) throws LookupException, PeppolSecurityException, EndpointNotFoundException { + return Endpoint.of(getFirstOrDefault(transportProfiles), uri, certificate); + } + + private TransportProfile getFirstOrDefault(TransportProfile... transportProfiles) { + return transportProfiles != null && transportProfiles.length > 0 ? transportProfiles[0] : this.transport; + } + + public URI getDefaultUri() { + return uri; + } + + public X509Certificate getDefaultCertificate() { + return certificate; + } + + public TransportProfile getDefaultTransport() { + return transport; + } + + public ProcessIdentifier getDefaultProcessIdentifier() { + return processIdentifier; + } + + public DocumentTypeIdentifier getDefaultDocType() { + return docType; + } + + public Endpoint getDefaultEndpoint() { + return endpoint; + } + +} diff --git a/peppol-lookup/src/main/resources/reference.conf b/peppol-lookup/src/main/resources/reference.conf index 4ae2758f..eea0e213 100644 --- a/peppol-lookup/src/main/resources/reference.conf +++ b/peppol-lookup/src/main/resources/reference.conf @@ -38,3 +38,14 @@ mode.FRTEST.lookup.locator.hostname = acc.edelivery.tech.ec.europa.eu # Reader mode.default.lookup.reader.class = network.oxalis.vefa.peppol.lookup.reader.MultiReader +# Client +mode.default.lookup.impl.class = network.oxalis.vefa.peppol.lookup.LookupClient + +# Settings for dummy implementation of LookupClient +mode.default.lookup.impl.dummy = { + uri: "http://localhost:8080/as4" + certificate: "MIIFxDCCA6ygAwIBAgIQficA79PO/IwYeTa2m7BCBTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQT3BlblBFUFBPTCBBSVNCTDEkMCIGA1UEAxMbUEVQUE9MIEFDQ0VTUyBQT0lOVCBDQSAtIEcyMB4XDTE4MDUyODAwMDAwMFoXDTIwMDUxNzIzNTk1OVowbjESMBAGA1UEAwwJUE5PMDAwMDAxMR0wGwYDVQQLDBRQRVBQT0wgUFJPRFVDVElPTiBBUDEsMCoGA1UECgwjRGlyZWt0b3JhdGV0IGZvciBmb3J2YWx0bmluZyBvZyBJS1QxCzAJBgNVBAYTAk5PMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyCCMetUNnXgLU72eJHAqjuVTNjwqcY95S1LoCOmmAxoubXK38HS94woP3cvGEkIrRCZ+KpoQ+GNOC38iPuoGK8pxU07Q9HiJah/h4fF1NGLctzFZiyTP77AuMcwzLRv44n5O+NIzSnoIYd/2FGkuuehnnm8w1jblc6q41Oyoz4FdMjZzIHsR9sjb/RhcYuC622FKVWLZysFNGn+m3RQiz49w3pVWcV6z4XNIRPkcoYEKrIQJpYBRlnvrpXN3WJE7QM75MBX84er/zeXPev0CgcMkYYYpM94fgN5apopn/dfsssuzs8va3jjIdpc9gAjNW2WVrm60fcKaad4x6UGfaQIDAQABo4IBfDCCAXgwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCA6gwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFLk0v9qGkCAOLQEkKjA6a9N+ibUFMF0GA1UdHwRWMFQwUqBQoE6GTGh0dHA6Ly9wa2ktY3JsLnN5bWF1dGguY29tL2NhXzdiZWRjYmNjNGY3MjRlZmUzMGQ1MDA2ZGRhNjgxYmEwL0xhdGVzdENSTC5jcmwwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vcGtpLW9jc3Auc3ltYXV0aC5jb20wHwYDVR0jBBgwFoAUhyXfWyOmxDv5n98bpSCR3eT0PIEwLQYKYIZIAYb4RQEQAwQfMB0GE2CGSAGG+EUBEAECAwEBgbLX9DYWBjk1NzYwODA5BgpghkgBhvhFARAFBCswKQIBABYkYUhSMGNITTZMeTl3YTJrdGNtRXVjM2x0WVhWMGFDNWpiMjA9MA0GCSqGSIb3DQEBCwUAA4ICAQB8jYF/nEgyFTgxWdGJ1uDYqsZaigHKWtGVZgrR23IV0wGJm7N1YBRVWcirkAmZMZ1wZBXrqALH6ptTTnNE9mg1TSslXDGWgfjcWs/+UXw5v5IQRB8hBbCehOsHY9EfoygyESIS+mg85+ZUs2Kv52v1cifYUePXiLAnRF3qET2nCHo+39oeIs/vqh307HmzxCOPaMV8GnIhiB1VzwWUbVFYh8YC5T+8DojiT04Kw2G4nnnitKPkYZjUnNCFxzSG5ewwovcUXkONZfYSEgbHamWjQyehh69jYb4wboCeSycJU/3BqrWXxQLxVl6gixKNTiDJhbl37injliKAbipZV4SOqA+v7jTKOsEnvx67HZt57plFQPZMfJi4mLqWXDhtGNL375EC0ij9AXFIiNrFZolNoHN/n61zMGgMT37y38bLwi4JiDx7WcPrbC/JruD99ZAjF0plVgJQtSQUHR3jdpfSOwehZ2lq4wGPy1xWEIfhRdCZU+NBuKC7uj3i/jlNJQwEUzI40PtNV7EXHVRwND78S21OcrvLRr8dfgCV79OnEIaBW0ae+ngurur6COLDiwDfkLmhAzM5ZH821GrUVDqE1MpXMQZJUEahgzKHJCMgquLS8Pur2fp3rpTX15Go3F4seYZqv46bb+zbjboOp23RxZC5lWjE6d7xxzLqP6uM1Q==" + transport: "peppol-transport-as4-v2_0" + process: "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0" + doctype: "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1" +} diff --git a/peppol-lookup/src/test/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClientTest.java b/peppol-lookup/src/test/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClientTest.java new file mode 100644 index 00000000..a3d25603 --- /dev/null +++ b/peppol-lookup/src/test/java/network/oxalis/vefa/peppol/lookup/dummy/DummyLookupClientTest.java @@ -0,0 +1,54 @@ +package network.oxalis.vefa.peppol.lookup.dummy; + +import static org.testng.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.testng.annotations.Test; + +import network.oxalis.vefa.peppol.common.model.Endpoint; +import network.oxalis.vefa.peppol.common.model.ParticipantIdentifier; +import network.oxalis.vefa.peppol.common.model.ProcessIdentifier; +import network.oxalis.vefa.peppol.common.model.TransportProfile; +import network.oxalis.vefa.peppol.lookup.LookupClient; +import network.oxalis.vefa.peppol.lookup.LookupClientBuilder; +import network.oxalis.vefa.peppol.mode.Mode; + +class DummyLookupClientTest { + + @Test + void testDummyLookupClient() throws Exception { + Mode mode = Mode.of("TEST"); + Map map = new HashMap(); + map.put(LookupClientBuilder.class.getName(), LookupClientBuilder.forMode(mode)); + DummyLookupClient client = new DummyLookupClient(mode, map); + + ProcessIdentifier pi = ProcessIdentifier.of("test"); + + String documentIdentifier = "busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"; + ParticipantIdentifier pari = ParticipantIdentifier.of("0184:12345678"); + assertEquals(client.getDocumentIdentifiers(pari).toString(), "[" + documentIdentifier + "]"); + + TransportProfile tp = TransportProfile.of("test"); + Endpoint endpoint = client.getEndpoint(null, tp); + assertEquals(endpoint.getAddress().toString(), "http://localhost:8080/as4"); + assertEquals(endpoint.getCertificate().getSubjectX500Principal().getName(), "C=NO,O=Direktoratet for forvaltning og IKT,OU=PEPPOL PRODUCTION AP,CN=PNO000001"); + assertEquals(endpoint.getTransportProfile().toString(), "TransportProfile{test}"); + + assertEquals(client.getEndpoint(null, pi, tp).getTransportProfile().toString(), "TransportProfile{test}"); + assertEquals(client.getEndpoint(null, null, pi, tp).getTransportProfile().toString(), "TransportProfile{test}"); + assertEquals(client.getServiceMetadata(null, null).getServiceInformation().getEndpoint(client.getDefaultProcessIdentifier(), client.getDefaultTransport()).getAddress().toString(), "http://localhost:8080/as4"); + assertEquals(client.getServiceReferences(pari).get(0).getDocumentTypeIdentifier().toString(), documentIdentifier); + } + + @Test + public void testOverridingConfiguration() throws Exception { + assertEquals(LookupClient.class.getName(), LookupClientBuilder.forProduction().build().getClass().getName()); + assertEquals(LookupClient.class.getName(), LookupClientBuilder.forMode("TEST").build().getClass().getName()); + LookupClient dummyClient = LookupClientBuilder.forMode("DUMMY").build(); + assertEquals(DummyLookupClient.class.getName(), dummyClient.getClass().getName()); + assertEquals("http://localhost:9090/as4", ((DummyLookupClient) dummyClient).getDefaultEndpoint().getAddress().toString()); + } + +} diff --git a/peppol-lookup/src/test/resources/reference.conf b/peppol-lookup/src/test/resources/reference.conf new file mode 100644 index 00000000..10a58cad --- /dev/null +++ b/peppol-lookup/src/test/resources/reference.conf @@ -0,0 +1,3 @@ +mode.DUMMY.inherit=TEST +mode.DUMMY.lookup.impl.class = network.oxalis.vefa.peppol.lookup.dummy.DummyLookupClient +mode.DUMMY.lookup.impl.dummy.uri="http://localhost:9090/as4" \ No newline at end of file