From 37e30e1bde7b1cb1ae8d65d3d46f203d07c607ae Mon Sep 17 00:00:00 2001 From: gmanifavas Date: Fri, 5 Mar 2021 12:51:57 +0200 Subject: [PATCH] [UNIONVMS-5039] Implement rule VP-L03-00-0004: Movement FLUXReportDocument id must be unique. --- LIQUIBASE/changelog/db-changelog-master.xml | 1 + .../v3.4/db-changelog-UNIONVMS-4660.xml | 29 ++++++++ .../v3.4/db-changelog-UNIONVMS-4945.xml | 28 ++++++++ .../uvms/rules/dao/MovementDocumentIdDao.java | 55 ++++++++++++++ .../rules/dao/MovementDocumentIdLockDao.java | 10 +++ .../ec/fisheries/uvms/rules/dao/RulesDao.java | 11 ++- .../bean/MovementDocumentIdLockDaoBean.java | 40 +++++++++++ .../uvms/rules/dao/bean/RulesDaoBean.java | 45 ++++++++++++ .../uvms/rules/entity/MovementDocumentId.java | 60 ++++++++++++++++ .../rules/entity/MovementDocumentIdLock.java | 33 +++++++++ .../movement/RulesMovementProcessorBean.java | 27 +++++-- .../fact/MovementReportDocumentFact.java | 6 +- .../generator/MovementFactGenerator.java | 28 +++++--- .../rules/service/config/ExtraValueType.java | 3 +- .../mapper/RulesFLUXMessageHelper.java | 72 ++++++++++++++----- .../MovementReportDocumentFactMapper.java | 8 ++- 16 files changed, 423 insertions(+), 33 deletions(-) create mode 100644 LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4945.xml create mode 100644 domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdDao.java create mode 100644 domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdLockDao.java create mode 100644 domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/MovementDocumentIdLockDaoBean.java create mode 100644 domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentId.java create mode 100644 domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentIdLock.java diff --git a/LIQUIBASE/changelog/db-changelog-master.xml b/LIQUIBASE/changelog/db-changelog-master.xml index 8a3a3fd31..ae2017946 100644 --- a/LIQUIBASE/changelog/db-changelog-master.xml +++ b/LIQUIBASE/changelog/db-changelog-master.xml @@ -97,4 +97,5 @@ + diff --git a/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml index 0c10a0faf..bc0b72406 100644 --- a/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml +++ b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml @@ -498,4 +498,33 @@ + + + + + + + + + + + + + + + + + + + + + + rule_id = 20004 + + + br_id = 'VP-L03-00-0004' + + + + diff --git a/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4945.xml b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4945.xml new file mode 100644 index 000000000..4d805ea05 --- /dev/null +++ b/LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4945.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdDao.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdDao.java new file mode 100644 index 000000000..4694ee1b4 --- /dev/null +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdDao.java @@ -0,0 +1,55 @@ +/* + Developed by the European Commission - Directorate General for Maritime Affairs and Fisheries @ European Union, 2015-2016. + + This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The IFDM Suite is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of + the License, or any later version. The IFDM Suite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. You should have received a copy of the GNU General Public License along with the IFDM Suite. If not, see . + */ + +package eu.europa.ec.fisheries.uvms.rules.dao; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import eu.europa.ec.fisheries.uvms.commons.service.dao.AbstractDAO; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; + +public class MovementDocumentIdDao extends AbstractDAO { + + private EntityManager em; + + public MovementDocumentIdDao(EntityManager em) { + this.em = em; + } + + @Override public EntityManager getEntityManager() { + return em; + } + + public List loadMovementDocumentIDByIds(Set ids) { + Set stringSet = new HashSet<>(); + if(CollectionUtils.isEmpty(ids)){ + return new ArrayList<>(); + } + for (MovementDocumentId id : ids) { + String uuid = id.getUuid(); + if(StringUtils.isNotEmpty(uuid)){ + stringSet.add(uuid); + stringSet.add(uuid.toLowerCase()); + stringSet.add(uuid.toUpperCase()); + } + } + Query query = getEntityManager().createNamedQuery(MovementDocumentId.LOAD_BY_UUID); + query.setParameter("uuids", stringSet); + return query.getResultList(); + } + +} diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdLockDao.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdLockDao.java new file mode 100644 index 000000000..b06a1f290 --- /dev/null +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/MovementDocumentIdLockDao.java @@ -0,0 +1,10 @@ +package eu.europa.ec.fisheries.uvms.rules.dao; + +import javax.ejb.Local; + +@Local +public interface MovementDocumentIdLockDao { + void takeNoteOfDocumentIdInNewTx(String documentId); + + void lock(String documentId); +} diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/RulesDao.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/RulesDao.java index be2c80216..acabf0d9c 100644 --- a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/RulesDao.java +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/RulesDao.java @@ -20,6 +20,7 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The import eu.europa.ec.fisheries.uvms.rules.entity.AlarmReport; import eu.europa.ec.fisheries.uvms.rules.entity.CustomRule; import eu.europa.ec.fisheries.uvms.rules.entity.FADocumentID; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; import eu.europa.ec.fisheries.uvms.rules.entity.PreviousReport; import eu.europa.ec.fisheries.uvms.rules.entity.RawMessage; import eu.europa.ec.fisheries.uvms.rules.entity.RuleSubscription; @@ -168,13 +169,21 @@ List getTicketListPaginated(Integer page, Integer listSize, String sql, List getValidationMessagesByRawMsgGuid(String rawMsgGuid, String type) throws DaoException; List loadFADocumentIDByIdsByIds(Set incomingIDs); + + List loadMovementDocumentIDByIds(Set incomingIDs); void takeNoteOfDocumentIds(Set incomingIDs); + + void takeNoteOfMovementDocumentIds(Set incomingIDs); List lockDocumentIds(Set incomingIDs); + + List lockMovementDocumentIds(Set incomingIDs); void createFaDocumentIdEntity(Set incomingID) throws ServiceException; - + + void createMovementDocumentIdEntity(Set incomingID) throws ServiceException; + void saveFaIdsPerTripList(List tripList); List loadExistingFaIdsPerTrip(List idsFromIncommingMessage); diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/MovementDocumentIdLockDaoBean.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/MovementDocumentIdLockDaoBean.java new file mode 100644 index 000000000..d979a080f --- /dev/null +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/MovementDocumentIdLockDaoBean.java @@ -0,0 +1,40 @@ +package eu.europa.ec.fisheries.uvms.rules.dao.bean; + +import static javax.ejb.TransactionAttributeType.REQUIRES_NEW; + +import javax.ejb.Stateless; +import javax.ejb.TransactionAttribute; +import javax.persistence.EntityManager; +import javax.persistence.LockModeType; +import javax.persistence.PersistenceContext; +import java.util.Collections; +import java.util.Map; + +import eu.europa.ec.fisheries.uvms.rules.dao.MovementDocumentIdLockDao; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentIdLock; + +@Stateless +public class MovementDocumentIdLockDaoBean implements MovementDocumentIdLockDao { + + private static final Map ZERO_LOCK_TIMEOUT = Collections.singletonMap("javax.persistence.lock.timeout", 0); + + @PersistenceContext(unitName = "rulesPostgresPU") + public EntityManager em; + + @TransactionAttribute(REQUIRES_NEW) + @Override + public void takeNoteOfDocumentIdInNewTx(String documentId) { + MovementDocumentIdLock lock = em.find(MovementDocumentIdLock.class, documentId); + if( lock == null ) { + em.persist(new MovementDocumentIdLock(documentId)); + } + } + + @Override + public void lock(String documentId) { + MovementDocumentIdLock lock = em.find(MovementDocumentIdLock.class, documentId, LockModeType.PESSIMISTIC_WRITE, ZERO_LOCK_TIMEOUT); + if( lock == null ) { + throw new IllegalStateException("lock " + documentId + " should have been created"); + } + } +} diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/RulesDaoBean.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/RulesDaoBean.java index 05888df01..2c8570343 100644 --- a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/RulesDaoBean.java +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/dao/bean/RulesDaoBean.java @@ -33,6 +33,8 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The import eu.europa.ec.fisheries.uvms.rules.dao.FADocumentIDDAO; import eu.europa.ec.fisheries.uvms.rules.dao.FaDocumentIdLockDao; import eu.europa.ec.fisheries.uvms.rules.dao.FaIdsPerTripDao; +import eu.europa.ec.fisheries.uvms.rules.dao.MovementDocumentIdDao; +import eu.europa.ec.fisheries.uvms.rules.dao.MovementDocumentIdLockDao; import eu.europa.ec.fisheries.uvms.rules.dao.RawMessageDao; import eu.europa.ec.fisheries.uvms.rules.dao.RulesDao; import eu.europa.ec.fisheries.uvms.rules.dao.TemplateDao; @@ -41,6 +43,7 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The import eu.europa.ec.fisheries.uvms.rules.entity.CustomRule; import eu.europa.ec.fisheries.uvms.rules.entity.FADocumentID; import eu.europa.ec.fisheries.uvms.rules.entity.FaIdsPerTrip; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; import eu.europa.ec.fisheries.uvms.rules.entity.PreviousReport; import eu.europa.ec.fisheries.uvms.rules.entity.RawMessage; import eu.europa.ec.fisheries.uvms.rules.entity.RuleSubscription; @@ -67,10 +70,14 @@ public class RulesDaoBean implements RulesDao { private ValidationMessageDao validationMessageDao; private FADocumentIDDAO fishingActivityIdDao; private FaIdsPerTripDao faIdsPerTripDao; + private MovementDocumentIdDao movementDocumentIdDao; @EJB private FaDocumentIdLockDao faDocumentIdLockDao; + @EJB + private MovementDocumentIdLockDao movementDocumentIdLockDao; + @PersistenceContext(unitName = "rulesPostgresPU") public EntityManager em; @@ -81,6 +88,7 @@ public void init() { validationMessageDao = new ValidationMessageDao(em); fishingActivityIdDao = new FADocumentIDDAO(em); faIdsPerTripDao = new FaIdsPerTripDao(em); + movementDocumentIdDao = new MovementDocumentIdDao(em); } @Override @@ -617,6 +625,11 @@ public List loadFADocumentIDByIdsByIds(Set incomingI return fishingActivityIdDao.loadFADocumentIDByIdsByIds(incomingIDs); } + @Override + public List loadMovementDocumentIDByIds(Set incomingIDs) { + return movementDocumentIdDao.loadMovementDocumentIDByIds(incomingIDs); + } + @Override public void takeNoteOfDocumentIds(Set incomingIDs) { incomingIDs.stream() @@ -625,6 +638,14 @@ public void takeNoteOfDocumentIds(Set incomingIDs) { .forEach(this::takeNoteOfDocumentIdAllowingDuplicates); } + @Override + public void takeNoteOfMovementDocumentIds(Set incomingIDs) { + incomingIDs.stream() + .map(MovementDocumentId::getUuid) + .sorted() + .forEach(this::takeNoteOfMovementDocumentIdAllowingDuplicates); + } + private void takeNoteOfDocumentIdAllowingDuplicates(String documentId) { try { faDocumentIdLockDao.takeNoteOfDocumentIdInNewTx(documentId); @@ -633,6 +654,14 @@ private void takeNoteOfDocumentIdAllowingDuplicates(String documentId) { } } + private void takeNoteOfMovementDocumentIdAllowingDuplicates(String documentId) { + try { + movementDocumentIdLockDao.takeNoteOfDocumentIdInNewTx(documentId); + } catch( EntityExistsException eee ) { + // ignore it + } + } + public List lockDocumentIds(Set incomingIDs) { return incomingIDs.stream() .map(FADocumentID::getUuid) @@ -641,6 +670,15 @@ public List lockDocumentIds(Set incomingIDs) { .collect(Collectors.toList()); } + @Override + public List lockMovementDocumentIds(Set incomingIDs) { + return incomingIDs.stream() + .map(MovementDocumentId::getUuid) + .sorted() + .peek(movementDocumentIdLockDao::lock) + .collect(Collectors.toList()); + } + @Override public void createFaDocumentIdEntity(Set incomingIDsList) throws ServiceException { if(CollectionUtils.isNotEmpty(incomingIDsList)){ @@ -650,6 +688,13 @@ public void createFaDocumentIdEntity(Set incomingIDsList) throws S } } + @Override + public void createMovementDocumentIdEntity(Set incomingID) throws ServiceException { + for(MovementDocumentId movementDocumentId: incomingID) { + movementDocumentIdDao.createEntity(movementDocumentId); + } + } + @Override public void saveFaIdsPerTripList(List tripList) { if(CollectionUtils.isNotEmpty(tripList)){ diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentId.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentId.java new file mode 100644 index 000000000..fa897ab00 --- /dev/null +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentId.java @@ -0,0 +1,60 @@ +/* + Developed by the European Commission - Directorate General for Maritime Affairs and Fisheries @ European Union, 2015-2016. + + This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The IFDM Suite is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of + the License, or any later version. The IFDM Suite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. You should have received a copy of the GNU General Public License along with the IFDM Suite. If not, see . + */ + +package eu.europa.ec.fisheries.uvms.rules.entity; + +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.PrePersist; +import javax.persistence.Table; +import java.io.Serializable; + +import eu.europa.ec.fisheries.uvms.commons.date.DateUtils; +import eu.europa.ec.fisheries.uvms.commons.domain.Audit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Table(name = "movement_doc_id") +@Data +@Entity +@EqualsAndHashCode(exclude = {"id", "audit"}) +@NamedQueries({ + @NamedQuery(name = MovementDocumentId.LOAD_BY_UUID, query = "FROM MovementDocumentId f WHERE f.uuid in (:uuids)") +}) +@RequiredArgsConstructor +@NoArgsConstructor +public class MovementDocumentId implements Serializable { + + public static final String LOAD_BY_UUID = "MovementDocumentId.loadByUUID"; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @NonNull + private String uuid; + + @Embedded + private Audit audit = new Audit(); + + @PrePersist + private void prePersist() { + audit.setCreatedOn(DateUtils.nowUTC().toDate()); + } + +} diff --git a/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentIdLock.java b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentIdLock.java new file mode 100644 index 000000000..924b6c409 --- /dev/null +++ b/domain/src/main/java/eu/europa/ec/fisheries/uvms/rules/entity/MovementDocumentIdLock.java @@ -0,0 +1,33 @@ +package eu.europa.ec.fisheries.uvms.rules.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Entity +@Table(name = "movement_doc_id_lock") +@NamedQueries({ + @NamedQuery(name = MovementDocumentIdLock.LOAD_BY_UUID, query = "FROM MovementDocumentIdLock f WHERE f.uuid in (:uuids)") +}) +@Data +@EqualsAndHashCode +@RequiredArgsConstructor +@NoArgsConstructor +public class MovementDocumentIdLock { + + public static final String LOAD_BY_UUID = "MovementDocumentIdLock.loadByUuid"; + + @Id + @NonNull + @Column(name = "uuid") + private String uuid; +} diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/movement/RulesMovementProcessorBean.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/movement/RulesMovementProcessorBean.java index c343b9b5c..2a4adb326 100644 --- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/movement/RulesMovementProcessorBean.java +++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/bean/movement/RulesMovementProcessorBean.java @@ -16,6 +16,7 @@ import static eu.europa.ec.fisheries.uvms.movement.model.exception.ErrorCode.MOVEMENT_DUPLICATE_ERROR; import static eu.europa.ec.fisheries.uvms.rules.service.config.BusinessObjectType.RECEIVING_MOVEMENT_MSG; import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.DATA_FLOW; +import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.MOVEMENT_DOC_IDS; import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.SENDER_RECEIVER; import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.XML; @@ -74,6 +75,7 @@ import eu.europa.ec.fisheries.uvms.commons.message.api.MessageException; import eu.europa.ec.fisheries.uvms.commons.message.impl.JAXBUtils; import eu.europa.ec.fisheries.uvms.commons.notifications.NotificationMessage; +import eu.europa.ec.fisheries.uvms.commons.service.exception.ServiceException; import eu.europa.ec.fisheries.uvms.config.model.mapper.ModuleRequestMapper; import eu.europa.ec.fisheries.uvms.exchange.model.exception.ExchangeModelMapperException; import eu.europa.ec.fisheries.uvms.exchange.model.exception.ExchangeModelMarshallException; @@ -85,6 +87,10 @@ import eu.europa.ec.fisheries.uvms.movement.model.exception.MovementModelException; import eu.europa.ec.fisheries.uvms.movement.model.mapper.MovementModuleRequestMapper; import eu.europa.ec.fisheries.uvms.movement.model.mapper.MovementModuleResponseMapper; +import eu.europa.ec.fisheries.uvms.rules.dao.RulesDao; +import eu.europa.ec.fisheries.uvms.rules.entity.FADocumentID; +import eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; import eu.europa.ec.fisheries.uvms.rules.message.consumer.RulesResponseConsumer; import eu.europa.ec.fisheries.uvms.rules.message.producer.bean.*; import eu.europa.ec.fisheries.uvms.rules.model.constant.AuditObjectTypeEnum; @@ -127,8 +133,11 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import un.unece.uncefact.data.standard.fluxfareportmessage._3.FLUXFAReportMessage; import un.unece.uncefact.data.standard.fluxvesselpositionmessage._4.FLUXVesselPositionMessage; import un.unece.uncefact.data.standard.mdr.communication.ObjectRepresentation; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FAReportDocument; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FLUXReportDocument; import un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType; import javax.annotation.PostConstruct; @@ -218,6 +227,9 @@ public class RulesMovementProcessorBean { @AlarmReportCountEvent private Event alarmReportCountEvent; + @Inject + private RulesDao rulesDaoBean; + private Map mapToMovementType; private RulesFLUXMessageHelper fluxMessageHelper; @@ -281,10 +293,16 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri return; } + Set idsFromIncomingMessage = fluxMessageHelper.mapToMovementDocumentID(fluxVesselPositionMessage); + rulesDaoBean.takeNoteOfMovementDocumentIds(idsFromIncomingMessage); + rulesDaoBean.lockMovementDocumentIds(idsFromIncomingMessage); + List storedIds = rulesDaoBean.loadMovementDocumentIDByIds(idsFromIncomingMessage); + Map extraValues = new EnumMap<>(ExtraValueType.class); extraValues.put(SENDER_RECEIVER, request.getSenderOrReceiver()); extraValues.put(XML, request.getRequest()); extraValues.put(DATA_FLOW, request.getFluxDataFlow()); + extraValues.put(MOVEMENT_DOC_IDS, storedIds); Collection factsResults = rulesEngine.evaluate(RECEIVING_MOVEMENT_MSG,fluxVesselPositionMessage,extraValues,null); final String reportId = fluxVesselPositionMessage.getFLUXReportDocument().getIDS().stream() @@ -300,7 +318,8 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri } // Decomment this one and comment the other when validation is working! Still work needs to be done after this! // processReceivedMovementsAsBatch(movementReportsList, pluginType, userName, request.getLogGuid()); - enrichAndSenMovementsAsBatch(validationResult, movementReportsList, userName, request.getLogGuid(), request, request.getLogGuid()); + idsFromIncomingMessage.removeAll(storedIds); + enrichAndSenMovementsAsBatch(validationResult, movementReportsList, userName, request.getLogGuid(), request, request.getLogGuid(), idsFromIncomingMessage); // Send some response to Movement, if it originated from there (manual movement) if (MovementSourceType.MANUAL.equals(movementReportsList.get(0).getSource())) {// A person has created a position ProcessedMovementAck response = MovementModuleResponseMapper.mapProcessedMovementAck(eu.europa.ec.fisheries.schema.movement.common.v1.AcknowledgeTypeType.OK, @@ -312,7 +331,6 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri } } - /** * This method is just up until the new movement flow is ready from Swe team! * It is actually avoiding validation process all together since it doesn't work as of now! @@ -322,7 +340,7 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri * @param exchangeLogGuid * @throws RulesServiceException */ - private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, List rawMovements, String username, String exchangeLogGuid, SetFLUXMovementReportRequest request, String reportId) throws RulesServiceException { + private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, List rawMovements, String username, String exchangeLogGuid, SetFLUXMovementReportRequest request, String reportId, Set idsFromIncomingMessage) throws RulesServiceException { try { // Enrich with MobilTerminal and Assets data. Get Mobile Terminal if it exists. EnrichedMovementWrapper enrichedWrapper = enrichBatchWithMobileTerminalAndAssets(rawMovements); @@ -330,6 +348,7 @@ private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, Lis ExchangeLogStatusTypeType status; if (movementBatchResponse != null && SimpleResponse.OK.equals(movementBatchResponse.getPermitted())) { if (SimpleResponse.OK.equals(movementBatchResponse.getResponse())) { + rulesDaoBean.createMovementDocumentIdEntity(idsFromIncomingMessage); status = ExchangeLogStatusTypeType.fromValue(fluxMessageHelper.calculateMessageValidationStatus(validationResult).value()); } else { status = ExchangeLogStatusTypeType.FAILED; @@ -340,7 +359,7 @@ private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, Lis } sendBatchBackToExchange(exchangeLogGuid, rawMovements, MovementRefTypeType.MOVEMENT, username); updateRequestMessageStatusInExchange(exchangeLogGuid, status); - } catch (MessageException | MobileTerminalModelMapperException | MobileTerminalUnmarshallException | JMSException | AssetModelMapperException | RulesModelException e) { + } catch (MessageException | MobileTerminalModelMapperException | MobileTerminalUnmarshallException | JMSException | AssetModelMapperException | RulesModelException | ServiceException e) { throw new RulesServiceException(e.getMessage(), e); } } diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementReportDocumentFact.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementReportDocumentFact.java index 7e7afcedc..45d453442 100644 --- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementReportDocumentFact.java +++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/business/fact/MovementReportDocumentFact.java @@ -40,8 +40,12 @@ public class MovementReportDocumentFact extends AbstractFact { private VesselCountryType registrationVesselCountry; private IDType registrationVesselCountryIdType; private DateTime dateTime; + private List existingIds; - + public boolean hasDuplicateId(List ids, List existingIds) { + return ids.stream().map(IDType::getValue).anyMatch(existingIds::contains); + } + public boolean containsTypesOfIdXTimes(List ids,String schemaType,int count){ int counter = 0; 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..ccbf8700b 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 @@ -11,6 +11,15 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The package eu.europa.ec.fisheries.uvms.rules.service.business.generator; +import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.DATA_FLOW; +import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.MOVEMENT_DOC_IDS; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; import eu.europa.ec.fisheries.uvms.rules.service.business.AbstractFact; import eu.europa.ec.fisheries.uvms.rules.service.business.MessageType; import eu.europa.ec.fisheries.uvms.rules.service.exception.RulesValidationException; @@ -18,14 +27,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; - -import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.DATA_FLOW; -import static eu.europa.ec.fisheries.uvms.rules.service.constants.XPathConstants.MOVEMENT_REPORT_DOCUMENT; public class MovementFactGenerator extends AbstractGenerator { @@ -53,7 +54,7 @@ public MovementFactGenerator() { public List generateAllFacts() { List facts = new ArrayList<>(); FLUXReportDocumentType fluxReportDocument = vesselPositionMessage.getFLUXReportDocument(); - + movementReportDocumentFactMapper.setExistingIds(extractExistingIds()); if (fluxReportDocument != null) { facts.add(movementReportDocumentFactMapper.generateFactForMovementReportDocument(vesselPositionMessage)); facts.addAll(movementReportDocumentFactMapper.generateFactForMovementReportDocumentId(vesselPositionMessage)); @@ -75,4 +76,13 @@ public void setBusinessObjectMessage(Object businessObject) throws RulesValidati } this.vesselPositionMessage = (FLUXVesselPositionMessage) businessObject; } + + private List extractExistingIds() { + @SuppressWarnings("unchecked") + List faDocumentIDS = Optional.ofNullable((List) extraValueMap.get(MOVEMENT_DOC_IDS)).orElse(new ArrayList<>()); + return (faDocumentIDS) + .stream() + .map(MovementDocumentId::getUuid) + .collect(Collectors.toList()); + } } diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/config/ExtraValueType.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/config/ExtraValueType.java index 036a95740..e127986d7 100644 --- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/config/ExtraValueType.java +++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/config/ExtraValueType.java @@ -22,5 +22,6 @@ public enum ExtraValueType { CREATION_DATE_OF_MESSAGE, RESPONSE_IDS, XML, - DATA_FLOW + DATA_FLOW, + MOVEMENT_DOC_IDS } diff --git a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/RulesFLUXMessageHelper.java b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/RulesFLUXMessageHelper.java index 60a9c530f..6c57e125f 100644 --- a/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/RulesFLUXMessageHelper.java +++ b/service/src/main/java/eu/europa/ec/fisheries/uvms/rules/service/mapper/RulesFLUXMessageHelper.java @@ -10,15 +10,30 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The package eu.europa.ec.fisheries.uvms.rules.service.mapper; -import javax.xml.XMLConstants; +import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_QUERY; +import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_REPORT; +import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_RESPONSE; +import static eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType.FA_QUERY_ID; +import static eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType.FA_REPORT_REF_ID; +import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.RESPONSE_IDS; +import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.SENDER_RECEIVER; +import static eu.europa.ec.fisheries.uvms.rules.service.mapper.xpath.util.SchemaInitializer.SCHEMA_MAP; +import static java.util.Collections.singletonList; + import javax.xml.bind.UnmarshalException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + import eu.europa.ec.fisheries.schema.exchange.v1.ExchangeLogStatusTypeType; import eu.europa.ec.fisheries.schema.rules.module.v1.RulesModuleMethod; import eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType; @@ -26,6 +41,7 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The import eu.europa.ec.fisheries.uvms.commons.message.impl.JAXBUtils; import eu.europa.ec.fisheries.uvms.rules.entity.FADocumentID; import eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType; +import eu.europa.ec.fisheries.uvms.rules.entity.MovementDocumentId; import eu.europa.ec.fisheries.uvms.rules.service.bean.RulesConfigurationCache; import eu.europa.ec.fisheries.uvms.rules.service.business.ValidationResult; import eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType; @@ -34,24 +50,24 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; -import org.xml.sax.SAXException; import un.unece.uncefact.data.standard.fluxfaquerymessage._3.FLUXFAQueryMessage; import un.unece.uncefact.data.standard.fluxfareportmessage._3.FLUXFAReportMessage; import un.unece.uncefact.data.standard.fluxresponsemessage._6.FLUXResponseMessage; -import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.*; +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._20.FAQuery; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FAReportDocument; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FLUXParty; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FLUXReportDocument; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FLUXResponseDocument; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FishingActivity; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.FishingTrip; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.ValidationQualityAnalysis; +import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._20.ValidationResultDocument; import un.unece.uncefact.data.standard.unqualifieddatatype._20.CodeType; import un.unece.uncefact.data.standard.unqualifieddatatype._20.DateTimeType; import un.unece.uncefact.data.standard.unqualifieddatatype._20.IDType; import un.unece.uncefact.data.standard.unqualifieddatatype._20.TextType; -import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_QUERY; -import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_REPORT; -import static eu.europa.ec.fisheries.schema.rules.rule.v1.RawMsgType.FA_RESPONSE; -import static eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType.FA_QUERY_ID; -import static eu.europa.ec.fisheries.uvms.rules.entity.FAUUIDType.FA_REPORT_REF_ID; -import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.RESPONSE_IDS; -import static eu.europa.ec.fisheries.uvms.rules.service.config.ExtraValueType.SENDER_RECEIVER; -import static eu.europa.ec.fisheries.uvms.rules.service.mapper.xpath.util.SchemaInitializer.SCHEMA_MAP; -import static java.util.Collections.singletonList; @Slf4j public class RulesFLUXMessageHelper { @@ -128,6 +144,17 @@ public Set mapToFADocumentID(FLUXFAReportMessage fluxfaReportMessa return ids; } + public Set mapToMovementDocumentID(FLUXVesselPositionMessage fluxVesselPositionMessage) { + Set ids = new HashSet<>(); + if (fluxVesselPositionMessage != null){ + FLUXReportDocumentType fluxReportDocument = fluxVesselPositionMessage.getFLUXReportDocument(); + if (fluxReportDocument != null){ + mapFluxReportDocumentIDS(ids, fluxReportDocument); + } + } + return ids; + } + private void mapFaReportDocuments(Set ids, List faReportDocuments) { if (CollectionUtils.isNotEmpty(faReportDocuments)){ for (FAReportDocument faReportDocument : faReportDocuments) { @@ -155,6 +182,19 @@ private void mapFluxReportDocumentIDS(Set ids, FLUXReportDocument } } } + + private void mapFluxReportDocumentIDS(Set ids, FLUXReportDocumentType fluxReportDocument) { + if (fluxReportDocument != null){ + List fluxReportDocumentIDS = fluxReportDocument.getIDS(); + if (CollectionUtils.isNotEmpty(fluxReportDocumentIDS)){ + un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType idType = fluxReportDocumentIDS.get(0); + if (idType != null){ + ids.add(new MovementDocumentId(idType.getValue())); + } + + } + } + } public List collectFaIdsAndTripIds(FLUXFAReportMessage fluxFaRepMessage) { List idsReqList = new ArrayList<>(); 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..722bf5114 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 @@ -41,8 +41,10 @@ This file is part of the Integrated Fisheries Data Management (IFDM) Suite. The @Slf4j public class MovementReportDocumentFactMapper { - private XPathStringWrapper xPathUtil; public static final String ID = "id"; + + private XPathStringWrapper xPathUtil; + private List existingIds; public MovementReportDocumentFactMapper() { @@ -67,6 +69,7 @@ public MovementReportDocumentFact generateFactForMovementReportDocument(FLUXVess fact.setCreationDateTime(getDate(creationDateTime)); xPathUtil.appendWithoutWrapping(partialXpath).append(FLUX_REPORT_DOCUMENT, XPathConstants.CREATION_DATE_TIME).storeInRepo(fact, CREATION_DATE_TIME); fact.setIds(vesselPositionMessage.getFLUXReportDocument().getIDS()); + fact.setExistingIds(existingIds); xPathUtil.appendWithoutWrapping(partialXpath).append(FLUX_REPORT_DOCUMENT, XPathConstants.ID).storeInRepo(fact, "id"); CodeType purposeCode = vesselPositionMessage.getFLUXReportDocument().getPurposeCode(); fact.setPurposeCode(purposeCode); @@ -200,6 +203,9 @@ private static Date getDate(DateTimeType dateTimeType) { return date; } + public void setExistingIds(List existingIds) { + this.existingIds = existingIds; + } }