Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
479 changes: 433 additions & 46 deletions LIQUIBASE/changelog/v3.4/db-changelog-UNIONVMS-4660.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions model/src/main/resources/contract/Template.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<xsd:enumeration value="MOVEMENT_REPORT_DOCUMENT"/>
<xsd:enumeration value="MOVEMENT_REPORT_DOCUMENT_ID"/>
<xsd:enumeration value="MOVEMENT_REPORT_DOC_OWNER_FLUX_PARTY_ID"/>
<xsd:enumeration value="MOVEMENT_VESSEL_TRANSPORT_MEANS"/>
<xsd:enumeration value="MOVEMENT_VESSEL_TRANSPORT_MEANS_ID"/>
</xsd:restriction>
</xsd:simpleType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ boolean combinationExistsInConversionFactorListAndIsGreaterOrEqualToOne(List<FLU
boolean doesRuleExistInRulesTable(String brId, String context);

String findContextForDf(String dataFlow);

boolean validateIdFormatForMovementMessage(un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType id, DateTime dateTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, FactType.MOVEMENT_VESSEL_TRANSPORT_MEANS_ID);

private final String packageName;
private final String containerName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -850,4 +850,12 @@ private boolean isDateInRange(Date testDate, Date startDate, Date endDate) {
return testDate.after(startDate) && testDate.before(endDate);
}

@Override
public boolean validateIdFormatForMovementMessage(un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType id, DateTime dateTime) {
FormatExpression formatExpression = cache.getFormatsByIdentifier().get(id.getSchemeID());
return formatExpression != null &&
!StringUtils.isEmpty(formatExpression.getExpression()) &&
id.getValue().matches(formatExpression.getExpression()) &&
isValidDate(dateTime, formatExpression.getStartDate(), formatExpression.getEndDate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import un.unece.uncefact.data.standard.unqualifieddatatype._18.MeasureType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -59,7 +60,7 @@ public class FLUXVesselPositionMapper {
* @param registerClassName
* @return
*/
public static List<RawMovementType> mapToRawMovementTypes(FLUXVesselPositionMessage fluxVesselPositionMessage, String registerClassName, String pluginType, Map<String, MovementTypeType> mapToMovementType) {
public static List<RawMovementType> mapToRawMovementTypes(FLUXVesselPositionMessage fluxVesselPositionMessage, MovementVesselMappingContext ctx, String registerClassName, String pluginType, Map<String, MovementTypeType> mapToMovementType) {
VesselTransportMeansType positionReport = fluxVesselPositionMessage.getVesselTransportMeans();
List<RawMovementType> rowMovements = new ArrayList<>();
for (VesselPositionEventType col : positionReport.getSpecifiedVesselPositionEvents()) {
Expand All @@ -76,8 +77,25 @@ public static List<RawMovementType> mapToRawMovementTypes(FLUXVesselPositionMess
rawMovement.setPluginName(registerClassName);
rawMovement.setDateRecieved(DateUtils.getNowDateUTC());
rowMovements.add(rawMovement);
if(ctx != null) {
ctx.put(positionReport, rawMovement);
}
}
return rowMovements;
}

public static List<RawMovementType> mapToRawMovementTypesForEmptyMessage(FLUXVesselPositionMessage fluxVesselPositionMessage, String registerClassName, String pluginType, Map<String, MovementTypeType> mapToMovementType) {
VesselTransportMeansType positionReport = fluxVesselPositionMessage.getVesselTransportMeans();
MovementBaseType baseMovement = mapResponseForEmptyMovement(positionReport,pluginType ,mapToMovementType);
RawMovementType rawMovement = MovementMapper.getInstance().getMapper().map(baseMovement, RawMovementType.class);
final eu.europa.ec.fisheries.schema.rules.asset.v1.AssetId assetId = rawMovement.getAssetId();
if (assetId != null && assetId.getAssetIdList() != null) {
assetId.getAssetIdList().addAll(MovementMapper.mapAssetIdList(baseMovement.getAssetId().getAssetIdList()));
}
rawMovement.setPluginType(PluginType.FLUX.name());
rawMovement.setPluginName(registerClassName);
rawMovement.setDateRecieved(DateUtils.getNowDateUTC());
return Collections.singletonList(rawMovement);
}

private static MovementBaseType mapResponse(VesselPositionEventType response, VesselTransportMeansType report, String pluginType, Map<String, MovementTypeType> mapToMovementType) {
Expand All @@ -98,6 +116,18 @@ private static MovementBaseType mapResponse(VesselPositionEventType response, Ve
return movement;
}

private static MovementBaseType mapResponseForEmptyMovement(VesselTransportMeansType report, String pluginType, Map<String, MovementTypeType> mapToMovementType) {
MovementBaseType movement = new MovementBaseType();
HashMap<String, String> extractAssetIds = extractAssetIds(report.getIDS());
movement.setAssetId(mapToAssetId(extractAssetIds));
movement.setExternalMarking(extractAssetIds.get(ASSET_EXT_MARKING_CODE));
movement.setIrcs(extractAssetIds.get(ASSET_IRCS_CODE));
setFlagState(movement, report.getRegistrationVesselCountry());
movement.setComChannelType(MovementComChannelType.FLUX);
movement.setSource(MovementSourceType.MANUAL.name().equals(pluginType)? MovementSourceType.MANUAL : MovementSourceType.OTHER);
return movement;
}

private static void setFlagState(MovementBaseType movement, VesselCountryType registrationVesselCountry) {
if (registrationVesselCountry != null && registrationVesselCountry.getID() != null) {
movement.setFlagState(registrationVesselCountry.getID().getValue());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package eu.europa.ec.fisheries.uvms.rules.service.bean.movement;

import java.util.HashMap;
import java.util.Map;

import eu.europa.ec.fisheries.schema.rules.movement.v1.RawMovementType;
import eu.europa.ec.fisheries.wsdl.asset.types.Asset;
import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselTransportMeansType;

public class MovementVesselMappingContext {

private Map<VesselTransportMeansType, RawMovementType> vesselTransportMeansToRawMovement = new HashMap<>();

private Map<RawMovementType, Asset> rawMovementToAsset = new HashMap<>();

public void put(VesselTransportMeansType vesselTransportMeansType, RawMovementType rawMovementType) {
vesselTransportMeansToRawMovement.put(vesselTransportMeansType, rawMovementType);
}

public void put(RawMovementType rawMovementType, Asset asset) {
rawMovementToAsset.put(rawMovementType, asset);
}

public RawMovementType getRawMovement(VesselTransportMeansType vesselTransportMeansType) {
return vesselTransportMeansToRawMovement.get(vesselTransportMeansType);
}

public Asset getAsset(RawMovementType rawMovementType) {
return rawMovementToAsset.get(rawMovementType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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_VESSEL_MAP;
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;

Expand Down Expand Up @@ -270,21 +271,24 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri
String pluginType = request.getType().name();
String userName = request.getUsername();
String registeredPluginClassName = request.getRegisteredClassName();
MovementVesselMappingContext ctx = new MovementVesselMappingContext();
try {
fluxVesselPositionMessage = JAXBUtils.unMarshallMessage(request.getRequest(), FLUXVesselPositionMessage.class, null);
List<RawMovementType> movementReportsList = FLUXVesselPositionMapper.mapToRawMovementTypes(fluxVesselPositionMessage, registeredPluginClassName,pluginType,mapToMovementType);
List<RawMovementType> movementReportsList = FLUXVesselPositionMapper.mapToRawMovementTypes(fluxVesselPositionMessage, ctx, registeredPluginClassName,pluginType,mapToMovementType);
// If no movements were received then there is no sense to continue, so just going to update the exchange log status to FAILED!
if (CollectionUtils.isEmpty(movementReportsList)) {
log.warn("The list of rawMovements is EMPTY! Not going to proceed neither validation not sending to Movement Module!");
updateRequestMessageStatusInExchange(request.getLogGuid(), ExchangeLogStatusTypeType.FAILED);
sendBatchBackToExchange(request.getLogGuid(), movementReportsList, MovementRefTypeType.ALARM, userName);
return;
movementReportsList = FLUXVesselPositionMapper.mapToRawMovementTypesForEmptyMessage(fluxVesselPositionMessage, registeredPluginClassName,pluginType,mapToMovementType);
}

// Enrich with MobilTerminal and Assets data. Get Mobile Terminal if it exists.
EnrichedMovementWrapper enrichedWrapper = enrichBatchWithMobileTerminalAndAssets(movementReportsList, ctx);

Map<ExtraValueType, Object> 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_VESSEL_MAP, ctx);
Collection<AbstractFact> factsResults = rulesEngine.evaluate(RECEIVING_MOVEMENT_MSG,fluxVesselPositionMessage,extraValues,null);

final String reportId = fluxVesselPositionMessage.getFLUXReportDocument().getIDS().stream()
Expand All @@ -300,14 +304,14 @@ 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());
enrichAndSenMovementsAsBatch(validationResult, movementReportsList, enrichedWrapper, userName, request.getLogGuid(), request, request.getLogGuid());
// 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,
messageGuid, "Movement successfully processed");
movOutQueueProducer.sendMessageWithSpecificIds(JAXBMarshaller.marshallJaxBObjectToString(response), movOutQueueProducer.getDestination(), null, messageGuid, messageGuid);
}
} catch (JAXBException | RulesModelMarshallException | MessageException | RulesValidationException e) {
} catch (JAXBException | RulesModelMarshallException | MessageException | RulesValidationException | JMSException | MobileTerminalUnmarshallException | AssetModelMapperException | MobileTerminalModelMapperException e) {
log.error("Error while processing received movement", e);
}
}
Expand All @@ -322,10 +326,8 @@ public void setMovementReportReceived(SetFLUXMovementReportRequest request, Stri
* @param exchangeLogGuid
* @throws RulesServiceException
*/
private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, List<RawMovementType> rawMovements, String username, String exchangeLogGuid, SetFLUXMovementReportRequest request, String reportId) throws RulesServiceException {
private void enrichAndSenMovementsAsBatch(ValidationResult validationResult, List<RawMovementType> rawMovements, EnrichedMovementWrapper enrichedWrapper, String username, String exchangeLogGuid, SetFLUXMovementReportRequest request, String reportId) throws RulesServiceException {
try {
// Enrich with MobilTerminal and Assets data. Get Mobile Terminal if it exists.
EnrichedMovementWrapper enrichedWrapper = enrichBatchWithMobileTerminalAndAssets(rawMovements);
CreateMovementBatchResponse movementBatchResponse = sendBatchToMovement(enrichedWrapper.getAssetList(), rawMovements, username);
ExchangeLogStatusTypeType status;
if (movementBatchResponse != null && SimpleResponse.OK.equals(movementBatchResponse.getPermitted())) {
Expand All @@ -340,15 +342,15 @@ 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 | RulesModelException e) {
throw new RulesServiceException(e.getMessage(), e);
}
}

private void processReceivedMovementsAsBatch(List<RawMovementType> rawMovements, String pluginType, String username, String exchangeLogGuid) throws RulesServiceException {
try {
// Enrich with MobilTerminal and Assets data. Get Mobile Terminal if it exists.
EnrichedMovementWrapper enrichedWrapper = enrichBatchWithMobileTerminalAndAssets(rawMovements);
EnrichedMovementWrapper enrichedWrapper = enrichBatchWithMobileTerminalAndAssets(rawMovements, null);
List<RawMovementFact> rawMovementFactList = RawMovementFactMapper.mapRawMovementFacts(rawMovements, enrichedWrapper.getMobileTerminalList(),
enrichedWrapper.getAssetList(), pluginType);
movementValidator.evaluateRawList(rawMovementFactList);
Expand Down Expand Up @@ -387,7 +389,7 @@ private void processReceivedMovementsAsBatch(List<RawMovementType> rawMovements,
* @throws JMSException
* @throws MobileTerminalModelMapperException
*/
private EnrichedMovementWrapper enrichBatchWithMobileTerminalAndAssets(List<RawMovementType> rawMovementList) throws AssetModelMapperException, MessageException, MobileTerminalUnmarshallException, JMSException, MobileTerminalModelMapperException {
private EnrichedMovementWrapper enrichBatchWithMobileTerminalAndAssets(List<RawMovementType> rawMovementList, MovementVesselMappingContext ctx) throws AssetModelMapperException, MessageException, MobileTerminalUnmarshallException, JMSException, MobileTerminalModelMapperException {
List<Asset> assetList = new ArrayList<>();
// Get Mobile Terminal if it exists
List<MobileTerminalType> mobileTerminalList;
Expand All @@ -403,6 +405,7 @@ private EnrichedMovementWrapper enrichBatchWithMobileTerminalAndAssets(List<RawM
for (RawMovementType rawMovementType : rawMovementList) {
Asset asset = getAssetByCfrIrcs(rawMovementType.getAssetId());
assetList.add(asset);
ctx.put(rawMovementType, asset);
if (isPluginTypeWithoutMobileTerminal(rawMovementType.getPluginType()) && asset != null) {
MobileTerminalType mobileTerminal = findMobileTerminalByAsset(asset.getAssetId().getGuid());
rawMovementType.setMobileTerminal(MobileTerminalMapper.mapMobileTerminal(mobileTerminal));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package eu.europa.ec.fisheries.uvms.rules.service.business.fact;

import java.util.Arrays;
import java.util.List;

import eu.europa.ec.fisheries.schema.rules.template.v1.FactType;
import eu.europa.ec.fisheries.uvms.rules.service.business.AbstractFact;
import eu.europa.ec.fisheries.wsdl.asset.types.Asset;
import eu.europa.ec.fisheries.wsdl.asset.types.AssetIdType;
import lombok.Data;
import org.joda.time.DateTime;
import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselCountryType;
import un.unece.uncefact.data.standard.reusableaggregatebusinessinformationentity._18.VesselPositionEventType;
import un.unece.uncefact.data.standard.unqualifieddatatype._18.IDType;

@Data
public class MovementVesselTransportMeansFact extends AbstractFact {

private List<IDType> ids;
private DateTime creationDateTime;
private VesselCountryType registrationVesselCountry;
private List<VesselPositionEventType> specifiedVesselPositionEvents;
private Asset asset;

public boolean hasAtLeastTimesXNonEmptyIds(List<IDType> ids, int count) {
return ids.stream().filter(id -> id.getValue() != null && !id.getValue().isEmpty()).count() >= count;
}

public boolean hasAtLeastOneOfTheSchemeIds(List<IDType> ids, String... schemeIds) {
List<String> schemeIdsAsList = Arrays.asList(schemeIds);
return ids.stream().anyMatch(id -> schemeIdsAsList.contains(id.getSchemeID()));
}

public boolean hasBothSchemeIdsOrNone(List<IDType> ids, String schemeId1, String schemeId2) {
return ids.stream().anyMatch(id -> schemeId1.equals(id.getSchemeID())) == ids.stream().anyMatch(id -> schemeId2.equals(id.getSchemeID()));
}

public boolean hasAtLeastTimesXSpecifiedVesselPositionEvents(List<VesselPositionEventType> specifiedVesselPositionEvents, int count) {
return specifiedVesselPositionEvents.size() >= count;
}

public boolean hasSchemeId(List<IDType> ids, String schemeID){
return ids.stream().anyMatch(id -> schemeID.equals(id.getSchemeID()));
}

public boolean hasExistingAsset(Asset asset) {
return asset != null && asset.getAssetId() != null && AssetIdType.GUID.equals(asset.getAssetId().getType());
}
@Override
public void setFactType() {
this.factType = FactType.MOVEMENT_VESSEL_TRANSPORT_MEANS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ public class MovementVesselTransportMeansIdFact extends AbstractFact {
private IDType id;
private DateTime creationDateTime;

public boolean hasValidUvi(IDType id) {
int[] multipliers = {7,6,5,4,3,2};
String value = id.getValue();
int sum = 0;
for(int i = 0; i < 6; i++) {
sum += Integer.parseInt(value.substring(i, i + 1)) * multipliers[i];
}
return String.valueOf(value.charAt(6)).equals(String.valueOf(sum % 10));
}


@Override
public void setFactType() {
this.factType = FactType.MOVEMENT_VESSEL_TRANSPORT_MEANS_ID;
Expand Down
Loading