From 0db758081263f27e0dd8b3165b4291a185fa5d31 Mon Sep 17 00:00:00 2001 From: gj0dcsa <135594855+gj0dcsa@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:35:58 +0100 Subject: [PATCH] CNF-42 JIT 120 beta 1 conformance --- jit/LICENSE | 201 ++ jit/pom.xml | 30 + .../standards/jit/JitComponentFactory.java | 149 + .../standards/jit/JitScenarioListBuilder.java | 81 + .../standards/jit/action/JitAction.java | 30 + .../jit/action/JitGetEventsAction.java | 52 + .../SupplyScenarioParametersAction.java | 113 + .../jit/party/JitFilterParameter.java | 35 + .../standards/jit/party/JitPublisher.java | 118 + .../standards/jit/party/JitRole.java | 23 + .../standards/jit/party/JitSubscriber.java | 74 + .../jit/party/SuppliedScenarioParameters.java | 44 + .../jit/messages/jit-120beta1-response.json | 88 + .../jit/sandboxes/auto-all-in-one.json | 35 + .../auto-publisher-tested-party.json | 29 + .../auto-publisher-testing-counterparts.json | 27 + .../auto-subscriber-tested-party.json | 31 + .../auto-subscriber-testing-counterparts.json | 31 + .../manual-publisher-tested-party.json | 27 + ...manual-publisher-testing-counterparts.json | 26 + .../manual-subscriber-tested-party.json | 27 + ...anual-subscriber-testing-counterparts.json | 26 + .../jit/schemas/jit-120beta1-publisher.json | 2714 +++++++++++++++++ pom.xml | 1 + sandbox/pom.xml | 5 + .../sandbox/ConformanceSandbox.java | 4 + .../sandbox/ConformanceWebuiHandler.java | 7 + .../springboot/ConformanceApplication.java | 2 + 28 files changed, 4030 insertions(+) create mode 100644 jit/LICENSE create mode 100644 jit/pom.xml create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/JitComponentFactory.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/JitScenarioListBuilder.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitAction.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitGetEventsAction.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/action/SupplyScenarioParametersAction.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitFilterParameter.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitPublisher.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitRole.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitSubscriber.java create mode 100644 jit/src/main/java/org/dcsa/conformance/standards/jit/party/SuppliedScenarioParameters.java create mode 100644 jit/src/main/resources/standards/jit/messages/jit-120beta1-response.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/auto-all-in-one.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/auto-publisher-tested-party.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/auto-publisher-testing-counterparts.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-tested-party.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-testing-counterparts.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/manual-publisher-tested-party.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/manual-publisher-testing-counterparts.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-tested-party.json create mode 100644 jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-testing-counterparts.json create mode 100644 jit/src/main/resources/standards/jit/schemas/jit-120beta1-publisher.json diff --git a/jit/LICENSE b/jit/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/jit/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/jit/pom.xml b/jit/pom.xml new file mode 100644 index 00000000..7a9cf697 --- /dev/null +++ b/jit/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + org.dcsa.conformance + jit + 0.0.1-SNAPSHOT + dcsa-conformance-jit + DCSA Conformance JIT + + 21 + 21 + 21 + UTF-8 + + + + org.dcsa.conformance + core + 0.0.1-SNAPSHOT + + + + org.projectlombok + lombok + 1.18.30 + true + + + diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/JitComponentFactory.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/JitComponentFactory.java new file mode 100644 index 00000000..b1553de0 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/JitComponentFactory.java @@ -0,0 +1,149 @@ +package org.dcsa.conformance.standards.jit; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import lombok.Getter; +import lombok.SneakyThrows; +import org.dcsa.conformance.core.AbstractComponentFactory; +import org.dcsa.conformance.core.check.JsonSchemaValidator; +import org.dcsa.conformance.core.party.ConformanceParty; +import org.dcsa.conformance.core.party.CounterpartConfiguration; +import org.dcsa.conformance.core.party.PartyConfiguration; +import org.dcsa.conformance.core.party.PartyWebClient; +import org.dcsa.conformance.core.scenario.ScenarioListBuilder; +import org.dcsa.conformance.core.state.JsonNodeMap; +import org.dcsa.conformance.core.toolkit.JsonToolkit; +import org.dcsa.conformance.standards.jit.party.JitPublisher; +import org.dcsa.conformance.standards.jit.party.JitRole; +import org.dcsa.conformance.standards.jit.party.JitSubscriber; + +public class JitComponentFactory extends AbstractComponentFactory { + public static final String STANDARD_NAME = "JIT"; + public static final List STANDARD_VERSIONS = List.of("1.2.0-Beta-1"); + + private static final String PUBLISHER_AUTH_HEADER_VALUE = UUID.randomUUID().toString(); + private static final String SUBSCRIBER_AUTH_HEADER_VALUE = UUID.randomUUID().toString(); + + @Getter private final String standardVersion; + + public JitComponentFactory(String standardVersion) { + this.standardVersion = standardVersion; + if (STANDARD_VERSIONS.stream().noneMatch(version -> version.equals(standardVersion))) { + throw new IllegalArgumentException( + "Unsupported standard version '%s'".formatted(standardVersion)); + } + } + + public List createParties( + PartyConfiguration[] partyConfigurations, + CounterpartConfiguration[] counterpartConfigurations, + JsonNodeMap persistentMap, + PartyWebClient webClient, + Map> orchestratorAuthHeader) { + Map partyConfigurationsByRoleName = + Arrays.stream(partyConfigurations) + .collect(Collectors.toMap(PartyConfiguration::getRole, Function.identity())); + Map counterpartConfigurationsByRoleName = + Arrays.stream(counterpartConfigurations) + .collect(Collectors.toMap(CounterpartConfiguration::getRole, Function.identity())); + + LinkedList parties = new LinkedList<>(); + + PartyConfiguration publisherConfiguration = + partyConfigurationsByRoleName.get(JitRole.PUBLISHER.getConfigName()); + if (publisherConfiguration != null) { + parties.add( + new JitPublisher( + standardVersion, + publisherConfiguration, + counterpartConfigurationsByRoleName.get(JitRole.SUBSCRIBER.getConfigName()), + persistentMap, + webClient, + orchestratorAuthHeader)); + } + + PartyConfiguration subscriberConfiguration = + partyConfigurationsByRoleName.get(JitRole.SUBSCRIBER.getConfigName()); + if (subscriberConfiguration != null) { + parties.add( + new JitSubscriber( + standardVersion, + subscriberConfiguration, + counterpartConfigurationsByRoleName.get(JitRole.PUBLISHER.getConfigName()), + persistentMap, + webClient, + orchestratorAuthHeader)); + } + + return parties; + } + + public LinkedHashMap> createModuleScenarioListBuilders( + PartyConfiguration[] partyConfigurations, + CounterpartConfiguration[] counterpartConfigurations) { + return JitScenarioListBuilder.createModuleScenarioListBuilders( + this, + _findPartyOrCounterpartName( + partyConfigurations, counterpartConfigurations, JitRole::isPublisher), + _findPartyOrCounterpartName( + partyConfigurations, counterpartConfigurations, JitRole::isSubscriber)); + } + + @Override + public SortedSet getRoleNames() { + return Arrays.stream(JitRole.values()) + .map(JitRole::getConfigName) + .collect(Collectors.toCollection(TreeSet::new)); + } + + public Set getReportRoleNames( + PartyConfiguration[] partyConfigurations, + CounterpartConfiguration[] counterpartConfigurations) { + return (partyConfigurations.length == JitRole.values().length + ? Arrays.stream(JitRole.values()).map(JitRole::getConfigName) + : Arrays.stream(counterpartConfigurations) + .map(CounterpartConfiguration::getRole) + .filter( + counterpartRole -> + Arrays.stream(partyConfigurations) + .map(PartyConfiguration::getRole) + .noneMatch(partyRole -> Objects.equals(partyRole, counterpartRole)))) + .collect(Collectors.toSet()); + } + + public JsonSchemaValidator getMessageSchemaValidator(String apiProviderRole, boolean forRequest) { + String schemaFilePath = + "/standards/jit/schemas/jit-%s-%s.json" + .formatted( + standardVersion.toLowerCase().replaceAll("[.-]", ""), + apiProviderRole.toLowerCase()); + String schemaName = + JitRole.isPublisher(apiProviderRole) ? (forRequest ? null : "operationsEvents") : null; + return JsonSchemaValidator.getInstance(schemaFilePath, schemaName); + } + + @SneakyThrows + public JsonNode getJsonSandboxConfigurationTemplate( + String testedPartyRole, boolean isManual, boolean isTestingCounterpartsConfig) { + return JsonToolkit.templateFileToJsonNode( + "/standards/jit/sandboxes/%s.json" + .formatted( + testedPartyRole == null + ? "auto-all-in-one" + : "%s-%s-%s" + .formatted( + isManual ? "manual" : "auto", + testedPartyRole.toLowerCase(), + isTestingCounterpartsConfig ? "testing-counterparts" : "tested-party")), + Map.ofEntries( + Map.entry("STANDARD_NAME_PLACEHOLDER", STANDARD_NAME), + Map.entry("STANDARD_VERSION_PLACEHOLDER", standardVersion), + Map.entry("PUBLISHER_AUTH_HEADER_VALUE_PLACEHOLDER", PUBLISHER_AUTH_HEADER_VALUE), + Map.entry("SUBSCRIBER_AUTH_HEADER_VALUE_PLACEHOLDER", SUBSCRIBER_AUTH_HEADER_VALUE), + Map.entry( + "SANDBOX_ID_PREFIX", + AbstractComponentFactory._sandboxIdPrefix(STANDARD_NAME, standardVersion)))); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/JitScenarioListBuilder.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/JitScenarioListBuilder.java new file mode 100644 index 00000000..9ac02f39 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/JitScenarioListBuilder.java @@ -0,0 +1,81 @@ +package org.dcsa.conformance.standards.jit; + +import static org.dcsa.conformance.standards.jit.party.JitFilterParameter.*; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.core.scenario.ScenarioListBuilder; +import org.dcsa.conformance.standards.jit.action.JitGetEventsAction; +import org.dcsa.conformance.standards.jit.action.SupplyScenarioParametersAction; +import org.dcsa.conformance.standards.jit.party.JitFilterParameter; +import org.dcsa.conformance.standards.jit.party.JitRole; + +@Slf4j +public class JitScenarioListBuilder extends ScenarioListBuilder { + private static final ThreadLocal threadLocalComponentFactory = + new ThreadLocal<>(); + private static final ThreadLocal threadLocalPublisherPartyName = new ThreadLocal<>(); + private static final ThreadLocal threadLocalSubscriberPartyName = new ThreadLocal<>(); + + public static LinkedHashMap createModuleScenarioListBuilders( + JitComponentFactory componentFactory, String publisherPartyName, String subscriberPartyName) { + threadLocalComponentFactory.set(componentFactory); + threadLocalPublisherPartyName.set(publisherPartyName); + threadLocalSubscriberPartyName.set(subscriberPartyName); + return Stream.of( + Map.entry( + "", + noAction() + .thenEither( + scenarioWithParameters(TRANSPORT_CALL_ID, LIMIT), + scenarioWithParameters(VESSEL_IMO_NUMBER, LIMIT), + scenarioWithParameters(CARRIER_SERVICE_CODE, LIMIT), + scenarioWithParameters(UN_LOCATION_CODE, LIMIT), + scenarioWithParameters(OPERATIONS_EVENT_TYPE_CODE, LIMIT), + scenarioWithParameters( + EVENT_CREATED_DATE_TIME_GTE, EVENT_CREATED_DATE_TIME_LT, LIMIT)))) + .collect( + Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } + + private JitScenarioListBuilder(Function actionBuilder) { + super(actionBuilder); + } + + private static JitScenarioListBuilder noAction() { + return new JitScenarioListBuilder(null); + } + + private static JitScenarioListBuilder scenarioWithParameters( + JitFilterParameter... jitFilterParameters) { + return supplyScenarioParameters(jitFilterParameters).then(getEvents()); + } + + private static JitScenarioListBuilder supplyScenarioParameters( + JitFilterParameter... jitFilterParameters) { + String publisherPartyName = threadLocalPublisherPartyName.get(); + return new JitScenarioListBuilder( + previousAction -> + new SupplyScenarioParametersAction(publisherPartyName, jitFilterParameters)); + } + + private static JitScenarioListBuilder getEvents() { + JitComponentFactory componentFactory = threadLocalComponentFactory.get(); + String publisherPartyName = threadLocalPublisherPartyName.get(); + String subscriberPartyName = threadLocalSubscriberPartyName.get(); + return new JitScenarioListBuilder( + previousAction -> + new JitGetEventsAction( + subscriberPartyName, + publisherPartyName, + previousAction, + componentFactory.getMessageSchemaValidator( + JitRole.PUBLISHER.getConfigName(), false))); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitAction.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitAction.java new file mode 100644 index 00000000..78952f35 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitAction.java @@ -0,0 +1,30 @@ +package org.dcsa.conformance.standards.jit.action; + +import java.util.Map; +import java.util.function.Supplier; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.standards.jit.party.SuppliedScenarioParameters; + +public abstract class JitAction extends ConformanceAction { + protected final Supplier sspSupplier; + protected final int expectedStatus; + + public JitAction( + String sourcePartyName, + String targetPartyName, + ConformanceAction previousAction, + String actionTitle, + int expectedStatus) { + super(sourcePartyName, targetPartyName, previousAction, actionTitle); + this.sspSupplier = _getSspSupplier(previousAction); + this.expectedStatus = expectedStatus; + } + + private Supplier _getSspSupplier(ConformanceAction previousAction) { + return previousAction instanceof SupplyScenarioParametersAction supplyScenarioParametersAction + ? supplyScenarioParametersAction::getSuppliedScenarioParameters + : previousAction == null + ? () -> SuppliedScenarioParameters.fromMap(Map.ofEntries()) + : _getSspSupplier(previousAction.getPreviousAction()); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitGetEventsAction.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitGetEventsAction.java new file mode 100644 index 00000000..2587b3f2 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/JitGetEventsAction.java @@ -0,0 +1,52 @@ +package org.dcsa.conformance.standards.jit.action; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.stream.Stream; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.dcsa.conformance.core.check.*; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.core.traffic.HttpMessageType; +import org.dcsa.conformance.standards.jit.party.JitRole; + +@Getter +@Slf4j +public class JitGetEventsAction extends JitAction { + private final JsonSchemaValidator responseSchemaValidator; + + public JitGetEventsAction( + String subscriberPartyName, + String publisherPartyName, + ConformanceAction previousAction, + JsonSchemaValidator responseSchemaValidator) { + super(subscriberPartyName, publisherPartyName, previousAction, "GetEvents", 200); + this.responseSchemaValidator = responseSchemaValidator; + } + + @Override + public String getHumanReadablePrompt() { + return "Send a GET events request with the following parameters: " + + sspSupplier.get().toJson().toPrettyString(); + } + + @Override + public ConformanceCheck createCheck(String expectedApiVersion) { + return new ConformanceCheck(getActionTitle()) { + @Override + protected Stream createSubChecks() { + return Stream.of( + new UrlPathCheck(JitRole::isSubscriber, getMatchedExchangeUuid(), "/events"), + new ResponseStatusCheck(JitRole::isPublisher, getMatchedExchangeUuid(), expectedStatus), + new JsonSchemaCheck( + JitRole::isPublisher, + getMatchedExchangeUuid(), + HttpMessageType.RESPONSE, + responseSchemaValidator)); + } + }; + } + + public ObjectNode asJsonNode() { + return super.asJsonNode().set("suppliedScenarioParameters", sspSupplier.get().toJson()); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/action/SupplyScenarioParametersAction.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/SupplyScenarioParametersAction.java new file mode 100644 index 00000000..9162904b --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/action/SupplyScenarioParametersAction.java @@ -0,0 +1,113 @@ +package org.dcsa.conformance.standards.jit.action; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.Getter; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.standards.jit.party.JitFilterParameter; +import org.dcsa.conformance.standards.jit.party.SuppliedScenarioParameters; + +@Getter +public class SupplyScenarioParametersAction extends ConformanceAction { + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + private SuppliedScenarioParameters suppliedScenarioParameters = null; + private final LinkedHashSet jitFilterParameters; + + public SupplyScenarioParametersAction( + String publisherPartyName, JitFilterParameter... jitFilterParameters) { + super( + publisherPartyName, + null, + null, + "SupplyScenarioParameters(%s)" + .formatted( + Arrays.stream(jitFilterParameters) + .map(JitFilterParameter::getQueryParamName) + .collect(Collectors.joining(", ")))); + this.jitFilterParameters = + Stream.of(jitFilterParameters).collect(Collectors.toCollection(LinkedHashSet::new)); + } + + @Override + public void reset() { + super.reset(); + suppliedScenarioParameters = null; + } + + @Override + public ObjectNode exportJsonState() { + ObjectNode jsonState = super.exportJsonState(); + if (suppliedScenarioParameters != null) { + jsonState.set("suppliedScenarioParameters", suppliedScenarioParameters.toJson()); + } + return jsonState; + } + + @Override + public void importJsonState(JsonNode jsonState) { + super.importJsonState(jsonState); + if (jsonState.has("suppliedScenarioParameters")) { + suppliedScenarioParameters = + SuppliedScenarioParameters.fromJson(jsonState.required("suppliedScenarioParameters")); + } + } + + @Override + public ObjectNode asJsonNode() { + ObjectNode objectNode = super.asJsonNode(); + ArrayNode jsonJitFilterParameters = objectNode.putArray("jitFilterParametersQueryParamNames"); + jitFilterParameters.forEach( + jitFilterParameter -> jsonJitFilterParameters.add(jitFilterParameter.getQueryParamName())); + return objectNode; + } + + @Override + public String getHumanReadablePrompt() { + return "Use the following format to provide the values of the specified query parameters" + + " for which your party can successfully process a GET request:"; + } + + @Override + public JsonNode getJsonForHumanReadablePrompt() { + return SuppliedScenarioParameters.fromMap( + jitFilterParameters.stream() + .collect( + Collectors.toMap( + Function.identity(), + jitFilterParameter -> + switch (jitFilterParameter) { + case LIMIT -> "100"; + case EVENT_CREATED_DATE_TIME, + EVENT_CREATED_DATE_TIME_EQ, + EVENT_CREATED_DATE_TIME_GT, + EVENT_CREATED_DATE_TIME_GTE, + EVENT_CREATED_DATE_TIME_LT, + EVENT_CREATED_DATE_TIME_LTE -> + ZonedDateTime.now() + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + default -> "TODO"; + }))) + .toJson(); + } + + @Override + public boolean isInputRequired() { + return true; + } + + @Override + public void handlePartyInput(JsonNode partyInput) { + super.handlePartyInput(partyInput); + suppliedScenarioParameters = SuppliedScenarioParameters.fromJson(partyInput.get("input")); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitFilterParameter.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitFilterParameter.java new file mode 100644 index 00000000..e7d080d3 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitFilterParameter.java @@ -0,0 +1,35 @@ +package org.dcsa.conformance.standards.jit.party; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import lombok.Getter; + +public enum JitFilterParameter { + TRANSPORT_CALL_ID("transportCallID"), + VESSEL_IMO_NUMBER("vesselIMONumber"), + CARRIER_SERVICE_CODE("carrierServiceCode"), + UN_LOCATION_CODE("UNLocationCode"), + OPERATIONS_EVENT_TYPE_CODE("operationsEventTypeCode"), + EVENT_CREATED_DATE_TIME("eventCreatedDateTime"), + EVENT_CREATED_DATE_TIME_GTE("eventCreatedDateTime:gte"), + EVENT_CREATED_DATE_TIME_GT("eventCreatedDateTime:gt"), + EVENT_CREATED_DATE_TIME_LTE("eventCreatedDateTime:lte"), + EVENT_CREATED_DATE_TIME_LT("eventCreatedDateTime:lt"), + EVENT_CREATED_DATE_TIME_EQ("eventCreatedDateTime:eq"), + LIMIT("limit"), + ; + + public static final Map byQueryParamName = + Arrays.stream(values()) + .collect( + Collectors.toUnmodifiableMap( + JitFilterParameter::getQueryParamName, Function.identity())); + + @Getter private final String queryParamName; + + JitFilterParameter(String queryParamName) { + this.queryParamName = queryParamName; + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitPublisher.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitPublisher.java new file mode 100644 index 00000000..624b795a --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitPublisher.java @@ -0,0 +1,118 @@ +package org.dcsa.conformance.standards.jit.party; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import lombok.extern.slf4j.Slf4j; +import org.dcsa.conformance.core.party.ConformanceParty; +import org.dcsa.conformance.core.party.CounterpartConfiguration; +import org.dcsa.conformance.core.party.PartyConfiguration; +import org.dcsa.conformance.core.party.PartyWebClient; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.core.state.JsonNodeMap; +import org.dcsa.conformance.core.toolkit.JsonToolkit; +import org.dcsa.conformance.core.traffic.ConformanceMessageBody; +import org.dcsa.conformance.core.traffic.ConformanceRequest; +import org.dcsa.conformance.core.traffic.ConformanceResponse; +import org.dcsa.conformance.standards.jit.action.SupplyScenarioParametersAction; + +@Slf4j +public class JitPublisher extends ConformanceParty { + + public JitPublisher( + String apiVersion, + PartyConfiguration partyConfiguration, + CounterpartConfiguration counterpartConfiguration, + JsonNodeMap persistentMap, + PartyWebClient webClient, + Map> orchestratorAuthHeader) { + super( + apiVersion, + partyConfiguration, + counterpartConfiguration, + persistentMap, + webClient, + orchestratorAuthHeader); + } + + @Override + protected void exportPartyJsonState(ObjectNode targetObjectNode) {} + + @Override + protected void importPartyJsonState(ObjectNode sourceObjectNode) {} + + @Override + protected void doReset() {} + + @Override + protected Map, Consumer> getActionPromptHandlers() { + return Map.ofEntries( + Map.entry(SupplyScenarioParametersAction.class, this::supplyScenarioParameters)); + } + + private void supplyScenarioParameters(JsonNode actionPrompt) { + log.info("JitPublisher.supplyScenarioParameters(%s)".formatted(actionPrompt.toPrettyString())); + + SuppliedScenarioParameters responseSsp = + SuppliedScenarioParameters.fromMap( + StreamSupport.stream( + actionPrompt.required("jitFilterParametersQueryParamNames").spliterator(), + false) + .map( + jsonJitFilterParameter -> + JitFilterParameter.byQueryParamName.get(jsonJitFilterParameter.asText())) + .collect( + Collectors.toMap( + Function.identity(), + jitFilterParameter -> + switch (jitFilterParameter) { + case TRANSPORT_CALL_ID -> UUID.randomUUID().toString(); + case VESSEL_IMO_NUMBER -> "9321483"; + case CARRIER_SERVICE_CODE -> "FE1"; + case UN_LOCATION_CODE -> "FRPAR"; + case OPERATIONS_EVENT_TYPE_CODE -> "STRT"; + case EVENT_CREATED_DATE_TIME, + EVENT_CREATED_DATE_TIME_GTE, + EVENT_CREATED_DATE_TIME_GT, + EVENT_CREATED_DATE_TIME_LTE, + EVENT_CREATED_DATE_TIME_LT, + EVENT_CREATED_DATE_TIME_EQ -> + ZonedDateTime.now() + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + case LIMIT -> "100"; + }))); + + asyncOrchestratorPostPartyInput( + new ObjectMapper() + .createObjectNode() + .put("actionId", actionPrompt.required("actionId").asText()) + .set("input", responseSsp.toJson())); + + addOperatorLogEntry( + "Submitting SuppliedScenarioParameters: %s" + .formatted(responseSsp.toJson().toPrettyString())); + } + + @Override + public ConformanceResponse handleRequest(ConformanceRequest request) { + log.info("JitPublisher.handleRequest(%s)".formatted(request)); + + JsonNode jsonResponseBody = + JsonToolkit.templateFileToJsonNode( + "/standards/jit/messages/jit-%s-response.json" + .formatted(apiVersion.toLowerCase().replaceAll("[.-]", "")), + Map.ofEntries()); + + return request.createResponse( + 200, + Map.of("Api-Version", List.of(apiVersion)), + new ConformanceMessageBody(jsonResponseBody)); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitRole.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitRole.java new file mode 100644 index 00000000..983b4024 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitRole.java @@ -0,0 +1,23 @@ +package org.dcsa.conformance.standards.jit.party; + +import lombok.Getter; + +@Getter +public enum JitRole { + PUBLISHER("Publisher"), + SUBSCRIBER("Subscriber"); + + private final String configName; + + JitRole(String configName) { + this.configName = configName; + } + + public static boolean isPublisher(String configName) { + return JitRole.PUBLISHER.configName.equals(configName); + } + + public static boolean isSubscriber(String configName) { + return JitRole.SUBSCRIBER.configName.equals(configName); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitSubscriber.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitSubscriber.java new file mode 100644 index 00000000..e97198dd --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/JitSubscriber.java @@ -0,0 +1,74 @@ +package org.dcsa.conformance.standards.jit.party; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.dcsa.conformance.core.party.ConformanceParty; +import org.dcsa.conformance.core.party.CounterpartConfiguration; +import org.dcsa.conformance.core.party.PartyConfiguration; +import org.dcsa.conformance.core.party.PartyWebClient; +import org.dcsa.conformance.core.scenario.ConformanceAction; +import org.dcsa.conformance.core.state.JsonNodeMap; +import org.dcsa.conformance.core.traffic.ConformanceRequest; +import org.dcsa.conformance.core.traffic.ConformanceResponse; +import org.dcsa.conformance.standards.jit.action.JitGetEventsAction; + +@Slf4j +public class JitSubscriber extends ConformanceParty { + + public JitSubscriber( + String apiVersion, + PartyConfiguration partyConfiguration, + CounterpartConfiguration counterpartConfiguration, + JsonNodeMap persistentMap, + PartyWebClient webClient, + Map> orchestratorAuthHeader) { + super( + apiVersion, + partyConfiguration, + counterpartConfiguration, + persistentMap, + webClient, + orchestratorAuthHeader); + } + + @Override + protected void exportPartyJsonState(ObjectNode targetObjectNode) {} + + @Override + protected void importPartyJsonState(ObjectNode sourceObjectNode) {} + + @Override + protected void doReset() {} + + @Override + protected Map, Consumer> getActionPromptHandlers() { + return Map.ofEntries(Map.entry(JitGetEventsAction.class, this::getEvents)); + } + + private void getEvents(JsonNode actionPrompt) { + log.info("JitSubscriber.getEvents(%s)".formatted(actionPrompt.toPrettyString())); + SuppliedScenarioParameters ssp = + SuppliedScenarioParameters.fromJson(actionPrompt.get("suppliedScenarioParameters")); + + syncCounterpartGet( + "/v1/events", + ssp.getMap().entrySet().stream() + .collect( + Collectors.toMap( + entry -> entry.getKey().getQueryParamName(), + entry -> Set.of(entry.getValue())))); + + addOperatorLogEntry( + "Sent GET events request with parameters %s".formatted(ssp.toJson().toPrettyString())); + } + + @Override + public ConformanceResponse handleRequest(ConformanceRequest request) { + log.info("JitSubscriber.handleRequest(%s)".formatted(request)); + throw new UnsupportedOperationException(); + } +} diff --git a/jit/src/main/java/org/dcsa/conformance/standards/jit/party/SuppliedScenarioParameters.java b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/SuppliedScenarioParameters.java new file mode 100644 index 00000000..71366280 --- /dev/null +++ b/jit/src/main/java/org/dcsa/conformance/standards/jit/party/SuppliedScenarioParameters.java @@ -0,0 +1,44 @@ +package org.dcsa.conformance.standards.jit.party; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import lombok.Getter; + +@Getter +public class SuppliedScenarioParameters { + + private final Map map; + + private SuppliedScenarioParameters(Map map) { + this.map = Collections.unmodifiableMap(map); + } + + public ObjectNode toJson() { + ObjectNode objectNode = new ObjectMapper().createObjectNode(); + map.forEach( + (jitFilterParameter, value) -> + objectNode.put(jitFilterParameter.getQueryParamName(), value)); + return objectNode; + } + + public static SuppliedScenarioParameters fromMap(Map map) { + return new SuppliedScenarioParameters(map); + } + + public static SuppliedScenarioParameters fromJson(JsonNode jsonNode) { + return new SuppliedScenarioParameters( + Arrays.stream(JitFilterParameter.values()) + .filter(jitFilterParameter -> jsonNode.has(jitFilterParameter.getQueryParamName())) + .collect( + Collectors.toUnmodifiableMap( + Function.identity(), + jitFilterParameter -> + jsonNode.required(jitFilterParameter.getQueryParamName()).asText()))); + } +} diff --git a/jit/src/main/resources/standards/jit/messages/jit-120beta1-response.json b/jit/src/main/resources/standards/jit/messages/jit-120beta1-response.json new file mode 100644 index 00000000..9e13769c --- /dev/null +++ b/jit/src/main/resources/standards/jit/messages/jit-120beta1-response.json @@ -0,0 +1,88 @@ +[ + { + "eventID": "3cecb101-7a1a-43a4-9d62-e88a131651e2", + "eventCreatedDateTime": "2021-01-09T14:12:56+01:00", + "eventType": "OPERATIONS", + "eventClassifierCode": "ACT", + "eventDateTime": "2019-11-12T07:41:00+08:30", + "operationsEventTypeCode": "STRT", + "publisher": { + "partyName": "Asseco Denmark", + "taxReference1": "CVR-25645774", + "taxReference2": "CVR-25645774", + "publicKey": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkFzaW", + "address": { + "name": "Henrik", + "street": "Kronprincessegade", + "streetNumber": "54", + "floor": "5. sal", + "postCode": "1306", + "city": "København", + "stateRegion": "N/A", + "country": "Denmark" + }, + "identifyingCodes": [ + { + "DCSAResponsibleAgencyCode": "SMDG", + "partyCode": "MSK", + "codeListName": "LCL" + } + ] + }, + "publisherRole": "TR", + "eventLocation": { + "locationName": "Port of Amsterdam", + "latitude": "48.8585500", + "longitude": "2.294492036", + "UNLocationCode": "FRPAR", + "facilityCode": "ADT", + "facilityCodeListProvider": "SMDG", + "address": { + "name": "Henrik", + "street": "Kronprincessegade", + "streetNumber": "54", + "floor": "5. sal", + "postCode": "1306", + "city": "København", + "stateRegion": "N/A", + "country": "Denmark" + } + }, + "portCallServiceTypeCode": "BUNK", + "portCallPhaseTypeCode": "ALGS", + "facilityTypeCode": "BRTH", + "delayReasonCode": "WEA", + "remark": "Port closed due to strike", + "transportCall": { + "transportCallID": "123e4567-e89b-12d3-a456-426614174000", + "transportCallReference": "987e4567", + "portVisitReference": "NLRTM1234589", + "carrierServiceCode": "FE1", + "carrierExportVoyageNumber": "2103S", + "carrierImportVoyageNumber": "2103N", + "transportCallSequenceNumber": 2, + "modeOfTransport": "VESSEL", + "location": { + "locationName": "Port of Amsterdam", + "latitude": "48.8585500", + "longitude": "2.294492036" + }, + "vessel": { + "vesselIMONumber": "9321483", + "vesselName": "King of the Seas", + "vesselFlag": "DE", + "vesselCallSignNumber": "NCVV", + "vesselOperatorCarrierCode": "MAEU", + "vesselOperatorCarrierCodeListProvider": "NMFTA" + } + }, + "vesselPosition": { + "locationName": "Port of Amsterdam", + "latitude": "48.8585500", + "longitude": "2.294492036" + }, + "milesToDestinationPort": 245.45, + "vesselDraft": 12.5, + "vesselDraftUnit": "MTR" + } +] \ No newline at end of file diff --git a/jit/src/main/resources/standards/jit/sandboxes/auto-all-in-one.json b/jit/src/main/resources/standards/jit/sandboxes/auto-all-in-one.json new file mode 100644 index 00000000..80a369ec --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/auto-all-in-one.json @@ -0,0 +1,35 @@ +{ + "id": "SANDBOX_ID_PREFIX-auto-all-in-one", + "name": "Auto all-in-one", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": true + }, + "parties" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-all-in-one" + }, { + "name" : "Subscriber1", + "role" : "Subscriber", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-all-in-one" + } ], + "counterparts" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-all-in-one/party/Publisher1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + }, { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-all-in-one/party/Subscriber1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-tested-party.json b/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-tested-party.json new file mode 100644 index 00000000..0098b7d7 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-tested-party.json @@ -0,0 +1,29 @@ +{ + "id": "SANDBOX_ID_PREFIX-auto-publisher-tested-party", + "name": "Auto publisher tested party", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": false + }, + "parties" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "orchestratorUrl": "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts" + } ], + "counterparts" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts/party/Publisher1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + } ,{ + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts/party/Subscriber1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-testing-counterparts.json b/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-testing-counterparts.json new file mode 100644 index 00000000..a5fdaea9 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/auto-publisher-testing-counterparts.json @@ -0,0 +1,27 @@ +{ + "id": "SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts", + "name": "Auto publisher testing counterparts", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": true + }, + "parties" : [ { + "name" : "Subscriber1", + "role" : "Subscriber", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts" + } ], + "counterparts" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-tested-party/party/Publisher1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + }, { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-publisher-testing-counterparts/party/Subscriber1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-tested-party.json b/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-tested-party.json new file mode 100644 index 00000000..e68e590d --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-tested-party.json @@ -0,0 +1,31 @@ +{ + "id": "SANDBOX_ID_PREFIX-auto-subscriber-tested-party", + "name": "Auto subscriber tested party", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "PLATFORM_AUTH_HEADER_VALUE_PLACEHOLDER", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": false + }, + "parties" : [ { + "name" : "Subscriber1", + "role" : "Subscriber", + "orchestratorUrl": "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-testing-counterparts" + } ], + "counterparts" : [ { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-tested-party/party/Subscriber1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "PLATFORM_AUTH_HEADER_VALUE_PLACEHOLDER" + }, { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-testing-counterparts/party/Publisher1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-testing-counterparts.json b/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-testing-counterparts.json new file mode 100644 index 00000000..32be6d28 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/auto-subscriber-testing-counterparts.json @@ -0,0 +1,31 @@ +{ + "id": "SANDBOX_ID_PREFIX-auto-subscriber-testing-counterparts", + "name": "Auto subscriber testing counterparts", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": true + }, + "parties" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-testing-counterparts" + } ], + "counterparts" : [ { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-tested-party/party/Subscriber1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "PLATFORM_AUTH_HEADER_VALUE_PLACEHOLDER" + }, { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-auto-subscriber-testing-counterparts/party/Publisher1/api", + "authHeaderName": "dcsa-conformance-api-key", + "authHeaderValue": "CARRIER_AUTH_HEADER_VALUE_PLACEHOLDER" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-tested-party.json b/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-tested-party.json new file mode 100644 index 00000000..1217e9b5 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-tested-party.json @@ -0,0 +1,27 @@ +{ + "id": "SANDBOX_ID_PREFIX-manual-publisher-tested-party", + "name": "Manual publisher tested party", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": false + }, + "parties" : [ { + "inManualMode": true, + "name" : "Publisher1", + "role" : "Publisher", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-testing-counterparts" + } ], + "counterparts" : [ { + "inManualMode": true, + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-tested-party/party/Publisher1/api" + }, { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-testing-counterparts/party/Subscriber1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-testing-counterparts.json b/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-testing-counterparts.json new file mode 100644 index 00000000..e6ff9935 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/manual-publisher-testing-counterparts.json @@ -0,0 +1,26 @@ +{ + "id": "SANDBOX_ID_PREFIX-manual-publisher-testing-counterparts", + "name": "Manual publisher testing counterparts", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": true + }, + "parties" : [ { + "name" : "Subscriber1", + "role" : "Subscriber", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-testing-counterparts" + } ], + "counterparts" : [ { + "inManualMode": true, + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-tested-party/party/Publisher1/api" + }, { + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-publisher-testing-counterparts/party/Subscriber1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-tested-party.json b/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-tested-party.json new file mode 100644 index 00000000..9be02cb9 --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-tested-party.json @@ -0,0 +1,27 @@ +{ + "id": "SANDBOX_ID_PREFIX-manual-subscriber-tested-party", + "name": "Manual subscriber tested party", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": false + }, + "parties" : [ { + "inManualMode": true, + "name" : "Subscriber1", + "role" : "Subscriber", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-testing-counterparts" + } ], + "counterparts" : [ { + "inManualMode": true, + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-tested-party/party/Subscriber1/api" + }, { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-testing-counterparts/party/Publisher1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-testing-counterparts.json b/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-testing-counterparts.json new file mode 100644 index 00000000..fb30e32d --- /dev/null +++ b/jit/src/main/resources/standards/jit/sandboxes/manual-subscriber-testing-counterparts.json @@ -0,0 +1,26 @@ +{ + "id": "SANDBOX_ID_PREFIX-manual-subscriber-testing-counterparts", + "name": "Manual subscriber testing counterparts", + "standard" : { + "name" : "STANDARD_NAME_PLACEHOLDER", + "version" : "STANDARD_VERSION_PLACEHOLDER" + }, + "orchestrator" : { + "active": true + }, + "parties" : [ { + "name" : "Publisher1", + "role" : "Publisher", + "orchestratorUrl" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-testing-counterparts" + } ], + "counterparts" : [ { + "inManualMode": true, + "name" : "Subscriber1", + "role" : "Subscriber", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-tested-party/party/Subscriber1/api" + }, { + "name" : "Publisher1", + "role" : "Publisher", + "url" : "http://localhost:8080/conformance/sandbox/SANDBOX_ID_PREFIX-manual-subscriber-testing-counterparts/party/Publisher1/api" + } ] +} diff --git a/jit/src/main/resources/standards/jit/schemas/jit-120beta1-publisher.json b/jit/src/main/resources/standards/jit/schemas/jit-120beta1-publisher.json new file mode 100644 index 00000000..06f59d29 --- /dev/null +++ b/jit/src/main/resources/standards/jit/schemas/jit-120beta1-publisher.json @@ -0,0 +1,2714 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "DCSA OpenAPI specification for Just in Time Portcalls\n", + "description": "API specification issued by DCSA.org\n\nThis API supports JIT v1.2 (Just in Time Portcalls). JIT is used for negotiating timestamps between vessel and port/terminal and other services providers. To create a new timestamp the `POST /v1/timestamps` endPoint is to be used.\n\nFor explanation to specific values or objects please refer to the [Information Model 2022.2 - **to be updated in July**]\n\nThis API does not define the business rules regarding what is allowed to update at what time. For this the [Just in Time Portcall IFS v1.2](https://dcsa.my.salesforce.com/sfc/p/#2o000000YvHJ/a/7T000000Db84/Rp.tknLWVuS79ZXmWUU_IXgexNiFXgSJExKnNPv5si8) should be consulted.\n\nIt is possible to use this API as a standalone API. In order to do so it is necessary to use the poll-endPoint `GET /v1/events` in order to pull event information.\n\nIt is recomended to implement the [DCSA Just in Time Portcalls (JIT) Event Hub v1.2](https://app.swaggerhub.com/apis/dcsaorg/JIT_EVENT_HUB/1.2.0-Beta-1) in order to use the push model. Here events are pushed as they occur.\n\nFor a changelog please click [here](https://github.com/dcsaorg/DCSA-OpenAPI/tree/master/jit/v1#v120B1). Please also [create a GitHub issue](https://github.com/dcsaorg/DCSA-OpenAPI/issues/new) if you have any questions/comments.\n\nFor an example of an implementation of this API please check the [JIT Reference Implementation](https://github.com/dcsaorg/DCSA-JIT)\n", + "contact": { + "name": "Digital Container Shipping Association (DCSA)", + "url": "https://dcsa.org", + "email": "info@dcsa.org" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.2.0-Beta-1" + }, + "servers": [ + { + "url": "/" + } + ], + "tags": [ + { + "name": "Just in Time Portcall", + "description": "Just in Time Portcall operations" + }, + { + "name": "Events" + } + ], + "paths": { + "/v1/timestamps": { + "post": { + "tags": [ + "Just in Time Portcall" + ], + "summary": "Post a new timestamp", + "description": "a timestamp object provides the date-time when a specific event is expected, requested or planned to occur or has occured\n", + "parameters": [ + { + "name": "API-Version", + "in": "header", + "description": "An API-Version header MAY be added to the request (optional); if added it MUST only contain MAJOR version. API-Version header MUST be aligned with the URI version.\n", + "required": false, + "schema": { + "type": "string", + "example": "1" + } + } + ], + "requestBody": { + "description": "The new Timestamp", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/timestamp" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Timestamp successfully posted", + "headers": { + "API-Version": { + "$ref": "#/components/headers/API-Version" + } + } + }, + "default": { + "description": "Unexpected error", + "headers": { + "API-Version": { + "$ref": "#/components/headers/API-Version" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/error" + } + } + } + } + } + } + }, + "/v1/events": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get Operations events", + "description": "Retrieves Operations events. The default sort order is by eventCreatedDateTime in descending order (`DESC`)\n\nIt is possible to combine queryParameters. When combing queryParameters the logical AND is used between them. The response list must fulfill all queryParameters. An example of this is when the following queryParameters are used:\n\n`eventCreatedDateTime:gte=2021-04-01T14:12:56+01:00` and `vesselIMONumber=9321484`\n\nthen all events in the response list returned must be connected to vesselIMONumber `9321484` AND have an eventCreatedDateTime ≥ `2021-04-01T14:12:56+01:00`\n\nNB: When combining queryParameters be aware that it is also possible to make combinations that are mutual contradicting! An example of this could be when the following queryParameters are used:\n\n`vesselIMONumber=9321484` and `carrierServiceCode=FE1`\n\nif there are no Vessels with IMO number `9321484` on Carrier Service Code `FE1`. If this is the case then this response will return an empty list!\n", + "parameters": [ + { + "name": "transportCallID", + "in": "query", + "description": "ID uniquely identifying a transport call, to filter events by.\n\nSpecifying this filter will only return events related to this particular transportCallID\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/transportCallID" + } + }, + { + "name": "vesselIMONumber", + "in": "query", + "description": "The identifier of vessel for which schedule details are published. Depending on schedule type, this may not be available yet.\n\nSpecifying this filter will only return events related to this particular vesselIMONumber.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/vesselIMONumber" + } + }, + { + "name": "carrierVoyageNumber", + "in": "query", + "description": "Filter on the vessel operator-specific identifier of the Voyage.\n\nSpecifying this filter will only return events related to this particular carrierVoyageNumber.\n\nDeprecated: Use exportVoyageNumber instead\n", + "required": false, + "deprecated": true, + "schema": { + "$ref": "#/components/schemas/carrierVoyageNumber" + } + }, + { + "name": "exportVoyageNumber", + "in": "query", + "description": "Filter on the vessel operator-specific identifier of the export Voyage.\n\nSpecifying this filter will only return events related to this particular exportVoyageNumber.\n\n**Deprecated:** Use carrierExportVoyageNumber instead\n", + "required": false, + "deprecated": true, + "schema": { + "$ref": "#/components/schemas/exportVoyageNumber" + } + }, + { + "name": "carrierServiceCode", + "in": "query", + "description": "Filter on the carrier specific identifier of the service.\n\nSpecifying this filter will only return events related to this particular carrierServiceCode.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/carrierServiceCode" + } + }, + { + "name": "UNLocationCode", + "in": "query", + "description": "The UN Location code specifying where the place is located.\n\nSpecifying this filter will only return events related to this particular UN Location code.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/UNLocationCode" + } + }, + { + "name": "operationsEventTypeCode", + "in": "query", + "description": "The code to identify the type of event that is related to the operation\n- STRT (Started)\n- CMPL (Completed)\n- ARRI (Arrived)\n- DEPA (Departed)\n- OMIT (Omitted)\n- CANC (Cancelled)\n\nIt is possible to select multiple values by comma (,) separating them. For multiple values the OR-operator is used. For example operationsEventTypeCode=ARRI,CMPL matches both Arrived (ARRI) and Completed (CMPL) operations events.\n\nDefault is all operationsEventTypeCodes.\n", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/operationsEventTypeCode" + }, + "default": "STRT,CMPL,ARRI,DEPA,OMIT,CANC" + }, + "example": "ARRI,CMPL" + }, + { + "name": "eventCreatedDateTime", + "in": "query", + "description": "Limit the result based on the creating date of the event. It is possible to use operators on this query parameter. This is done by adding a colon followed by an operator at the end of the queryParameterName (before the =)\n\neventCreatedDateTime:gte=2021-04-01T14:12:56+01:00\n\nwould result in all events created ≥ 2021-04-01T14:12:56+01:00\n\nThe following operators are supported\n- :gte (≥ Greater than or equal)\n- :gt (> Greater than)\n- :lte (≤ Less than or equal)\n- :lt (< Less than)\n- :eq (= Equal to)\n\nIf no operator is provided, a strictly equal is used (this is equivalent to :eq operator).\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/eventCreatedDateTime" + }, + "example": "2021-04-01T14:12:56+01:00" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of items to return.", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "format": "int32", + "default": 100 + }, + "example": 100 + }, + { + "name": "cursor", + "in": "query", + "description": "A server generated value to specify a specific point in a collection result, used for pagination.", + "required": false, + "schema": { + "type": "string" + }, + "example": "fE9mZnNldHw9MTAmbGltaXQ9MTA=" + }, + { + "name": "sort", + "in": "query", + "description": "A comma-separated list of field names to define the sort order. Field names should be suffixed by a (:) followed by either the keyword ASC (for ascending order) or DESC (for descening order) to specify direction. :ASC may be omitted, in which case ascending order will be used.\n", + "required": false, + "schema": { + "type": "string" + }, + "example": "carrierBookingReference:DESC" + }, + { + "name": "API-Version", + "in": "header", + "description": "An API-Version header MAY be added to the request (optional); if added it MUST only contain MAJOR version. API-Version header MUST be aligned with the URI version.\n", + "required": false, + "schema": { + "type": "string", + "example": "1" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "headers": { + "API-Version": { + "$ref": "#/components/headers/API-Version" + }, + "Current-Page": { + "$ref": "#/components/headers/Current-Page" + }, + "Next-Page": { + "$ref": "#/components/headers/Next-Page" + }, + "Prev-Page": { + "$ref": "#/components/headers/Prev-Page" + }, + "Last-Page": { + "$ref": "#/components/headers/Last-Page" + }, + "First-Page": { + "$ref": "#/components/headers/First-Page" + } + }, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/operationsEvent" + } + } + } + } + }, + "default": { + "description": "Unexpected error", + "headers": { + "API-Version": { + "$ref": "#/components/headers/API-Version" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/error" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "timestamp": { + "required": [ + "UNLocationCode", + "carrierServiceCode", + "carrierVoyageNumber", + "eventClassifierCode", + "eventDateTime", + "operationsEventTypeCode", + "publisher", + "publisherRole", + "vesselIMONumber" + ], + "type": "object", + "description": "A digital record of the time of occurrence of an Operations event\n", + "example": { + "publisher": { + "partyName": "Asseco Denmark", + "taxReference1": "CVR-25645774", + "taxReference2": "CVR-25645774", + "publicKey": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkFzaW", + "address": { + "name": "Henrik", + "street": "Kronprincessegade", + "streetNumber": "54", + "floor": "5. sal", + "postCode": "1306", + "city": "København", + "stateRegion": "N/A", + "country": "Denmark" + }, + "identifyingCodes": [ + { + "DCSAResponsibleAgencyCode": "SMDG", + "partyCode": "MSK", + "codeListName": "LCL" + } + ] + }, + "publisherRole": "CA", + "vesselIMONumber": "9321483", + "vessel": { + "vesselIMONumber": "9321483", + "name": "King of the Seas", + "lengthOverall": 245.45, + "width": 37.33, + "callSign": "NCVV", + "type": "CONT", + "draft": 12.5, + "dimensionUnit": "MTR" + }, + "carrierServiceCode": "FE1", + "carrierImportVoyageNumber": "2103N", + "carrierExportVoyageNumber": "2103S", + "portVisitReference": "NLRTM1234589", + "transportCallSequenceNumber": 2, + "vesselPosition": { + "locationName": "Port of Amsterdam", + "latitude": "52.4120", + "longitude": "4.8079" + }, + "UNLocationCode": "NLAMS", + "facilityTypeCode": "BRTH", + "eventLocation": { + "locationName": "Amsterdam Container Terminal", + "UNLocationCode": "NLAMS", + "facilityCode": "ACT", + "facilityCodeListProvider": "SMDG" + }, + "milesToDestinationPort": 0, + "eventClassifierCode": "ACT", + "operationsEventTypeCode": "STRT", + "portCallPhaseTypeCode": "SHIF", + "portCallServiceTypeCode": "PILO", + "eventDateTime": "2019-11-12T07:41:00+08:30", + "carrierVoyageNumber": "2103S" + }, + "allOf": [ + { + "type": "object", + "properties": { + "publisher": { + "allOf": [ + { + "$ref": "#/components/schemas/partyNoID" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "publisherRole": { + "allOf": [ + { + "$ref": "#/components/schemas/publisherRole" + }, + { + "example": "CA" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vesselIMONumber": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselIMONumber" + }, + { + "description": "The unique reference for a registered Vessel. The reference is the International Maritime Organisation (IMO) number, also sometimes known as the Lloyd's register code, which does not change during the lifetime of the vessel\n\nNB: vesselIMONumber is deprecated at the top level - vesselIMONumber needs to also be provided inside the vessel object.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vessel": { + "allOf": [ + { + "$ref": "#/components/schemas/vessel" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "carrierServiceCode": { + "allOf": [ + { + "$ref": "#/components/schemas/carrierServiceCode" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "importVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/importVoyageNumber" + }, + { + "description": "The identifier of an import voyage. The vessel operator-specific identifier of the import Voyage.\n\n**NB:** the importVoyageNumber is deprecated. Use `carrierImportVoyageNumber`.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "exportVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/exportVoyageNumber" + }, + { + "description": "The identifier of an export voyage. The vessel operator-specific identifier of the export Voyage.\n\n**NB:** the exportVoyageNumber is deprecated use `carrierExportVoyageNumber`.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "carrierImportVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/carrierImportVoyageNumber" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "carrierExportVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/carrierExportVoyageNumber" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "portVisitReference": { + "allOf": [ + { + "$ref": "#/components/schemas/portVisitReference" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "transportCallSequenceNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/transportCallSequenceNumber" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vesselPosition": { + "allOf": [ + { + "$ref": "#/components/schemas/geoLocation" + }, + { + "example": { + "locationName": "Port of Amsterdam", + "latitude": "52.4120", + "longitude": "4.8079" + } + } + ] + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "allOf": [ + { + "$ref": "#/components/schemas/UNLocationCode" + }, + { + "description": "The **UN Location Code** specifying where the Facility is located.\n" + }, + { + "example": "NLAMS" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilitySMDGCode": { + "allOf": [ + { + "$ref": "#/components/schemas/facilityCode" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilitySMDGCode": { + "allOf": [ + { + "description": "The SMDG code used for identifying the specific facility. This code does not include the UN Location Code.\n\nNB: facilitySMDGCode is deprecated - facilityCode together with facilityCodeListProvider in the eventLocation object should be used instead.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilityTypeCode": { + "allOf": [ + { + "$ref": "#/components/schemas/facilityTypeCodeOPR" + }, + { + "description": "A specialized version of the facilityCode to be used in Operations events. The code to identify the specific type of facility.\n\n- PBPL (Pilot boarding place)\n- BRTH (Berth)\n- ANCH (Anchorage)\n\nMore details can be found on [GitHub](https://github.com/dcsaorg/DCSA-Information-Model/blob/master/datamodel/referencedata.d/facilitytypes.csv).\n\n**NB:** This is a conditional field and is connected to `portCallServiceTypeCode`. Please check the IFS for allowed combinations.\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "eventLocation": { + "anyOf": [ + { + "$ref": "#/components/schemas/unLocationLocation" + }, + { + "$ref": "#/components/schemas/facilitySMDGLocation" + }, + { + "$ref": "#/components/schemas/geoLocation" + }, + { + "$ref": "#/components/schemas/addressLocation" + }, + { + "$ref": "#/components/schemas/facilityLocation" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "eventLocation": { + "description": "General purpose object to capture the location in the `timestamp`. The location can be specified in **any** of the following ways: `UN Location Code`, `FacilitySMDG` or `Geo Location`. In addition to the above `Address` and `Facility` should only be used when the terminal/location cannot be expressed using a **SMDG** code but needs an **Address** or **BIC** code\n", + "example": { + "locationName": "Amsterdam Container Terminal", + "UNLocationCode": "NLAMS", + "facilityCode": "ACT", + "facilityCodeListProvider": "SMDG" + } + } + } + }, + { + "type": "object", + "properties": { + "milesToDestinationPort": { + "allOf": [ + { + "$ref": "#/components/schemas/milesToDestinationPort" + }, + { + "example": 0 + } + ] + } + } + }, + { + "type": "object", + "properties": { + "eventClassifierCode": { + "allOf": [ + { + "$ref": "#/components/schemas/eventClassifierCode" + }, + { + "description": "Code for the event classifier.\n\n- PLN (Planned)\n- ACT (Actual)\n- REQ (Requested)\n- EST (Estimated)\n\nMore details can be found on [GitHub](https://github.com/dcsaorg/DCSA-Information-Model/blob/master/datamodel/referencedata.d/eventclassifiercodes.csv).\n\n**NB:** This is a conditional field and must match timestamps defined in the IFS\n" + }, + { + "type": "string", + "enum": [ + "PLN", + "ACT", + "REQ", + "EST" + ] + }, + { + "example": "ACT" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "operationsEventTypeCode": { + "allOf": [ + { + "$ref": "#/components/schemas/operationsEventTypeCode" + }, + { + "description": "The code to identify the type of event that is related to the operation\n- STRT (Started)\n- CMPL (Completed)\n- ARRI (Arrived)\n- DEPA (Departed)\n- OMIT (Omitted)\n- CANC (Cancelled)\n\nMore details can be found on [GitHub](https://github.com/dcsaorg/DCSA-Information-Model/blob/master/datamodel/referencedata.d/operationseventtypecodes.csv).\n\n**NB:** This is a conditional field and has to be aligned with other fields such as `portCallServiceTypeCode`. One such example is if `portCallServiceTypeCode` is **not** null then `operationsEventTypeCode` **should** be either: STRT (Started), COMP (Completed) or CANC (Cancelled). If `portCallServiceTypeCode` **is** null then `operationsEventTypeCode` is one of: ARRI (Arrived), DEPA (Departed) or OMIT (Omitted). Please check the IFS for allowed combinations.\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "modeOfTransport": { + "allOf": [ + { + "$ref": "#/components/schemas/modeOfTransport" + }, + { + "description": "**NB:** this field is marked deprecated since the standard is only defined for `VESSEL` and therefore redundant.\n\nJIT 1.0 and JIT 1.1 timestamps have used this field to differentiate timestamps. Since JIT 1.2 this is no longer needed except for 1 pair of JIT 1.1 timestamps that JIT 1.2 still needs for the sake of backward compatability. These timestamps have the portCallServiceTypeCode set to SAFE.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "portCallPhaseTypeCode": { + "allOf": [ + { + "$ref": "#/components/schemas/portCallPhaseTypeCode" + }, + { + "description": "The general direction of the vessel for which information applies\n- INBD (Inbound)\n- ALGS (Alongside)\n- SHIF (Shifting)\n- OUTB (Outbound)\n\nMore details can be found on [GitHub](https://github.com/dcsaorg/DCSA-Information-Model/blob/master/datamodel/referencedata.d/portcallphasetypecodes.csv).\n\n**NB:** This is a conditional field and must match timestamps according to the IFS. Please be aware that JIT 1.0 does not know about this field. Server implementations are expected to map this to a valid timestamp. If `portCallServiceTypeCode` is `PILO` (Pilotage) and `portCallPhaseTypeCode` is Null then `portCallPhaseTypeCode` can be set to `INBD` (Inbound).\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "portCallServiceTypeCode": { + "allOf": [ + { + "$ref": "#/components/schemas/portCallServiceTypeCode" + }, + { + "description": "The type of the service provided in the port call\n- PILO (Pilotage)\n- MOOR (Mooring)\n- CRGO (Cargo operations)\n- TOWG (Towage)\n- BUNK (Bunkering)\n- LASH (Lashing)\n- SAFE (Safety)\n- FAST (All Fast)\n- GWAY (Gangway down and secure)\n- ANCO (Anchorage operations)\n- SLUG (Sludge)\n- SHPW (Shore Power)\n- LCRO (Loading cargo operations)\n- DCRO (Discharge cargo operations)\n- VRDY (Vessel ready)\n\nMore details can be found on [GitHub](https://github.com/dcsaorg/DCSA-Information-Model/blob/master/datamodel/referencedata.d/portcallservicetypecodes.csv).\n\n**NB:** This is a conditional field and must match timestamps defined in the IFS\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "eventDateTime": { + "allOf": [ + { + "$ref": "#/components/schemas/eventDateTime" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "carrierVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/carrierVoyageNumber" + }, + { + "deprecated": true + }, + { + "description": "The vessel operator-specific identifier of the Voyage.\n\n**Deprecated:** Use `carrierExportVoyageNumber` and/or `carrierImportVoyageNumber` instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "delayReasonCode": { + "allOf": [ + { + "$ref": "#/components/schemas/delayReasonCode" + }, + { + "example": "STR" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "remark": { + "allOf": [ + { + "$ref": "#/components/schemas/remark" + } + ] + } + } + } + ] + }, + "partyNoID": { + "type": "object", + "description": "refers to a company or a legal entity.", + "allOf": [ + { + "type": "object", + "properties": { + "partyName": { + "$ref": "#/components/schemas/partyName" + } + } + }, + { + "type": "object", + "properties": { + "taxReference1": { + "$ref": "#/components/schemas/taxReference1" + } + } + }, + { + "type": "object", + "properties": { + "taxReference2": { + "$ref": "#/components/schemas/taxReference2" + } + } + }, + { + "type": "object", + "properties": { + "publicKey": { + "$ref": "#/components/schemas/publicKey" + } + } + }, + { + "type": "object", + "properties": { + "address": { + "allOf": [ + { + "$ref": "#/components/schemas/address" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "identifyingCodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/identifyingCode" + } + } + } + }, + { + "type": "object", + "properties": { + "nmftaCode": { + "allOf": [ + { + "$ref": "#/components/schemas/nmftaCode" + }, + { + "deprecated": true + }, + { + "description": "The Standard Carrier Alpha Code (SCAC) provided by NMFTA.

Deprecated: Replaced by DCSAResponsibleAgencyCode and partyCode defined in the identifyingCodes list" + } + ] + } + } + } + ] + }, + "partyName": { + "maxLength": 100, + "type": "string", + "description": "Name of the party.", + "example": "Asseco Denmark" + }, + "taxReference1": { + "maxLength": 20, + "type": "string", + "description": "The identifying number of the consignee or shipper (Individual or entity) used for tax purposes.", + "example": "CVR-25645774" + }, + "taxReference2": { + "maxLength": 20, + "type": "string", + "description": "Optional second identifying number of the consignee or shipper (Individual or entity) used for tax purposes.", + "example": "CVR-25645774" + }, + "publicKey": { + "maxLength": 500, + "type": "string", + "description": "The public key used for a digital signature.", + "example": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkFzaW" + }, + "address": { + "type": "object", + "description": "An object for storing address related information", + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "$ref": "#/components/schemas/addressName" + } + } + }, + { + "type": "object", + "properties": { + "street": { + "$ref": "#/components/schemas/streetName" + } + } + }, + { + "type": "object", + "properties": { + "streetNumber": { + "$ref": "#/components/schemas/streetNumber" + } + } + }, + { + "type": "object", + "properties": { + "floor": { + "$ref": "#/components/schemas/floor" + } + } + }, + { + "type": "object", + "properties": { + "postCode": { + "$ref": "#/components/schemas/postCode" + } + } + }, + { + "type": "object", + "properties": { + "city": { + "$ref": "#/components/schemas/cityName" + } + } + }, + { + "type": "object", + "properties": { + "stateRegion": { + "$ref": "#/components/schemas/stateRegion" + } + } + }, + { + "type": "object", + "properties": { + "country": { + "$ref": "#/components/schemas/country" + } + } + } + ] + }, + "addressName": { + "maxLength": 100, + "type": "string", + "description": "Name of the address", + "example": "Henrik" + }, + "streetName": { + "maxLength": 100, + "type": "string", + "description": "The name of the street of the party’s address.", + "example": "Kronprincessegade" + }, + "streetNumber": { + "maxLength": 50, + "type": "string", + "description": "The number of the street of the party’s address.", + "example": "54" + }, + "floor": { + "maxLength": 50, + "type": "string", + "description": "The floor of the party’s street number.", + "example": "5. sal" + }, + "postCode": { + "maxLength": 10, + "type": "string", + "description": "The post code of the party’s address.", + "example": "1306" + }, + "cityName": { + "maxLength": 65, + "type": "string", + "description": "The city name of the party’s address.", + "example": "København" + }, + "stateRegion": { + "maxLength": 65, + "type": "string", + "description": "The state/region of the party’s address.", + "example": "N/A" + }, + "country": { + "maxLength": 75, + "type": "string", + "description": "The country of the party’s address.", + "example": "Denmark" + }, + "identifyingCode": { + "required": [ + "DCSAResponsibleAgencyCode", + "partyCode" + ], + "type": "object", + "allOf": [ + { + "type": "object", + "properties": { + "codeListResponsibleAgencyCode": { + "$ref": "#/components/schemas/codeListResponsibleAgencyCode" + } + } + }, + { + "type": "object", + "properties": { + "DCSAResponsibleAgencyCode": { + "$ref": "#/components/schemas/DCSAResponsibleAgencyCode" + } + } + }, + { + "type": "object", + "properties": { + "partyCode": { + "$ref": "#/components/schemas/partyCode" + } + } + }, + { + "type": "object", + "properties": { + "codeListName": { + "$ref": "#/components/schemas/codeListName" + } + } + } + ] + }, + "codeListResponsibleAgencyCode": { + "type": "string", + "description": "UN/CEFACT codes for code list providers:\n- 5 (ISO)\n- 6 (UN/ECE)\n- 11 (Lloyd's register of shipping)\n- 20 (BIC (Bureau International des Containeurs)\n- 54 (IMO (incl. IMDG))\n- 182 (Standard Carrier Alpha Code (SCAC))\n- 274 (ITIGG)\n- 296 (ITU)\n- 306 (SMDG)\n- 399 (EXIS)\n- zzz (Mutually defined)\n\nDeprecated: Use DCSAResponsibleAgencyCode instead\n", + "example": "306", + "deprecated": true, + "enum": [ + "5", + "6", + "11", + "20", + "54", + "182", + "274", + "296", + "306", + "399", + "zzz" + ] + }, + "DCSAResponsibleAgencyCode": { + "type": "string", + "description": "A DCSA provided code for UN/CEFACT code list providers:\n- ISO\n- UNECE\n- LLOYD (Lloyd's register of shipping)\n- BIC (Bureau International des Containeurs)\n- IMO\n- SCAC (Standard Carrier Alpha Code)\n- ITIGG\n- ITU\n- SMDG\n- EXIS\n- FMC (Federal Maritime Commission)\n- CBSA (Canada Border Services Agency)\n- ZZZ (Mutually defined)\n", + "example": "SMDG", + "enum": [ + "ISO", + "UNECE", + "LLOYD", + "BIC", + "IMO", + "SCAC", + "ITIGG", + "ITU", + "SMDG", + "EXIS", + "FMC", + "CBSA", + "ZZZ" + ] + }, + "partyCode": { + "maxLength": 100, + "type": "string", + "description": "Code to identify the party as provided by the agency\n", + "example": "MSK" + }, + "codeListName": { + "maxLength": 100, + "type": "string", + "description": "The name of the list, provided by the responsible agency\n", + "example": "LCL" + }, + "nmftaCode": { + "maxLength": 4, + "type": "string", + "description": "The Standard Carrier Alpha Code (SCAC) provided by NMFTA.", + "example": "MMCU" + }, + "publisherRole": { + "type": "string", + "description": "The party function code of the publisher. The values are divided into 4 categories:\n\n#### Carrier\n- CA (Carrier)\n- AG (Carrier local agent)\n- VSL (Vessel)\n\n#### Port\n- ATH (Port Authorities)\n- PLT (Port Pilot)\n- TWG (Towage service provider)\n- MOR (Mooring service provider)\n\n#### Terminal\n- TR (Terminal)\n\n#### Service Provider\n- LSH (Lashing service provider)\n- BUK (Bunker service provider)\n- SLU (Sludge service provider)\n- SVP (Any other service provider)\n\nMore details can be found on GitHub\n", + "example": "TR", + "enum": [ + "CA", + "AG", + "VSL", + "ATH", + "PLT", + "TWG", + "MOR", + "TR", + "LSH", + "BUK", + "SLU", + "SVP" + ] + }, + "vesselIMONumber": { + "maxLength": 7, + "type": "string", + "description": "The unique reference for a registered Vessel. The reference is the International Maritime Organisation (IMO) number, also sometimes known as the Lloyd's register code, which does not change during the lifetime of the vessel\n", + "example": "9321483" + }, + "vessel": { + "required": [ + "vesselIMONumber" + ], + "type": "object", + "description": "A floating, sea going structure (mother vessels and feeder vessels) with either an internal or external mode of propulsion designed for the transport of cargo and/or passengers. Ocean vessels are uniquely identified by an IMO number consisting of 7 digits.\n", + "allOf": [ + { + "type": "object", + "properties": { + "vesselIMONumber": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselIMONumber" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "name": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselName" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "lengthOverall": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselLOA" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "width": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselWidth" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "callSign": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselCallSign" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselType" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "draft": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselDraft" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "dimensionUnit": { + "allOf": [ + { + "$ref": "#/components/schemas/dimensionUnit" + } + ] + } + } + } + ] + }, + "vesselName": { + "maxLength": 35, + "type": "string", + "description": "The name of the Vessel given by the Vessel Operator and registered with IMO.\n", + "example": "King of the Seas" + }, + "vesselLOA": { + "type": "number", + "description": "The maximum length of a ship's hull measured parallel to the waterline (Length OverAll).\n\nIf the length is specified in feet (`FOT`) then the decimal part should be concidered as a fraction of a foot and **not** as a number of inches. E.g. 120.5 feet means 120 and a half foot (which would be 120'6\")\n", + "format": "float", + "example": 245.45 + }, + "vesselWidth": { + "type": "number", + "description": "Overall width of the ship measured at the widest point of the nominal waterline.\n\nIf the width is specified in feet (`FOT`) then the decimal part should be concidered as a fraction of a foot and **not** as a number of inches. E.g. 120.5 feet means 120 and a half foot (which would be 120'6\")\n", + "format": "float", + "example": 37.33 + }, + "vesselCallSign": { + "maxLength": 10, + "type": "string", + "description": "A unique alphanumeric identity that belongs to the vessel and is assigned by the International Telecommunication Union (ITU). It consists of a threeletter alphanumeric prefix that indicates nationality, followed by one to four characters to identify the individual vessel. For instance, vessels registered under Denmark are assigned the prefix ranges 5PA-5QZ, OUAOZZ, and XPA-XPZ. The Call Sign changes whenever a vessel changes its flag.\n", + "example": "NCVV" + }, + "vesselType": { + "type": "string", + "description": "Categorization of ocean-going vessels distinguished by the main cargo the vessel carries. Possible values:\n- GCGO (General cargo)\n- CONT (Container)\n- RORO (RoRo)\n- CARC (Car carrier)\n- PASS (Passenger)\n- FERY (Ferry)\n- BULK (Bulk)\n- TANK (Tanker)\n- LGTK (Liquefied gas tanker)\n- ASSI (Assistance)\n- PILO (Pilot boat)\n", + "example": "CONT", + "enum": [ + "GCGO", + "CONT", + "RORO", + "CARC", + "PASS", + "FERY", + "BULK", + "TANK", + "LGTK", + "ASSI", + "PILO" + ] + }, + "vesselDraft": { + "type": "number", + "description": "The actual draft of the vessel.\n\nIf the draft is specified in feet (`FOT`) then the decimal part should be concidered as a fraction of a foot and **not** as a number of inches. E.g. 120.5 feet means 120 and a half foot (which would be 120'6\")\n", + "format": "float", + "example": 12.5 + }, + "dimensionUnit": { + "type": "string", + "description": "The unit of measure which can be expressed in\n- MTR (Meter)\n- FOT (Foot)\n", + "example": "MTR", + "enum": [ + "MTR", + "FOT" + ] + }, + "carrierServiceCode": { + "maxLength": 5, + "type": "string", + "description": "The Carrier specific code of the service for which the schedule details are published.\n", + "example": "FE1" + }, + "importVoyageNumber": { + "maxLength": 50, + "type": "string", + "description": "The identifier of an import voyage. The vessel operator-specific identifier of the import Voyage.\n", + "example": "2103N" + }, + "exportVoyageNumber": { + "maxLength": 50, + "type": "string", + "description": "The identifier of an export voyage. The vessel operator-specific identifier of the export Voyage.\n", + "example": "2103S" + }, + "carrierImportVoyageNumber": { + "maxLength": 50, + "type": "string", + "description": "The identifier of an import voyage. The vessel operator-specific identifier of the import Voyage.\n", + "example": "2103N" + }, + "carrierExportVoyageNumber": { + "maxLength": 50, + "type": "string", + "description": "The identifier of an export voyage. The vessel operator-specific identifier of the export Voyage.\n", + "example": "2103S" + }, + "portVisitReference": { + "maxLength": 50, + "type": "string", + "description": "The unique reference that can be used to link different `transportCallReferences` to the same port visit. The reference is provided by the port to uniquely identify a port call\n", + "example": "NLRTM1234589" + }, + "transportCallSequenceNumber": { + "type": "integer", + "description": "Transport operator's key that uniquely identifies each individual call. This key is essential to distinguish between two separate calls at the same location within one voyage.\n", + "format": "int32", + "example": 2 + }, + "geoLocation": { + "required": [ + "latitude", + "longitude" + ], + "type": "object", + "description": "An interface used to express a location using `latitude` and `longitude`\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "latitude": { + "$ref": "#/components/schemas/latitude" + } + } + }, + { + "type": "object", + "properties": { + "longitude": { + "$ref": "#/components/schemas/longitude" + } + } + } + ] + }, + "locationName": { + "maxLength": 100, + "type": "string", + "description": "The name of the location.", + "example": "Port of Amsterdam" + }, + "latitude": { + "maxLength": 10, + "type": "string", + "description": "Geographic coordinate that specifies the north–south position of a point on the Earth's surface.", + "example": "48.8585500" + }, + "longitude": { + "maxLength": 11, + "type": "string", + "description": "Geographic coordinate that specifies the east–west position of a point on the Earth's surface.", + "example": "2.294492036" + }, + "UNLocationCode": { + "maxLength": 5, + "type": "string", + "description": "The UN Location code specifying where the place is located.", + "example": "FRPAR" + }, + "facilityCode": { + "maxLength": 6, + "type": "string", + "description": "The code used for identifying the specific facility. This code does not include the UN Location Code.\n", + "nullable": false, + "example": "ADT" + }, + "facilityTypeCodeOPR": { + "type": "string", + "description": "A specialized version of the facilityCode to be used in Operations events. The code to identify the specific type of facility.\n- PBPL (Pilot boarding place)\n- BRTH (Berth)\n- ANCH (Anchorage Location)\n", + "example": "BRTH", + "enum": [ + "PBPL", + "BRTH", + "ANCH" + ] + }, + "unLocationLocation": { + "required": [ + "UNLocationCode" + ], + "type": "object", + "description": "An interface used to express a location using a `Un Location Code`\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "$ref": "#/components/schemas/UNLocationCode" + } + } + } + ] + }, + "facilitySMDGLocation": { + "required": [ + "UNLocationCode", + "facilitySMDGCode" + ], + "type": "object", + "description": "An interface used to express a location using a `Facility` by the `SMDG` code list. The `facilitySMDGCode` does not contain the `UNLocationCode` - this should be provided in the `UnLocationCode` attribute.\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "$ref": "#/components/schemas/UNLocationCode" + } + } + }, + { + "type": "object", + "properties": { + "facilitySMDGCode": { + "$ref": "#/components/schemas/facilityCode" + } + } + } + ] + }, + "addressLocation": { + "required": [ + "address" + ], + "type": "object", + "description": "An interface used to express a location using an `Address` object\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "address": { + "description": "Address related information", + "allOf": [ + { + "$ref": "#/components/schemas/address_1" + } + ] + } + } + } + ] + }, + "address_1": { + "type": "object", + "description": "An object for storing address related information\n", + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "$ref": "#/components/schemas/addressName" + } + } + }, + { + "type": "object", + "properties": { + "street": { + "$ref": "#/components/schemas/streetName" + } + } + }, + { + "type": "object", + "properties": { + "streetNumber": { + "$ref": "#/components/schemas/streetNumber" + } + } + }, + { + "type": "object", + "properties": { + "floor": { + "$ref": "#/components/schemas/floor" + } + } + }, + { + "type": "object", + "properties": { + "postCode": { + "$ref": "#/components/schemas/postCode_1" + } + } + }, + { + "type": "object", + "properties": { + "city": { + "$ref": "#/components/schemas/cityName" + } + } + }, + { + "type": "object", + "properties": { + "stateRegion": { + "$ref": "#/components/schemas/stateRegion" + } + } + }, + { + "type": "object", + "properties": { + "country": { + "$ref": "#/components/schemas/country" + } + } + } + ] + }, + "postCode_1": { + "maxLength": 50, + "type": "string", + "description": "The post code of the party’s address.", + "example": "1306" + }, + "facilityLocation": { + "required": [ + "facilityCode", + "facilityCodeListProvider" + ], + "type": "object", + "description": "An interface used to express a location using a `Facility`. The facility can either be expressed using a `BIC` code or a `SMDG` code. The `facilityCode` does not contain the `UNLocationCode` - this should be provided in the `UnLocationCode` attribute.\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "allOf": [ + { + "$ref": "#/components/schemas/UNLocationCode" + }, + { + "description": "The UN Location code specifying where the place is located. This field is conditionally mandatory depending on the value of the `facilityCodeListProvider` field.\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilityCode": { + "$ref": "#/components/schemas/facilityCode" + } + } + }, + { + "type": "object", + "properties": { + "facilityCodeListProvider": { + "$ref": "#/components/schemas/facilityCodeListProvider" + } + } + } + ] + }, + "facilityCodeListProvider": { + "type": "string", + "description": "The provider used for identifying the facility Code. Some facility codes are only defined in combination with an `UN Location Code`\n- BIC (Requires a UN Location Code)\n- SMDG (Requires a UN Location Code)\n", + "example": "SMDG", + "enum": [ + "BIC", + "SMDG" + ] + }, + "milesToDestinationPort": { + "type": "number", + "description": "Remaining distance reported by the vessel to the next destination port in nautical miles \n", + "format": "float", + "example": 245.45 + }, + "eventClassifierCode": { + "type": "string", + "description": "Code for the event classifier. Values can vary depending on eventType\n" + }, + "operationsEventTypeCode": { + "type": "string", + "description": "The code to identify the type of event that is related to the operation\n- STRT (Started)\n- CMPL (Completed)\n- ARRI (Arrived)\n- DEPA (Departed)\n- OMIT (Omitted)\n- CANC (Cancelled)\n\nMore details can be found on GitHub\n", + "example": "STRT", + "enum": [ + "STRT", + "CMPL", + "ARRI", + "DEPA", + "OMIT", + "CANC" + ] + }, + "modeOfTransport": { + "type": "string", + "description": "The mode of transport as defined by DCSA.\n", + "enum": [ + "VESSEL", + "RAIL", + "TRUCK", + "BARGE" + ] + }, + "portCallPhaseTypeCode": { + "type": "string", + "description": "The general direction of the vessel for which information applies\n- INBD (Inbound)\n- ALGS (Alongside)\n- SHIF (Shifting)\n- OUTB (Outbound)\n\nMore details can be found on GitHub\n", + "example": "ALGS", + "enum": [ + "INBD", + "ALGS", + "SHIF", + "OUTB" + ] + }, + "portCallServiceTypeCode": { + "type": "string", + "description": "The type of the service provided in the port call\n- PILO (Pilotage)\n- MOOR (Mooring)\n- CRGO (Cargo operations)\n- TOWG (Towage)\n- BUNK (Bunkering)\n- LASH (Lashing)\n- SAFE (Safety)\n- FAST (All Fast)\n- GWAY (Gangway down and secure)\n- ANCO (Anchorage operations)\n- SLUG (Sludge)\n- SHPW (Shore Power)\n- LCRO (Loading cargo operations)\n- DCRO (Discharge cargo operations)\n- VRDY (Vessel ready)\n\nMore details can be found on GitHub\n", + "example": "BUNK", + "enum": [ + "PILO", + "MOOR", + "CRGO", + "TOWG", + "BUNK", + "LASH", + "SAFE", + "FAST", + "GWAY", + "ANCO", + "SLUG", + "SHPW", + "LCRO", + "DCRO", + "VRDY" + ] + }, + "eventDateTime": { + "type": "string", + "description": "The local date and time, where the event took place or when the event will take place, in ISO 8601 format.", + "format": "date-time", + "example": "2019-11-12T07:41:00+08:30" + }, + "carrierVoyageNumber": { + "maxLength": 50, + "type": "string", + "description": "The vessel operator-specific identifier of the Voyage.", + "example": "2103S" + }, + "delayReasonCode": { + "maxLength": 3, + "type": "string", + "description": "Reason code for the delay. See SMDG [Code list DELAY](https://smdg.org/documents/smdg-code-lists/delay-reason-and-port-call-activity/) for a list of valid codes to be used for this attribute.\n", + "example": "WEA" + }, + "remark": { + "maxLength": 500, + "type": "string", + "description": "Free text to provide additional information on the context.\n", + "example": "Port closed due to strike" + }, + "error": { + "required": [ + "errorDateTime", + "errors", + "httpMethod", + "requestUri", + "statusCode", + "statusCodeText" + ], + "type": "object", + "properties": { + "httpMethod": { + "type": "string", + "description": "The HTTP request method type", + "example": "POST" + }, + "requestUri": { + "type": "string", + "description": "The request URI.", + "example": "https://dcsa.org/dcsa/tnt/v1/events" + }, + "errors": { + "$ref": "#/components/schemas/subErrors" + }, + "statusCode": { + "type": "integer", + "description": "The HTTP status code", + "example": 400 + }, + "statusCodeText": { + "type": "string", + "description": "The textual representation of the response status.", + "example": "Bad Request" + }, + "errorDateTime": { + "type": "string", + "description": "The date and time (in ISO 8601 format) the error occurred.", + "format": "$date-time", + "example": "2019-11-12T07:41:00+08:30" + } + } + }, + "subErrors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/subErrors_inner" + } + }, + "transportCallID": { + "maxLength": 100, + "type": "string", + "description": "The unique identifier for a transport call", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "eventCreatedDateTime": { + "type": "string", + "description": "The timestamp of when the event was created.\n\nNB: This field should be considered Metadata\n", + "format": "date-time", + "example": "2021-01-09T14:12:56+01:00" + }, + "operationsEvents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/operationsEvent" + } + }, + "operationsEvent": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/baseEvent" + }, + { + "$ref": "#/components/schemas/baseOperationsEvent" + } + ] + }, + "baseEvent": { + "required": [ + "eventCreatedDateTime" + ], + "type": "object", + "allOf": [ + { + "type": "object", + "properties": { + "eventID": { + "$ref": "#/components/schemas/eventID" + } + } + }, + { + "type": "object", + "properties": { + "eventCreatedDateTime": { + "$ref": "#/components/schemas/eventCreatedDateTime" + } + } + }, + { + "$ref": "#/components/schemas/baseEventBody" + } + ] + }, + "eventID": { + "type": "string", + "description": "The unique identifier for the event (the message - not the source).\n\nNB: This field should be considered Metadata\n", + "format": "uuid", + "example": "3cecb101-7a1a-43a4-9d62-e88a131651e2" + }, + "baseEventBody": { + "required": [ + "eventClassifierCode", + "eventDateTime", + "eventType" + ], + "type": "object", + "description": "The Event entity is described as a generalization of all the specific event categories. An event always takes place in relation to a shipment and can additionally be linked to a transport or an equipment\n", + "allOf": [ + { + "type": "object", + "properties": { + "eventType": { + "$ref": "#/components/schemas/eventType" + } + } + }, + { + "type": "object", + "properties": { + "eventClassifierCode": { + "$ref": "#/components/schemas/eventClassifierCode" + } + } + }, + { + "type": "object", + "properties": { + "eventDateTime": { + "$ref": "#/components/schemas/eventDateTime" + } + } + } + ] + }, + "eventType": { + "type": "string", + "description": "The Event Type of the object - to be used as a discriminator.\n\nNB: This field should be considered Metadata\n" + }, + "baseOperationsEvent": { + "required": [ + "operationsEventTypeCode", + "publisher", + "publisherRole", + "transportCall" + ], + "type": "object", + "description": "The operations event entity is a specialization of the event entity to support specification of data that only applies to an operations event.\n", + "allOf": [ + { + "type": "object", + "properties": { + "eventType": { + "type": "string", + "example": "OPERATIONS", + "enum": [ + "OPERATIONS" + ] + } + } + }, + { + "type": "object", + "properties": { + "eventClassifierCode": { + "type": "string", + "description": "Code for the event classifier can be\n- ACT (Actual)\n- PLN (Planned)\n- EST (Estimated)\n- REQ (Requested)\n", + "example": "ACT", + "enum": [ + "ACT", + "PLN", + "EST", + "REQ" + ] + } + } + }, + { + "type": "object", + "properties": { + "operationsEventTypeCode": { + "$ref": "#/components/schemas/operationsEventTypeCode" + } + } + }, + { + "type": "object", + "properties": { + "publisher": { + "allOf": [ + { + "$ref": "#/components/schemas/partyNoID" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "publisherRole": { + "$ref": "#/components/schemas/publisherRole" + } + } + }, + { + "type": "object", + "properties": { + "eventLocation": { + "allOf": [ + { + "$ref": "#/components/schemas/location" + }, + { + "description": "The location where the event takes place." + } + ] + } + } + }, + { + "type": "object", + "properties": { + "portCallServiceTypeCode": { + "$ref": "#/components/schemas/portCallServiceTypeCode" + } + } + }, + { + "type": "object", + "properties": { + "portCallPhaseTypeCode": { + "$ref": "#/components/schemas/portCallPhaseTypeCode" + } + } + }, + { + "type": "object", + "properties": { + "facilityTypeCode": { + "$ref": "#/components/schemas/facilityTypeCodeOPR" + } + } + }, + { + "type": "object", + "properties": { + "delayReasonCode": { + "$ref": "#/components/schemas/delayReasonCode" + } + } + }, + { + "type": "object", + "properties": { + "remark": { + "$ref": "#/components/schemas/remark" + } + } + }, + { + "type": "object", + "properties": { + "transportCall": { + "$ref": "#/components/schemas/transportCall" + } + } + }, + { + "type": "object", + "properties": { + "vesselPosition": { + "allOf": [ + { + "$ref": "#/components/schemas/geoLocation" + }, + { + "description": "The position of the vessel at the time when the message was sent" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "milesToDestinationPort": { + "allOf": [ + { + "$ref": "#/components/schemas/milesToDestinationPort" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vesselDraft": { + "allOf": [ + { + "$ref": "#/components/schemas/vesselDraft" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vesselDraftUnit": { + "allOf": [ + { + "$ref": "#/components/schemas/dimensionUnit" + } + ] + } + } + } + ] + }, + "location": { + "type": "object", + "description": "General purpose object to capture location-related data, the location can be specified in **any** of the following ways: `geoLocation` (lat+long), `UN Location Code`, a `Facility` or an `Address`.\n\nIf multiple ways are used - then they all have to point to the same location!\n", + "allOf": [ + { + "type": "object", + "properties": { + "locationName": { + "$ref": "#/components/schemas/locationName" + } + } + }, + { + "type": "object", + "properties": { + "latitude": { + "$ref": "#/components/schemas/latitude" + } + } + }, + { + "type": "object", + "properties": { + "longitude": { + "$ref": "#/components/schemas/longitude" + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "$ref": "#/components/schemas/UNLocationCode" + } + } + }, + { + "type": "object", + "properties": { + "facilityCode": { + "$ref": "#/components/schemas/facilityCode" + } + } + }, + { + "type": "object", + "properties": { + "facilityCodeListProvider": { + "$ref": "#/components/schemas/facilityCodeListProvider" + } + } + }, + { + "type": "object", + "properties": { + "address": { + "description": "Address related information", + "allOf": [ + { + "$ref": "#/components/schemas/address_1" + } + ] + } + } + } + ] + }, + "transportCall": { + "required": [ + "modeOfTransport", + "transportCallID" + ], + "type": "object", + "allOf": [ + { + "type": "object", + "properties": { + "transportCallID": { + "$ref": "#/components/schemas/transportCallID" + } + } + }, + { + "type": "object", + "properties": { + "transportCallID": { + "description": "The unique identifier for a transport call\n\n**Deprecated:** Use `transportCallReference` instead\n" + } + } + }, + { + "type": "object", + "properties": { + "transportCallReference": { + "$ref": "#/components/schemas/transportCallReference" + } + } + }, + { + "type": "object", + "properties": { + "portVisitReference": { + "$ref": "#/components/schemas/portVisitReference" + } + } + }, + { + "type": "object", + "properties": { + "carrierServiceCode": { + "$ref": "#/components/schemas/carrierServiceCode" + } + } + }, + { + "type": "object", + "properties": { + "carrierVoyageNumber": { + "allOf": [ + { + "$ref": "#/components/schemas/carrierVoyageNumber" + }, + { + "description": "The vessel operator-specific identifier of the Voyage.\n\nIn case there are multiple voyages the export voyage is chosen.\n" + }, + { + "deprecated": true + } + ] + } + } + }, + { + "type": "object", + "properties": { + "exportVoyageNumber": { + "$ref": "#/components/schemas/exportVoyageNumber" + } + } + }, + { + "type": "object", + "properties": { + "exportVoyageNumber": { + "description": "The identifier of an export voyage. The vessel operator-specific identifier of the export Voyage.\n\n**Deprecated:** Use `carrierExportVoyageNumber` instead\n", + "deprecated": true + } + } + }, + { + "type": "object", + "properties": { + "carrierExportVoyageNumber": { + "$ref": "#/components/schemas/carrierExportVoyageNumber" + } + } + }, + { + "type": "object", + "properties": { + "importVoyageNumber": { + "$ref": "#/components/schemas/importVoyageNumber" + } + } + }, + { + "type": "object", + "properties": { + "importVoyageNumber": { + "description": "The identifier of an import voyage. The vessel operator-specific identifier of the import Voyage.\n\n**Deprecated:** Use `carrierImportVoyageNumber` instead\n", + "deprecated": true + } + } + }, + { + "type": "object", + "properties": { + "carrierImportVoyageNumber": { + "$ref": "#/components/schemas/carrierImportVoyageNumber" + } + } + }, + { + "type": "object", + "properties": { + "transportCallSequenceNumber": { + "$ref": "#/components/schemas/transportCallSequenceNumber" + } + } + }, + { + "type": "object", + "properties": { + "UNLocationCode": { + "allOf": [ + { + "$ref": "#/components/schemas/UNLocationCode" + }, + { + "deprecated": true + }, + { + "description": "The UN Location code specifying where the place is located.\n\n**Deprecated**: Use UN Location Code defined in the location object instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilityCode": { + "allOf": [ + { + "$ref": "#/components/schemas/facilityCode" + }, + { + "deprecated": true + }, + { + "description": "The code used for identifying the specific facility. This code does not include the UN Location Code.\n\n**Deprecated**: Use facilityCode defined in the location object instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilityCodeListProvider": { + "allOf": [ + { + "$ref": "#/components/schemas/facilityCodeListProvider" + }, + { + "deprecated": true + }, + { + "description": "The provider used for identifying the facility Code\n\n**Deprecated**: Use facilityCodeListProvider defined in the location object instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "facilityTypeCode": { + "allOf": [ + { + "$ref": "#/components/schemas/facilityTypeCodeTRN" + }, + { + "deprecated": true + }, + { + "description": "A specialized version of the facilityCode to be used in TransportCalls. The code to identify the specific type of facility.\n\n- BOCR (Border crossing)\n- CLOC (Customer location)\n- COFS (Container freight station)\n- COYA (Deprecated - use OFFD intead)\n- OFFD (Off dock storage)\n- DEPO (Depot)\n- INTE (Inland terminal)\n- POTE (Port terminal)\n- RAMP (Ramp)\n\n**Deprecated**: Use facilityTypeCode defined on Event root level instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "otherFacility": { + "allOf": [ + { + "$ref": "#/components/schemas/otherFacility" + }, + { + "deprecated": true + }, + { + "description": "An alternative way to capture the facility when no standardized DCSA facility code can be found.\n\n**Deprecated**: Use address object defined in the location object instead\n" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "modeOfTransport": { + "$ref": "#/components/schemas/modeOfTransport" + } + } + }, + { + "type": "object", + "properties": { + "location": { + "anyOf": [ + { + "$ref": "#/components/schemas/geoLocation" + }, + { + "$ref": "#/components/schemas/facilityLocation" + }, + { + "$ref": "#/components/schemas/unLocationLocation" + }, + { + "$ref": "#/components/schemas/addressLocation" + } + ] + } + } + }, + { + "type": "object", + "properties": { + "vessel": { + "$ref": "#/components/schemas/vessel_1" + } + } + } + ] + }, + "transportCallReference": { + "maxLength": 100, + "type": "string", + "description": "A carrier definied reference to a TransportCall.\n\nIn the case the Means of Transport is a `Vessel` and the facility is a `Port`/`Terminal` - this reference should be considered a **Terminal Call Reference**\n", + "example": "987e4567" + }, + "facilityTypeCodeTRN": { + "type": "string", + "description": "A specialized version of the facilityCode to be used in TransportCalls. The code to identify the specific type of facility.\n- BOCR (Border crossing)\n- CLOC (Customer location)\n- COFS (Container freight station)\n- COYA (Deprecated - use OFFD intead)\n- OFFD (Off dock storage)\n- DEPO (Depot)\n- INTE (Inland terminal)\n- POTE (Port terminal)\n- RAMP (Ramp)\n", + "example": "POTE", + "enum": [ + "BOCR", + "CLOC", + "COFS", + "COYA", + "OFFD", + "DEPO", + "INTE", + "POTE", + "RAMP" + ] + }, + "otherFacility": { + "maxLength": 50, + "type": "string", + "description": "An alternative way to capture the facility when no standardized DCSA facility code can be found.", + "example": "Depot location or address" + }, + "vessel_1": { + "required": [ + "vesselIMONumber" + ], + "type": "object", + "description": "describes a floating, sea going structure (mother vessels and feeder vessels) with either an internal or external mode of propulsion designed for the transport of cargo and/or passengers. Ocean vessels are uniquely identified by an IMO number consisting of 7 digits, or alternatively by their AIS signal with an MMSI number. \n", + "allOf": [ + { + "type": "object", + "properties": { + "vesselIMONumber": { + "$ref": "#/components/schemas/vesselIMONumber" + } + } + }, + { + "type": "object", + "properties": { + "vesselName": { + "$ref": "#/components/schemas/vesselName" + } + } + }, + { + "type": "object", + "properties": { + "vesselFlag": { + "$ref": "#/components/schemas/vesselFlag" + } + } + }, + { + "type": "object", + "properties": { + "vesselCallSignNumber": { + "$ref": "#/components/schemas/vesselCallSignNumber" + } + } + }, + { + "type": "object", + "properties": { + "vesselOperatorCarrierCode": { + "$ref": "#/components/schemas/vesselOperatorCarrierCode" + } + } + }, + { + "type": "object", + "properties": { + "vesselOperatorCarrierCodeListProvider": { + "$ref": "#/components/schemas/vesselOperatorCarrierCodeListProvider" + } + } + } + ] + }, + "vesselFlag": { + "maxLength": 2, + "type": "string", + "description": "The flag of the nation whose laws the vessel is registered under. This is the ISO 3166 two-letter country code\n", + "example": "DE" + }, + "vesselCallSignNumber": { + "maxLength": 10, + "type": "string", + "description": "A unique alphanumeric identity that belongs to the vessel and is assigned by the International Telecommunication Union (ITU). It consists of a threeletter alphanumeric prefix that indicates nationality, followed by one to four characters to identify the individual vessel. For instance, vessels registered under Denmark are assigned the prefix ranges 5PA-5QZ, OUAOZZ, and XPA-XPZ. The Call Sign changes whenever a vessel changes its flag.\n", + "example": "NCVV" + }, + "vesselOperatorCarrierCode": { + "maxLength": 10, + "type": "string", + "description": "The carrier who is in charge of the vessel operation based on either the SMDG or SCAC code lists\n", + "nullable": false, + "example": "MAEU" + }, + "vesselOperatorCarrierCodeListProvider": { + "type": "string", + "description": "Identifies the code list provider used for the operator and partner carriercodes.", + "nullable": false, + "example": "NMFTA", + "enum": [ + "SMDG", + "NMFTA" + ] + }, + "startDate": { + "type": "string", + "description": "The start date of the period for which schedule information is sent. The value is populated in `ISO 8601` Date format.", + "format": "date", + "example": "2020-04-06" + }, + "dateRange": { + "type": "string", + "description": "The time period for which schedule information is sent. The duration is populated in ISO 8601 Duration format.", + "format": "iso8601", + "example": "P4W" + }, + "subErrors_inner": { + "required": [ + "message", + "reason" + ], + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "High level error message.", + "example": "invalidQuery" + }, + "message": { + "type": "string", + "description": "Detailed error message.", + "example": "The request did not contain one of the three required query parameters." + } + } + } + }, + "parameters": { + "startDate": { + "name": "startDate", + "in": "query", + "description": "The start date of the period for which schedule information is requested. The value is populated in ISO 8601 Date format. If not provided, the current date is used by default.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "$ref": "#/components/schemas/startDate" + } + }, + "dateRange": { + "name": "dateRange", + "in": "query", + "description": "The time period for which schedule information is sent. The duration is populated in ISO 8601 Duration format.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "$ref": "#/components/schemas/dateRange" + } + }, + "Api-Version-Major": { + "name": "API-Version", + "in": "header", + "description": "An API-Version header MAY be added to the request (optional); if added it MUST only contain MAJOR version. API-Version header MUST be aligned with the URI version.\n", + "required": false, + "schema": { + "type": "string", + "example": "1" + } + }, + "transportCallID": { + "name": "transportCallID", + "in": "query", + "description": "ID uniquely identifying a transport call, to filter events by.\n\nSpecifying this filter will only return events related to this particular transportCallID\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/transportCallID" + } + }, + "vesselIMONumber": { + "name": "vesselIMONumber", + "in": "query", + "description": "The identifier of vessel for which schedule details are published. Depending on schedule type, this may not be available yet.\n\nSpecifying this filter will only return events related to this particular vesselIMONumber.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/vesselIMONumber" + } + }, + "carrierVoyageNumber": { + "name": "carrierVoyageNumber", + "in": "query", + "description": "Filter on the vessel operator-specific identifier of the Voyage.\n\nSpecifying this filter will only return events related to this particular carrierVoyageNumber.\n\nDeprecated: Use exportVoyageNumber instead\n", + "required": false, + "deprecated": true, + "schema": { + "$ref": "#/components/schemas/carrierVoyageNumber" + } + }, + "exportVoyageNumber": { + "name": "exportVoyageNumber", + "in": "query", + "description": "Filter on the vessel operator-specific identifier of the export Voyage.\n\nSpecifying this filter will only return events related to this particular exportVoyageNumber.\n\n**Deprecated:** Use carrierExportVoyageNumber instead\n", + "required": false, + "deprecated": true, + "schema": { + "$ref": "#/components/schemas/exportVoyageNumber" + } + }, + "carrierServiceCode": { + "name": "carrierServiceCode", + "in": "query", + "description": "Filter on the carrier specific identifier of the service.\n\nSpecifying this filter will only return events related to this particular carrierServiceCode.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/carrierServiceCode" + } + }, + "UNLocationCode": { + "name": "UNLocationCode", + "in": "query", + "description": "The UN Location code specifying where the place is located.\n\nSpecifying this filter will only return events related to this particular UN Location code.\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/UNLocationCode" + } + }, + "operationsEventTypeCode": { + "name": "operationsEventTypeCode", + "in": "query", + "description": "The code to identify the type of event that is related to the operation\n- STRT (Started)\n- CMPL (Completed)\n- ARRI (Arrived)\n- DEPA (Departed)\n- OMIT (Omitted)\n- CANC (Cancelled)\n\nIt is possible to select multiple values by comma (,) separating them. For multiple values the OR-operator is used. For example operationsEventTypeCode=ARRI,CMPL matches both Arrived (ARRI) and Completed (CMPL) operations events.\n\nDefault is all operationsEventTypeCodes.\n", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/operationsEventTypeCode" + }, + "default": "STRT,CMPL,ARRI,DEPA,OMIT,CANC" + }, + "example": "ARRI,CMPL" + }, + "eventCreatedDateTime": { + "name": "eventCreatedDateTime", + "in": "query", + "description": "Limit the result based on the creating date of the event. It is possible to use operators on this query parameter. This is done by adding a colon followed by an operator at the end of the queryParameterName (before the =)\n\neventCreatedDateTime:gte=2021-04-01T14:12:56+01:00\n\nwould result in all events created ≥ 2021-04-01T14:12:56+01:00\n\nThe following operators are supported\n- :gte (≥ Greater than or equal)\n- :gt (> Greater than)\n- :lte (≤ Less than or equal)\n- :lt (< Less than)\n- :eq (= Equal to)\n\nIf no operator is provided, a strictly equal is used (this is equivalent to :eq operator).\n", + "required": false, + "schema": { + "$ref": "#/components/schemas/eventCreatedDateTime" + }, + "example": "2021-04-01T14:12:56+01:00" + }, + "limit": { + "name": "limit", + "in": "query", + "description": "Maximum number of items to return.", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "format": "int32", + "default": 100 + }, + "example": 100 + }, + "cursor": { + "name": "cursor", + "in": "query", + "description": "A server generated value to specify a specific point in a collection result, used for pagination.", + "required": false, + "schema": { + "type": "string" + }, + "example": "fE9mZnNldHw9MTAmbGltaXQ9MTA=" + }, + "sort": { + "name": "sort", + "in": "query", + "description": "A comma-separated list of field names to define the sort order. Field names should be suffixed by a (:) followed by either the keyword ASC (for ascending order) or DESC (for descening order) to specify direction. :ASC may be omitted, in which case ascending order will be used.\n", + "required": false, + "schema": { + "type": "string" + }, + "example": "carrierBookingReference:DESC" + } + }, + "headers": { + "API-Version": { + "description": "SemVer used to indicate the version of the contract (API version) returned.", + "schema": { + "type": "string", + "example": "1.0.0" + } + }, + "Current-Page": { + "description": "A link to the current page.", + "required": true, + "schema": { + "type": "string", + "example": "fE9mZnNldHw9MCZsaW1pdD01" + } + }, + "Next-Page": { + "description": "A link to the next page. Next-Page header link MAY be omitted if the current page is the last page.", + "required": false, + "schema": { + "type": "string", + "example": "fE9mZnNldHw9NSZsaW1pdD01" + } + }, + "Prev-Page": { + "description": "A link to the previous page. Previous-Page header link MAY be omitted if the current page is the first page.", + "required": false, + "schema": { + "type": "string", + "example": "fE9mZnNldHw9MCZsaW1pdD01" + } + }, + "Last-Page": { + "description": "A link to the last page. Last-Page header link MAY be omitted if the current page is the last page.", + "required": false, + "schema": { + "type": "string", + "example": "fE9mZnNldHw9NTkmbGltaXQ9NQ==" + } + }, + "First-Page": { + "description": "A link to thefirst page. First-Page header link MAY be omitted if current page is the first page.", + "required": false, + "schema": { + "type": "string", + "example": "fE9mZnNldHw9NjAmbGltaXQ9NQ==" + } + } + } + } +} diff --git a/pom.xml b/pom.xml index cc7ce8fb..be8cd7bf 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ ebl ebl-issuance ebl-surrender + jit ovs tnt cdk diff --git a/sandbox/pom.xml b/sandbox/pom.xml index d3f2a774..88ed591c 100644 --- a/sandbox/pom.xml +++ b/sandbox/pom.xml @@ -39,6 +39,11 @@ ebl-surrender 0.0.1-SNAPSHOT + + org.dcsa.conformance + jit + 0.0.1-SNAPSHOT + org.dcsa.conformance ovs diff --git a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java index 0149a544..7801d70a 100644 --- a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java +++ b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java @@ -29,6 +29,7 @@ import org.dcsa.conformance.standards.ebl.EblComponentFactory; import org.dcsa.conformance.standards.eblissuance.EblIssuanceComponentFactory; import org.dcsa.conformance.standards.eblsurrender.EblSurrenderComponentFactory; +import org.dcsa.conformance.standards.jit.JitComponentFactory; import org.dcsa.conformance.standards.ovs.OvsComponentFactory; import org.dcsa.conformance.standards.tnt.TntComponentFactory; @@ -809,6 +810,9 @@ private static AbstractComponentFactory _createComponentFactory( if (EblSurrenderComponentFactory.STANDARD_NAME.equals(standardConfiguration.getName())) { return new EblSurrenderComponentFactory(standardConfiguration.getVersion()); } + if (JitComponentFactory.STANDARD_NAME.equals(standardConfiguration.getName())) { + return new JitComponentFactory(standardConfiguration.getVersion()); + } if (OvsComponentFactory.STANDARD_NAME.equals(standardConfiguration.getName())) { return new OvsComponentFactory(standardConfiguration.getVersion()); } diff --git a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceWebuiHandler.java b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceWebuiHandler.java index 42cd45d9..b40f29fb 100644 --- a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceWebuiHandler.java +++ b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceWebuiHandler.java @@ -19,6 +19,7 @@ import org.dcsa.conformance.standards.ebl.EblComponentFactory; import org.dcsa.conformance.standards.eblissuance.EblIssuanceComponentFactory; import org.dcsa.conformance.standards.eblsurrender.EblSurrenderComponentFactory; +import org.dcsa.conformance.standards.jit.JitComponentFactory; import org.dcsa.conformance.standards.ovs.OvsComponentFactory; import org.dcsa.conformance.standards.tnt.TntComponentFactory; @@ -59,6 +60,12 @@ public class ConformanceWebuiHandler { .collect( Collectors.toMap( Function.identity(), EblSurrenderComponentFactory::new)))), + Map.entry( + JitComponentFactory.STANDARD_NAME, + new TreeMap<>( + JitComponentFactory.STANDARD_VERSIONS.stream() + .collect( + Collectors.toMap(Function.identity(), JitComponentFactory::new)))), Map.entry( OvsComponentFactory.STANDARD_NAME, new TreeMap<>( diff --git a/spring-boot/src/main/java/org/dcsa/conformance/springboot/ConformanceApplication.java b/spring-boot/src/main/java/org/dcsa/conformance/springboot/ConformanceApplication.java index 3b543724..43a1157f 100644 --- a/spring-boot/src/main/java/org/dcsa/conformance/springboot/ConformanceApplication.java +++ b/spring-boot/src/main/java/org/dcsa/conformance/springboot/ConformanceApplication.java @@ -30,6 +30,7 @@ import org.dcsa.conformance.standards.ebl.EblComponentFactory; import org.dcsa.conformance.standards.eblissuance.EblIssuanceComponentFactory; import org.dcsa.conformance.standards.eblsurrender.EblSurrenderComponentFactory; +import org.dcsa.conformance.standards.jit.JitComponentFactory; import org.dcsa.conformance.standards.ovs.OvsComponentFactory; import org.dcsa.conformance.standards.tnt.TntComponentFactory; import org.springframework.boot.SpringApplication; @@ -151,6 +152,7 @@ public ConformanceApplication(ConformanceConfiguration conformanceConfiguration) .map(EblIssuanceComponentFactory::new), EblSurrenderComponentFactory.STANDARD_VERSIONS.stream() .map(EblSurrenderComponentFactory::new), + JitComponentFactory.STANDARD_VERSIONS.stream().map(JitComponentFactory::new), OvsComponentFactory.STANDARD_VERSIONS.stream().map(OvsComponentFactory::new), TntComponentFactory.STANDARD_VERSIONS.stream().map(TntComponentFactory::new)) .flatMap(Function.identity());