diff --git a/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml
index 0c10a0faf..5a53562ee 100644
--- a/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml
+++ b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml
@@ -498,4 +498,358 @@
+
+
+
+
+
+
+
+
+
+ template_id = 2004
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20301
+
+
+ br_id = 'VP-L01-00-0301'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20302
+
+
+ br_id = 'VP-L01-00-20302'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20321
+
+
+ br_id = 'VP-L01-00-0321'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20331
+
+
+ br_id = 'VP-L01-00-0331'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20311
+
+
+ br_id = 'VP-L01-00-0311'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ template_id = 2004
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20321
+
+
+ br_id = 'VP-L01-00-0321'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20331
+
+
+ br_id = 'VP-L01-00-0331'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20401
+
+
+ br_id = 'VP-L01-00-0401'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20411
+
+
+ br_id = 'VP-L01-00-0411'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20330
+
+
+ br_id = 'VP-L03-00-0330'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rule_id = 20320
+
+
+ br_id = 'VP-L03-00-0320'
+
+
+
+
diff --git a/model/src/main/resources/contract/Template.xsd b/model/src/main/resources/contract/Template.xsd
index e07152f21..2e7a2b952 100755
--- a/model/src/main/resources/contract/Template.xsd
+++ b/model/src/main/resources/contract/Template.xsd
@@ -91,6 +91,7 @@
+
\ No newline at end of file
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/ContainerType.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/ContainerType.java
index 7d529af6d..857cbff64 100644
--- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/ContainerType.java
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/ContainerType.java
@@ -48,7 +48,7 @@ public enum ContainerType {
FactType.SALES_AUCTION_SALE, FactType.SALES_FLUX_SALES_QUERY_MESSAGE, FactType.SALES_QUERY_PARAMETER, FactType.SALES_FLUX_SALES_RESPONSE_MESSAGE),
MOVEMENTS("movement","ec.europa.eu.movement", FactType.MOVEMENT_REPORT_DOCUMENT, FactType.MOVEMENT_REPORT_DOCUMENT_ID,
- FactType.MOVEMENT_REPORT_DOC_OWNER_FLUX_PARTY_ID, FactType.MOVEMENT_VESSEL_TRANSPORT_MEANS_ID);
+ FactType.MOVEMENT_REPORT_DOC_OWNER_FLUX_PARTY_ID, FactType.MOVEMENT_VESSEL_TRANSPORT_MEANS_ID, FactType.MOVEMENT_SPECIFIED_VESSEL_POSITION_EVENT);
private final String packageName;
private final String containerName;
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementSpecifiedVesselPositionEventFact.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementSpecifiedVesselPositionEventFact.java
new file mode 100644
index 000000000..91c44b5c6
--- /dev/null
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementSpecifiedVesselPositionEventFact.java
@@ -0,0 +1,68 @@
+package eu.europa.ec.fisheries.uvms.rules.service.business.fact;
+
+import eu.europa.ec.fisheries.schema.rules.template.v1.FactType;
+import eu.europa.ec.fisheries.uvms.rules.service.business.AbstractFact;
+import lombok.Data;
+import org.joda.time.DateTime;
+import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselGeographicalCoordinateType;
+import un.unece.uncefact.data.standard.unqualifieddatatype._18.CodeType;
+import un.unece.uncefact.data.standard.unqualifieddatatype._18.DateTimeType;
+
+import java.math.BigDecimal;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+
+@Data
+public class MovementSpecifiedVesselPositionEventFact extends AbstractFact {
+ private CodeType typeCode;
+ private DateTime creationDateTime;
+ private BigDecimal speedValue;
+ private BigDecimal courseValue;
+ private String creationDateTimeString;
+ private BigDecimal latitudeMeasure;
+ private BigDecimal longitudeMeasure;
+
+ public boolean hasValidSpeedValue(BigDecimal speedValue) {
+ return speedValue.signum() > 0 && speedValue.scale() < 3;
+ }
+
+ public boolean hasValidCourseValue(BigDecimal courseValue) {
+ return courseValue.compareTo(new BigDecimal(360)) <= 0 && courseValue.compareTo(BigDecimal.ZERO) >= 0;
+ }
+
+ public boolean hasValidTypeCodeValueListID(CodeType typeCode) {
+ return typeCode.getListID().equals("FLUX_VESSEL_POSITION_TYPE");
+ }
+
+ public boolean hasValidCreationDateTime(String creationDateTimeString) {
+ DateTimeFormatter formatter = new DateTimeFormatterBuilder()
+ .parseStrict()
+ .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
+ .optionalStart()
+ .appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, true)
+ .optionalEnd()
+ .appendLiteral('Z')//timezone must always be utc, thus the literal Z
+ .parseStrict().toFormatter();
+ try {
+ formatter.parse(creationDateTimeString);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean hasValidLatitudeMeasure(BigDecimal latitudeMeasure) {
+ return latitudeMeasure.compareTo(new BigDecimal(90)) <= 0 && latitudeMeasure.compareTo(new BigDecimal(-90)) >= 0 && latitudeMeasure.scale() >= 3 && latitudeMeasure.scale() <= 6;
+ }
+
+ public boolean hasValidLongitudeMeasure(BigDecimal longitudeMeasure) {
+ return longitudeMeasure.compareTo(new BigDecimal(180)) <= 0 && longitudeMeasure.compareTo(new BigDecimal(-180)) >= 0 && longitudeMeasure.scale() >= 3 && longitudeMeasure.scale() <= 6;
+ }
+
+ @Override
+ public void setFactType() {
+ this.factType = FactType.MOVEMENT_SPECIFIED_VESSEL_POSITION_EVENT;
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/generator/MovementFactGenerator.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/generator/MovementFactGenerator.java
index 29e8c48ab..cbc5e64a8 100644
--- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/generator/MovementFactGenerator.java
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/generator/MovementFactGenerator.java
@@ -18,8 +18,6 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The
import eu.europa.ec.fisheries.uvms.rules.service.mapper.xpath.util.XPathStringWrapper;
import un.unece.uncefact.data.standard.fluxvesselpositionmessage._4.FLUXVesselPositionMessage;
import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.FLUXReportDocumentType;
-import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselTransportMeansType;
-import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.VesselTransportMeans;
import java.util.ArrayList;
import java.util.List;
@@ -59,6 +57,7 @@ public List generateAllFacts() {
facts.addAll(movementReportDocumentFactMapper.generateFactForMovementReportDocumentId(vesselPositionMessage));
facts.addAll(movementReportDocumentFactMapper.generateFactForMovementReportDocOwnerFluxPartyId(vesselPositionMessage));
facts.addAll(movementReportDocumentFactMapper.generateFactForMovementVesselTransportMeansId(vesselPositionMessage));
+ facts.addAll(movementReportDocumentFactMapper.generateFactForSpecifiedVesselPositionEvent(vesselPositionMessage));
}
String df = (String) extraValueMap.get(DATA_FLOW);
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/helper/DrtPathHelper.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/helper/DrtPathHelper.java
index fbb8663d2..5447865bb 100644
--- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/helper/DrtPathHelper.java
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/helper/DrtPathHelper.java
@@ -38,6 +38,7 @@ public enum DrtPathHelper {
MOVEMENT_REPORT_DOCUMENT_ID("/templates/MovementReportDocumentId.drt"),
MOVEMENT_REPORT_DOC_OWNER_FLUX_PARTY_ID("/templates/MovementReportDocOwnerFluxPartyId.drt"),
MOVEMENT_VESSEL_TRANSPORT_MEANS_ID("/templates/MovementVesselTransportMeansId.drt"),
+ MOVEMENT_SPECIFIED_VESSEL_POSITION_EVENT("/templates/MovementSpecifiedVesselPositionEvent.drt"),
FA_RELOCATION("/templates/FaRelocation.drt"),
FA_RESPONSE("/templates/FaResponse.drt"),
FA_TRANSHIPMENT("/templates/FaTranshipment.drt"),
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/constants/XPathConstants.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/constants/XPathConstants.java
index a65bb751b..8511ef1c6 100644
--- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/constants/XPathConstants.java
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/constants/XPathConstants.java
@@ -118,5 +118,10 @@ public class XPathConstants {
public static final String RESPONSE_CODE = "ResponseCode";
public static final String RESPONDENT_FLUX_PARTY = "RespondentFLUXParty";
public static final String SPECIFIED_VESSELPOSITION_EVENT = "SpecifiedVesselPositionEvent";
-
+ public static final String SPEED_VALUE_MEASURE = "SpeedValueMeasure";
+ public static final String COURSE_VALUE_MEASURE = "CourseValueMeasure";
+ public static final String OBTAINED_OCCURRENCE_DATE_TIME = "ObtainedOccurrenceDateTime";
+ public static final String SPECIFIED_VESSEL_GEOGRAPHICAL_COORDINATE = "SpecifiedVesselGeographicalCoordinate";
+ public static final String LATITUDE_MEASURE = "LatitudeMeasure";
+ public static final String LONGITUDE_MEASURE = "LongitudeMeasure";
}
diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/fact/MovementReportDocumentFactMapper.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/fact/MovementReportDocumentFactMapper.java
index e9cf509d7..e11817e9e 100644
--- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/fact/MovementReportDocumentFactMapper.java
+++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/fact/MovementReportDocumentFactMapper.java
@@ -11,6 +11,7 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The
package eu.europa.ec.fisheries.uvms.rules.service.mapper.fact;
+
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.CREATION_DATE_TIME;
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.FLUX_REPORT_DOCUMENT;
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.MOVEMENT_REPORT_DOCUMENT;
@@ -19,7 +20,14 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.REGISTRATION_VESSEL_COUNTRY;
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.VESSEL_TRANSPORT_MEANS;
import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.VESSEL_TRANSPORT_MEANS_ID;
-
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.TYPE_CODE;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.SPEED_VALUE_MEASURE;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.SPECIFIED_VESSELPOSITION_EVENT;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.COURSE_VALUE_MEASURE;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.OBTAINED_OCCURRENCE_DATE_TIME;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.SPECIFIED_VESSEL_GEOGRAPHICAL_COORDINATE;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.LATITUDE_MEASURE;
+import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.LONGITUDE_MEASURE;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -28,12 +36,14 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The
import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementReportDocOwnerFluxPartyIdFact;
import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementReportDocumentFact;
import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementReportDocumentIdFact;
+import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementSpecifiedVesselPositionEventFact;
import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementVesselTransportMeansIdFact;
import eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants;
import eu.europa.ec.fisheries.uvms.rules.service.mapper.xpath.util.XPathStringWrapper;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import un.unece.uncefact.data.standard.fluxvesselpositionmessage._4.FLUXVesselPositionMessage;
+import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselPositionEventType;
import un.unece.uncefact.data.standard.unqualifieddatatype._18.CodeType;
import un.unece.uncefact.data.standard.unqualifieddatatype._18.DateTimeType;
import un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType;
@@ -157,6 +167,58 @@ public List generateFactForMovementVesselTra
return factList;
}
+ public List generateFactForSpecifiedVesselPositionEvent(FLUXVesselPositionMessage vesselPositionMessage) {
+
+ String partialXpath = xPathUtil.append(MOVEMENT_REPORT_DOCUMENT).append(VESSEL_TRANSPORT_MEANS).getValue();
+ List factList = new ArrayList<>();
+
+ if(vesselPositionMessage == null || vesselPositionMessage.getVesselTransportMeans() == null || vesselPositionMessage.getVesselTransportMeans().getSpecifiedVesselPositionEvents().isEmpty()){
+ xPathUtil.clear();
+ return factList;
+ }
+
+ List specifiedVesselPositionEvents= vesselPositionMessage.getVesselTransportMeans().getSpecifiedVesselPositionEvents();
+ Date creationDate = getDate(vesselPositionMessage.getFLUXReportDocument().getCreationDateTime());
+ int index = 1;
+ for(VesselPositionEventType vesselPositionEventType: specifiedVesselPositionEvents) {
+ MovementSpecifiedVesselPositionEventFact fact = new MovementSpecifiedVesselPositionEventFact();
+ fact.setCreationDateTime(new DateTime(creationDate));
+
+ fact.setTypeCode(vesselPositionEventType.getTypeCode());
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(TYPE_CODE).storeInRepo(fact, "typeCode");
+
+ if (vesselPositionEventType.getSpeedValueMeasure() != null) {
+ fact.setSpeedValue(vesselPositionEventType.getSpeedValueMeasure().getValue());
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(SPEED_VALUE_MEASURE).storeInRepo(fact, "speedValue");
+ } else {
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).storeInRepo(fact, "speedValue");
+ }
+
+
+ if (vesselPositionEventType.getCourseValueMeasure() != null) {
+ fact.setCourseValue(vesselPositionEventType.getCourseValueMeasure().getValue());
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(COURSE_VALUE_MEASURE).storeInRepo(fact, "courseValue");
+ } else {
+ fact.setCourseValue(null);
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).storeInRepo(fact, "courseValue");
+ }
+
+ fact.setCreationDateTimeString(dateTimeAsString(vesselPositionEventType.getObtainedOccurrenceDateTime()));
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(OBTAINED_OCCURRENCE_DATE_TIME).storeInRepo(fact, "creationDateTimeString");
+
+ fact.setLatitudeMeasure(vesselPositionEventType.getSpecifiedVesselGeographicalCoordinate().getLatitudeMeasure().getValue());
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(SPECIFIED_VESSEL_GEOGRAPHICAL_COORDINATE).append(LATITUDE_MEASURE).storeInRepo(fact, "latitudeMeasure");
+
+ fact.setLongitudeMeasure(vesselPositionEventType.getSpecifiedVesselGeographicalCoordinate().getLongitudeMeasure().getValue());
+ xPathUtil.appendWithoutWrapping(partialXpath).appendWithIndex(SPECIFIED_VESSELPOSITION_EVENT, index).append(SPECIFIED_VESSEL_GEOGRAPHICAL_COORDINATE).append(LONGITUDE_MEASURE).storeInRepo(fact, "longitudeMeasure");
+
+ factList.add(fact);
+ index ++;
+ }
+
+ return factList;
+ }
+
public static MovementReportDocumentFact mapToMovementReportDocumentFact(FLUXVesselPositionMessage vesselPositionMessage){
if(vesselPositionMessage == null || vesselPositionMessage.getFLUXReportDocument() == null){
diff --git a/service/src/main/resources/templates/MovementSpecifiedVesselPositionEvent.drt b/service/src/main/resources/templates/MovementSpecifiedVesselPositionEvent.drt
new file mode 100644
index 000000000..8e2985dac
--- /dev/null
+++ b/service/src/main/resources/templates/MovementSpecifiedVesselPositionEvent.drt
@@ -0,0 +1,34 @@
+template header
+
+tname
+expression
+brid
+rulemsg
+type
+level
+propertyNames
+context
+
+package eu.europa.ec.fisheries.uvms.rules.service.business.activity;
+
+import eu.europa.ec.fisheries.uvms.rules.service.business.fact.MovementSpecifiedVesselPositionEventFact;
+import java.util.Arrays;
+global eu.europa.ec.fisheries.uvms.rules.service.business.helper.RuleApplicabilityChecker appliChecker;
+global eu.europa.ec.fisheries.uvms.rules.service.MDRCacheRuleService mdrService;
+
+
+template "@{tname}"
+
+rule "Specified Vessel Position Event Type Code Fact @{tname} - @{brid} - Context : @{context}"
+
+when
+
+ $fact : MovementSpecifiedVesselPositionEventFact((appliChecker.isApplicable("@{brid}", "@{context}", getMessageDataFlow(), getCreationDateOfMessage(), mdrService)) && (@{expression}))
+
+then
+ $fact.setOk(false);
+ $fact.addWarningOrError(mdrService.getErrorTypeStrForForBrIAndDFAndValidity("@{brid}", "@{context}", $fact.getCreationJavaDateOfMessage()), mdrService.getErrorMessageForBrIAndDFAndValidity("@{brid}", "@{context}", $fact.getCreationJavaDateOfMessage()), "@{brid}", "@{level}", "@{propertyNames}");
+
+end
+
+end template
\ No newline at end of file