---------- Start of ./activityaddressing/TransitScheduledActivitiesAddressService.java ----------
package eu.reply.lea.services.yard.activityaddressing;

import java.io.InvalidClassException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;

import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.actions.request.HandlingRequestAddOrUpdateReferenceAction;
import eu.reply.lea.services.yard.boundary.HandlingRequestProcessor;
import eu.reply.lea.services.yard.entities.HandlingRequest;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.entities.ScheduledActivity;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exceptions.DockActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;

@ApplicationScoped
@Logged
public class TransitScheduledActivitiesAddressService implements ITransitScheduledActivitiesAddressService {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Inject
    private DefaultMasterdataService defaultMasterdataService;
    @Inject
    private HandlingRequestProcessor handlingRequestProcessor;

    @Transactional(Transactional.TxType.REQUIRES_NEW)
    @Override
    public void addressTransit(Transit transit) throws MasterdataServiceException, InvalidClassException, DockActionException,
        HandlingRequestActionException {
        Transit managedTransit = em.find(eu.reply.lea.services.yard.entities.Transit.class, transit.getId());
        Set<ScheduledActivity> activities = managedTransit.getScheduledActivities();
        Set<HandlingRequest> handlingRequests = managedTransit.getHandlingRequests();

        for (HandlingRequest handlingRequest : handlingRequests) {
            if (handlingRequest.getHandlingRequestActivities().size() > 0) {
                LoadingUnitReference loadingUnitRef = getLoadingUnitReference(handlingRequest);
                Set<ScheduledActivity> activitiesFilteredByType = filterActivitiesByHrType(activities, handlingRequest.getType());

                List<LocationReference> locations = activitiesFilteredByType.stream().map(a -> {
                    try {
                        return getLocationReferenceFromActivity(a);
                    } catch (MasterdataServiceException | InvalidClassException e) {
                        throw new RuntimeException(e);
                    }
                }).collect(Collectors.toList());
                HandlingRequestAddOrUpdateReferenceAction action = new HandlingRequestAddOrUpdateReferenceAction();
                action.setLocationReferences(locations);
                action.setLoadingUnitReference(loadingUnitRef);
                handlingRequestProcessor.action(handlingRequest,action);
            }
        }
    }

    private LoadingUnitReference getLoadingUnitReference(HandlingRequest handlingRequest) {
        Set<LoadingUnitResource> loadingUnits = handlingRequest.getUnits();
        if (loadingUnits.size() > 1) {
            throw new RuntimeException("[automatic addressing] More than one loading unit!");
        }
        LoadingUnitResource loadingUnit = loadingUnits.iterator().next();
        return new LoadingUnitReference(loadingUnit);
    }

    private Set<ScheduledActivity> filterActivitiesByHrType(Set<ScheduledActivity> activities, HandlingRequest.Type type) {
        return activities.stream()
            .filter(a -> a.getType() == type)
            .collect(Collectors.toSet());
    }

    private LocationReference getLocationReferenceFromActivity(ScheduledActivity activity)
        throws MasterdataServiceException, InvalidClassException {
        Dock dock = defaultMasterdataService.get( activity.getDockReference());
        if(dock == null ) {
            throw new RuntimeException(String.format("[automatic addressing] Dock not found for reference %s!",
                                                     activity.getDockReference().toString()));
        }
        return new LocationReference(dock);
    }

}




---------- End of ./activityaddressing/TransitScheduledActivitiesAddressService.java ----------

---------- Start of ./activityaddressing/AutomaticHandlingRequestActivityAddressing.java ----------
package eu.reply.lea.services.yard.activityaddressing;


import java.io.InvalidClassException;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.slf4j.Logger;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exceptions.DockActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException;
import eu.reply.sce.backend.core.jee.configuration.Configuration;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration.Module;
import eu.reply.sce.backend.core.jee.log.Logged;


@ApplicationScoped
@Logged
public class AutomaticHandlingRequestActivityAddressing {


    @Inject
    @Configuration.Property(defaultValue = "false")
    @Configuration.PerTenant
    private Configuration.PropertyInstance<Boolean> isAutomaticAddressingEnabled;

    @Inject
    @Module(Module.CURRENT)
    private EntityManager em;

    @Inject
    private Logger log;

    //region Logger Methods

    /**
     * The aim of this method is to use the debug method
     * to log debug information.
     *
     * @param message Message to be logged
     * @param params  Params used to construct log message.
     */
    protected void debug(String message, Object... params) {
        if (this.log != null) {
            this.log.debug(message, params);
        }
    }

    @Inject
    private ITransitScheduledActivitiesAddressService transitScheduledActivitiesAddressService;

    public void addressHandlingRequestActivities()
        throws MasterdataServiceException {
        if (!isAutomaticAddressingEnabled.get()) {
            return;
        }
        List<Transit> transitsToAddress = em.createQuery(
                "select t from Transit t where t.automaticAddressing = true and t.alreadyTriedAutomaticAddressing = false and (t.status = 'ARRIVED')",
                Transit.class)
            .getResultList();

        for (Transit transit : transitsToAddress) {
            try {
                transit.setAlreadyTriedAutomaticAddressing(true);
                transitScheduledActivitiesAddressService.addressTransit(transit);
            } catch (Exception e) {
                this.debug("Error while addressing transit {}.", transit.getId(), e);
            }
        }
    }
}

---------- End of ./activityaddressing/AutomaticHandlingRequestActivityAddressing.java ----------

---------- Start of ./activityaddressing/ITransitScheduledActivitiesAddressService.java ----------
package eu.reply.lea.services.yard.activityaddressing;

import java.io.InvalidClassException;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exceptions.DockActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException;

public interface ITransitScheduledActivitiesAddressService {
    void addressTransit(Transit transit) throws MasterdataServiceException, InvalidClassException, DockActionException,
        HandlingRequestActionException;
}

---------- End of ./activityaddressing/ITransitScheduledActivitiesAddressService.java ----------

---------- Start of ./ModuleConfiguration.java ----------
package eu.reply.lea.services.yard;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import eu.reply.sce.backend.core.jee.configuration.HibernateMultiTenantModuleConfiguration;

@ApplicationScoped
public class ModuleConfiguration extends HibernateMultiTenantModuleConfiguration {

    public static final String MODULE_NAME = Constants.YARD_SERVICE_NAME;

    @PersistenceContext(unitName = MODULE_NAME)
    private EntityManager em;

    public ModuleConfiguration() {
        super(MODULE_NAME);
    }

    @Produces
    @RequestScoped
    @Module(MODULE_NAME)
    @Override
    public EntityManager getEntityManager() {
        return super.getEntityManager();
    }

    @Override
    protected EntityManager getDelegate() {
        return em;
    }

    public static class ModuleConnectionProvider extends TenantConnectionProvider {
        private static final long serialVersionUID = 204565826149726312L;

        public ModuleConnectionProvider() {
            super(MODULE_NAME);
        }
    }

}
---------- End of ./ModuleConfiguration.java ----------

---------- Start of ./repository/TransitMovementRepository.java ----------
package eu.reply.lea.services.yard.repository;


import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;

import java.util.ArrayList;
import java.util.List;

import eu.reply.lea.services.yard.entities.TransitMovement;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;


@ApplicationScoped
@Logged
public class TransitMovementRepository {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    public List<TransitMovement> findByTransitReference(final TransitReference transitReference) {
        try{
            return em.createNamedQuery(TransitMovement.Q_FIND_BY_TRANSIT_REFERENCE, TransitMovement.class)
                .setParameter("module", transitReference.getModule())
                .setParameter("entityName", transitReference.getEntityName())
                .setParameter("entityId", transitReference.getEntityId())
                .getResultList();
        }catch (NoResultException noResultException){
            return new ArrayList<>();
        }
    }
}

---------- End of ./repository/TransitMovementRepository.java ----------

---------- Start of ./repository/LoadingUnitMovementRepository.java ----------
package eu.reply.lea.services.yard.repository;


import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import java.util.ArrayList;
import java.util.List;

import eu.reply.lea.services.yard.entities.LoadingUnitMovement;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;


@ApplicationScoped
@Logged
public class LoadingUnitMovementRepository {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    public List<LoadingUnitMovement> findByLoadingUnitRef(final LoadingUnitReference loadingUnitRef) {
        try{
            return em.createNamedQuery(LoadingUnitMovement.Q_FIND_BY_LOADING_UNIT, LoadingUnitMovement.class)
                .setParameter("module", loadingUnitRef.getModule())
                .setParameter("entityName", loadingUnitRef.getEntityName())
                .setParameter("entityId", loadingUnitRef.getEntityId())
                .getResultList();
        }catch (NoResultException noResultException){
            return new ArrayList<>();
        }
    }


}

---------- End of ./repository/LoadingUnitMovementRepository.java ----------

---------- Start of ./exception/TransitAlreadyPresentException.java ----------
package eu.reply.lea.services.yard.exception;

import eu.reply.sce.backend.core.exception.SerializableException;

import lombok.Getter;

public class TransitAlreadyPresentException extends SerializableException {

    @Getter
    Long transitId;

    public enum Codes {
        //@formatter:off
        ALREADY_PRESENT_FOR_APPOINTMENT("Can't create a new transit for the appointment, transit for the same "
                                        + "appointment code is "
                                        + "already created and active, "
                                        + "Transit id: [%s]");
        private String message;

        public String getMessage() {
            return message;
        }

        private Codes(final String message) {
            this.message = message;
        }
    }

    public TransitAlreadyPresentException(final Codes code, final Long transitId) {
        super(String.valueOf(code), String.format(code.getMessage(), transitId));

        this.transitId=transitId;
    }


}

---------- End of ./exception/TransitAlreadyPresentException.java ----------

---------- Start of ./observer/LoadingUnitMovementObserver.java ----------
package eu.reply.lea.services.yard.observer;

import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;

import eu.reply.lea.services.masterdata.model.Container;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.application.LoadingUnitMovementApplicationService;
import eu.reply.lea.services.yard.entities.LoadingUnitMovement;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.entities.LoadingUnitResourceRepository;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.entities.TransitMovement;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitChangedStatusEvent;
import eu.reply.lea.services.yard.events.movement.MovementStatusChangedEvent;
import eu.reply.lea.services.yard.model.ContainerResource;
import eu.reply.lea.services.yard.model.Movement;
import eu.reply.lea.services.yard.model.TrailerResource;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.lea.services.yard.util.ObjectMapperUtility;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.event.ModuleEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Observer
@Logged
@ApplicationScoped
public class LoadingUnitMovementObserver {

    @Inject
    private ConfigurableEventProducer<LoadingUnitChangedStatusEvent> loadingUnitChangedStatusEventProducer;

    @Inject
    private LoadingUnitMovementApplicationService loadingUnitMovementApplicationService;

    @Inject
    private LoadingUnitResourceRepository loadingUnitResourceRepository;


    public void onMovementStatusChanged(
        @Observes final MovementStatusChangedEvent  event)  {
        if (event.getPayload().getMovement().getLogisticUnitRef().getEntityName().equals(Transit.RESOURCE_NAME)){
            this.dispatch((TransitMovement) event.getPayload().getMovement());
        }else if (event.getPayload().getMovement().getLogisticUnitRef().getEntityName().equals(TrailerResource.RESOURCE_NAME)){
            this.dispatch((LoadingUnitMovement) event.getPayload().getMovement());
        }else if (event.getPayload().getMovement().getLogisticUnitRef().getEntityName().equals(ContainerResource.RESOURCE_NAME)){
            this.dispatch((LoadingUnitMovement) event.getPayload().getMovement());
        } else {
            throw new UnsupportedOperationException(
                "Unknown logistic unit for the movement: " + event.getPayload().getMovement().getLogisticUnitRef().getEntityName());
        }
    }

    private void dispatch(final TransitMovement movement) {
        if (movement.getStatus().equals(Movement.Status.EXECUTING)){
            List<LoadingUnitResource> loadingUnitResources =
                loadingUnitResourceRepository.findLoadingUnitByAttachedTransit(new TransitReference(movement.getLogisticUnitRef()));
            for (LoadingUnitResource loadingUnitResource : loadingUnitResources) {
                loadingUnitMovementApplicationService.createNewMovement(new LoadingUnitReference(loadingUnitResource), movement.getDestinationLocation());
            }
        } else if (movement.getStatus().equals(Movement.Status.COMPLETED)){
            List<LoadingUnitResource> loadingUnitResources =
                loadingUnitResourceRepository.findLoadingUnitByAttachedTransit(new TransitReference(movement.getLogisticUnitRef()));
            for (LoadingUnitResource loadingUnitResource : loadingUnitResources) {
                loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(loadingUnitResource), movement.getDestinationLocation());
            }
        }
    }

    private void dispatch(final LoadingUnitMovement movement) {
        LoadingUnitResource loadingUnitResource = loadingUnitResourceRepository.findByEntityRef(movement.getLoadingUnitRef());
        if (movement.getStatus().equals(Movement.Status.EXECUTING)){
            loadingUnitResource.moving(movement.getSourceLocation(), movement.getDestinationLocation(),
                                       loadingUnitChangedStatusEventProducer);
        } else if (movement.getStatus().equals(Movement.Status.COMPLETED)){
            loadingUnitResource.inPlace(movement.getDestinationLocation(), loadingUnitChangedStatusEventProducer);
        }
    }

    public void updateLoadingUnitLocation(
        @Observes @ModuleEvent("logisticUnitLocationUpdateCommand") final JsonNode event)
        throws JsonProcessingException {
        EntityReference
            logisticUnitRef =
            ObjectMapperUtility.getMapper().treeToValue(event.path("logisticUnitRef"), EntityReference.class);
        LocationReference
            locationReference =
            ObjectMapperUtility.getMapper().treeToValue(event.path("locationReference"), LocationReference.class);
        String
            areaType = ObjectMapperUtility.getMapper().treeToValue(event.path("areaType"), String.class);
        if ( logisticUnitRef==null || !(logisticUnitRef.getEntityName().equals(Container.RESOURCE_NAME) ||
                                        logisticUnitRef.getEntityName().equals(TrailerResource.RESOURCE_NAME))){
            return;
        }
        if (areaType.equals("WAITING_AREA") || areaType.equals("BOOKING_AREA")) {
            loadingUnitMovementApplicationService.createNewMovement(new LoadingUnitReference(logisticUnitRef), locationReference);
            loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(logisticUnitRef), locationReference);
        }
        if (areaType.equals("EXECUTION_AREA")) {
            loadingUnitMovementApplicationService.createNewMovement(new LoadingUnitReference(logisticUnitRef), locationReference);
        }
    }

    public void onTaskEnter(
        @Observes @ModuleEvent("completeMovementCommand") final JsonNode event) throws JsonProcessingException {
        EntityReference
            logisticUnitReference = ObjectMapperUtility.getMapper().treeToValue(event.path("logisticUnitReference"), EntityReference.class);
        LocationReference locationOfExecution = ObjectMapperUtility.getMapper().treeToValue(event.path("location"), LocationReference.class);
        if( logisticUnitReference!=null &&
            (logisticUnitReference.getEntityName().equals(Container.RESOURCE_NAME) ||
            logisticUnitReference.getEntityName().equals(TrailerResource.RESOURCE_NAME) )){
            loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(logisticUnitReference), locationOfExecution);
        }
    }
}

---------- End of ./observer/LoadingUnitMovementObserver.java ----------

---------- Start of ./observer/TransitMovementObserver.java ----------
package eu.reply.lea.services.yard.observer;


import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.application.TransitMovementApplicationService;
import eu.reply.lea.services.yard.model.Transit;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.lea.services.yard.util.ObjectMapperUtility;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.event.ModuleEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Observer
@Logged
@ApplicationScoped
public class TransitMovementObserver {

    @Inject
    private TransitMovementApplicationService transitMovementApplicationService;



    public void updateTransitPosition(
        @Observes @ModuleEvent("logisticUnitLocationUpdateCommand") final JsonNode event)
        throws JsonProcessingException {
        EntityReference
            logisticUnitRef =
            ObjectMapperUtility.getMapper().treeToValue(event.path("logisticUnitRef"), EntityReference.class);
        LocationReference
            locationReference =
            ObjectMapperUtility.getMapper().treeToValue(event.path("locationReference"), LocationReference.class);
        String
            areaType = ObjectMapperUtility.getMapper().treeToValue(event.path("areaType"), String.class);
        if ( logisticUnitRef==null || !logisticUnitRef.getEntityName().equals(Transit.RESOURCE_NAME) ){
            return;
        }
        if (areaType.equals("WAITING_AREA") || areaType.equals("BOOKING_AREA")) {
            transitMovementApplicationService.createNewMovement(new TransitReference(logisticUnitRef), locationReference);
            transitMovementApplicationService.completeMovement(new TransitReference(logisticUnitRef), locationReference);
        }
        if (areaType.equals("EXECUTION_AREA")) {
            transitMovementApplicationService.createNewMovement(new TransitReference(logisticUnitRef), locationReference);
        }
    }

    public void onTaskEnter(
        @Observes @ModuleEvent("completeMovementCommand") final JsonNode event) throws JsonProcessingException {
        EntityReference
            logisticUnitReference = ObjectMapperUtility.getMapper().treeToValue(event.path("logisticUnitReference"), EntityReference.class);
        LocationReference locationOfExecution = ObjectMapperUtility.getMapper().treeToValue(event.path("location"), LocationReference.class);
        if( logisticUnitReference!=null && logisticUnitReference.getEntityName().equals(Transit.RESOURCE_NAME) ){
            transitMovementApplicationService.completeMovement(new TransitReference(logisticUnitReference), locationOfExecution);
        }
    }


}

---------- End of ./observer/TransitMovementObserver.java ----------

---------- Start of ./observer/TransitCompletenessObserver.java ----------
package eu.reply.lea.services.yard.observer;


import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.application.TransitApplicationService;
import eu.reply.lea.services.yard.application.TransitMovementApplicationService;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.lea.services.yard.util.ObjectMapperUtility;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.event.ModuleEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Observer
@Logged
@ApplicationScoped
public class TransitCompletenessObserver {

    @Inject
    private TransitApplicationService transitApplicationService;


    public void onCompletenessCommand(
        @Observes @ModuleEvent("completeTransitCommand") final JsonNode event)
        throws JsonProcessingException {
        EntityReference
            transitReference =
            ObjectMapperUtility.getMapper().treeToValue(event.path("logisticUnitRef"), EntityReference.class);
        transitApplicationService.completeTransit(new TransitReference(transitReference));
    }



}

---------- End of ./observer/TransitCompletenessObserver.java ----------

---------- Start of ./observer/TransitObserver.java ----------
package eu.reply.lea.services.yard.observer;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.events.container.ContainerResourceSealRegisteredEvent;
import eu.reply.lea.services.yard.events.transit.TransitCancelledEvent;
import eu.reply.lea.services.yard.events.transit.TransitCheckedOutEvent;
import eu.reply.lea.services.yard.events.transit.TransitDeniedEvent;
import eu.reply.lea.services.yard.events.transit.TransitForcedOutEvent;
import eu.reply.lea.services.yard.events.transit.TransitStatusChangedEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration.Module;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Observer
@ApplicationScoped
public class TransitObserver {

    @Inject
    @Module(Module.CURRENT)
    private EntityManager em;

    @Inject
    private Producer<TransitStatusChangedEvent> transitStatusChangedEventProducer;

    public void activateTransitTransfer(@Observes final TransitCheckedOutEvent event) {
        activateTransitTransfer(event.getPayload());
    }

    public void activateTransitTransfer(@Observes final TransitForcedOutEvent event) {
        activateTransitTransfer(event.getPayload());
    }

    private void activateTransitTransfer(final eu.reply.lea.services.yard.model.Transit transit) {
        Transit transitTransfer = Transit.findByOriginTransitTransfer(em, transit);
        if(transitTransfer != null && Transit.Status.TRANSFER.equals(transitTransfer.getStatus())) {
            transitTransfer.waiting();
            transitStatusChangedEventProducer.fire(new TransitStatusChangedEvent(transitTransfer, Transit.Status.TRANSFER));
        }
    }

    public void cancelTransitTransfer(@Observes final TransitDeniedEvent event) {
        cancelTransitTransfer(event.getPayload().getTransit());
    }

    public void cancelTransitTransfer(@Observes final TransitCancelledEvent event) {
        cancelTransitTransfer(event.getPayload());
    }

    private void cancelTransitTransfer(final eu.reply.lea.services.yard.model.Transit transit) {
        Transit transitTransfer = Transit.findByOriginTransitTransfer(em, transit);
        if(transitTransfer != null && Transit.Status.TRANSFER.equals(transitTransfer.getStatus())) {
            transitTransfer.cancel();
            transitStatusChangedEventProducer.fire(new TransitStatusChangedEvent(transitTransfer, Transit.Status.TRANSFER));
        }
    }

}

---------- End of ./observer/TransitObserver.java ----------

---------- Start of ./observer/YardMessageListener.java ----------
package eu.reply.lea.services.yard.observer;

import javax.inject.Inject;
import javax.jms.MessageListener;
import javax.persistence.EntityManager;

import eu.reply.lea.services.yard.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration.Module;
import eu.reply.sce.backend.core.jee.jms.ModuleMessageListener;

public class YardMessageListener extends ModuleMessageListener implements MessageListener {

    @Inject
    @Module(Module.CURRENT)
    private EntityManager em;

    public YardMessageListener() {
        super(ModuleConfiguration.MODULE_NAME);
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

}

---------- End of ./observer/YardMessageListener.java ----------

---------- Start of ./entities/TrailerResource.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.util.List;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.validation.constraints.NotNull;

import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.sce.backend.core.entity.configuration.BusinessKey;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;

@Data
@RequiredArgsConstructor
@ToString(callSuper = true, of = {"licencePlate"})
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@NamedQueries({
    @NamedQuery(name = TrailerResource.Q_FIND_BY_PLATE,
        query = "select t from TrailerResource t where t.licencePlate = :licencePlate"),
    @NamedQuery(name = TrailerResource.Q_FIND_BY_PLATE_AND_STATUS,
        query = "select t from TrailerResource t where t.licencePlate = :licencePlate and not t.status = :status"),
    @NamedQuery(name = TrailerResource.Q_FIND_BY_CODE, query = "select t from TrailerResource t where t.code = :code")})
@StringifyAttributes(attributes = {"code"})
@BusinessKeySequence(prefix = "TRR", length = 10)
@BusinessKey(attributes = {"code"})
public class TrailerResource extends LoadingUnitResource implements eu.reply.lea.services.yard.model.TrailerResource {

    private static final long serialVersionUID = 832018754268773351L;

    public static final String Q_FIND_BY_CODE = "TrailerResource.findByCode";
    public static final String Q_FIND_BY_PLATE = "TrailerResource.findByPlate";
    public static final String Q_FIND_BY_PLATE_AND_STATUS = "TrailerResource.findByPlateAndStatus";

    public static final String P_CODE = "code";
    public static final String P_PLATE = "licencePlate";
    public static final String P_TRAILER = "trailer";
    public static final String P_STATUS = "status";


    //
    // Attributes
    //

    @NonNull
    @NotNull
    @Embedded
    private LicencePlate licencePlate; // Sync with masterdata

    public static TrailerResource findByCode(final EntityManager em, final String code) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_CODE, TrailerResource.class).setParameter(P_CODE, code).getSingleResult();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(code);
        }
    }

    public static List<TrailerResource> findBy(final EntityManager em, final LicencePlate licencePlate) {
        return em.createNamedQuery(Q_FIND_BY_PLATE, TrailerResource.class).setParameter(P_PLATE, licencePlate).getResultList();
    }

    public static List<TrailerResource> findByPlateAndStatus(final EntityManager em, final LicencePlate licencePlate,
                                                             final Status status) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_PLATE_AND_STATUS, TrailerResource.class)
                .setParameter(P_PLATE, licencePlate)
                .setParameter(P_STATUS, status).getResultList();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(TrailerResource.class.getSimpleName());
        }
    }

    public TrailerResource(final LicencePlate licencePlate, final LoadStatus loadStatus,
                           final ConfirmationStatus confirmationStatus, final Transit transit,
                           final BigDecimal inboundExpectedWeight, final BigDecimal outboundExpectedWeight,
                           final String inboundExpectedSeal, final String outboundExpectedSeal,
                           final LoadingUnitRegistry loadingUnitRegistry) {
        super(inboundExpectedWeight, outboundExpectedWeight, inboundExpectedSeal, outboundExpectedSeal, loadingUnitRegistry);
        this.licencePlate = licencePlate;
        this.setLoadStatus(loadStatus);
        this.setConfirmationStatus(confirmationStatus);
        this.setInboundTransit(transit);
    }

    public TrailerResource(final LicencePlate licencePlate, final LoadStatus loadStatus,
                           final ConfirmationStatus confirmationStatus, final Transit transit,
                           final LoadingUnitRegistry loadingUnitRegistry){
        super(loadingUnitRegistry);
        this.licencePlate = licencePlate;
        this.setLoadStatus(loadStatus);
        this.setConfirmationStatus(confirmationStatus);
        this.setInboundTransit(transit);
    }
}

---------- End of ./entities/TrailerResource.java ----------

---------- Start of ./entities/ExpectedTrailer.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.util.Objects;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.validation.constraints.NotNull;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;

import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;

@Data
@Entity
@StringifyAttributes(attributes = {"licencePlate"})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(callSuper = true, of = {"licencePlate"})
@EqualsAndHashCode(callSuper = false)
@NamedQuery(name = ExpectedTrailer.Q_FIND_BY_TRANSIT_AND_PLATE,
    query = "select et from ExpectedTrailer et where et.transit = :transit and et.licencePlate = :licencePlate")
public class ExpectedTrailer extends ExpectedLoadingUnit implements eu.reply.lea.services.yard.model.ExpectedTrailer {

    private static final long serialVersionUID = -8292709462473400690L;

    public static final String P_PLATE = "licencePlate";
    public static final String Q_FIND_BY_TRANSIT_AND_PLATE = "ExpectedTrailer.findByTransit";

    @NonNull
    @NotNull
    @ManyToOne(optional = false)
    @Setter(AccessLevel.PROTECTED)
    private Transit transit;

    @Embedded
    @NotNull
    private LicencePlate licencePlate;

    public ExpectedTrailer(final Transit transitTransfer, final LicencePlate licencePlate) {
        super(transitTransfer);
        this.licencePlate = licencePlate;
    }

    public ExpectedTrailer(final LicencePlate licencePlate) {
        super();
        this.licencePlate = licencePlate;
    }

    public ExpectedTrailer(final Transit transit, final LicencePlate licencePlate, final BigDecimal inboundWeight,
                           final BigDecimal outboundWeight) {
        super(transit, inboundWeight, outboundWeight);
        this.licencePlate = licencePlate;
    }

    public static ExpectedTrailer findBy(final EntityManager em, final Transit transit, final LicencePlate plate)
        throws eu.reply.sce.backend.core.entity.exception.EntityNotFoundException {
        try {
            //@formatter:off
            return em.createNamedQuery(Q_FIND_BY_TRANSIT_AND_PLATE, ExpectedTrailer.class)
                .setParameter(P_TRANSIT, transit)
                .setParameter(P_PLATE, plate).getSingleResult();
            //@formatter:on
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(ExpectedTrailer.class);
        }
    }

    public void setLicencePlate(final LicencePlate licencePlate) {
        this.licencePlate = licencePlate;
    }

    @Override
    @JsonIgnore
    public Object getIdentificationData() {
        return licencePlate;
    }

    @Override
    public String resourceName() {
        return ExpectedTrailer.class.getSimpleName();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ExpectedTrailer that = (ExpectedTrailer) o;
        return Objects.equals(licencePlate, that.licencePlate);
    }

    public TrailerResource createLoadingUnit(final LoadingUnitResource.LoadStatus loadStatus,
                                             final LoadingUnitRegistry loadingUnitRegistry) {
        TrailerResource trailerResource =
            new TrailerResource(this.getLicencePlate(), loadStatus, LoadingUnitResource.ConfirmationStatus.EXPECTED, this.getTransit(),
                                getInboundWeight(), getOutboundWeight(), getInboundSeal(), getOutboundSeal(),
                                loadingUnitRegistry);

        return trailerResource;

    }

    @Override
    public int hashCode() {
        return Objects.hash(licencePlate);
    }
}

---------- End of ./entities/ExpectedTrailer.java ----------

---------- Start of ./entities/ExpectedContainer.java ----------
package eu.reply.lea.services.yard.entities;

import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.validation.constraints.NotNull;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;

import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;

@Data
@Entity
@StringifyAttributes(attributes = {"transit", "bic"})
@ToString(callSuper = false, of = {"transit", "bic"})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(callSuper = false)
@NamedQuery(name = ExpectedContainer.Q_FIND_BY_TRANSIT_AND_BIC,
    query = "select et from ExpectedContainer et where et.transit = :transit and et.bic = :bic")
public class ExpectedContainer extends ExpectedLoadingUnit implements eu.reply.lea.services.yard.model.ExpectedContainer {

    private static final long serialVersionUID = 4691111880151638996L;

    private String bic;

    @NonNull
    @NotNull
    @ManyToOne(optional = false)
    @Setter(AccessLevel.PROTECTED)
    private Transit transit;

    public static final String Q_FIND_BY_TRANSIT_AND_BIC = "ExpectedContainer.findByTransit";

    public ExpectedContainer(final Transit transitTransfer, final String bic) {
        super(transitTransfer);
        this.bic = bic;
    }

    @Override
    @JsonIgnore
    public Object getIdentificationData() {
        return bic;
    }

    public void setBic(final String bic) {
        this.bic = bic;
    }

    @Override
    public String resourceName() {
        return ExpectedContainer.class.getSimpleName();
    }

    public ContainerResource createLoadingUnit(final LoadingUnitResource.LoadStatus loadStatus,
                                               final LoadingUnitRegistry loadingUnitRegistry) {
        ContainerResource containerResource = new ContainerResource(this.getBic(), loadStatus,
                                                                    LoadingUnitResource.ConfirmationStatus.EXPECTED, this.getTransit(),
                                                                    getInboundWeight(), getOutboundWeight(), getInboundSeal(),
                                                                    getOutboundSeal(),
                                                                    loadingUnitRegistry);

        return containerResource;

    }
}

---------- End of ./entities/ExpectedContainer.java ----------

---------- Start of ./entities/Transit.java ----------
package eu.reply.lea.services.yard.entities;

import java.util.*;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import eu.reply.lea.services.common.model.CodeSupport;

import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.sce.backend.core.entity.SpareData;

import lombok.*;
import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;

import eu.reply.lea.services.common.embedded.DrivingLicence;
import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.reference.CarrierReference;
import eu.reply.lea.services.masterdata.reference.DriverReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.masterdata.reference.TruckReference;
import eu.reply.lea.services.yard.exceptions.TransitActionException;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;

@Data
@RequiredArgsConstructor
@ToString(callSuper = false, of = {"code", "status", "carrier", "destinationSite"})
@EqualsAndHashCode(callSuper = false, exclude = {"inboundLoadingUnits", "outboundLoadingUnits", "handlingRequests", "expectedContainers", "expectedTrailers"})
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@Entity
@Table(indexes = {@Index(columnList = "status")}, uniqueConstraints = {@UniqueConstraint(columnNames = {"code"})})
@NamedQueries({@NamedQuery(name = Transit.Q_FIND_BY_CODE, query = "select t from Transit t where t.code = :code"),
    @NamedQuery(name = Transit.Q_FIND_BY_TRUCK_PLATE, query = "select t from Transit t where t.truckPlate = :truckPlate"),
    @NamedQuery(name = Transit.Q_FIND_BY_DRIVER, query = "select t from Transit t where t.drivingLicence = :license"),
    @NamedQuery(name = Transit.Q_FIND_BY_ORIGIN_TRANSIT_TRANSFER, query = "select t from Transit t where t.originTransitTransfer = :transit"),
    @NamedQuery(name = Transit.Q_FIND_BY_APP_CODE, query = "select t from Transit t where t.appointmentCode = :appointmentCode"),
    @NamedQuery(name = Transit.Q_FIND_BY_APP_CODE_AND_STATUS, query = "select t from Transit t where t.appointmentCode = :appointmentCode and t.status in :status "),
    @NamedQuery(name = Transit.Q_FIND_BY_UID_AND_STATUS_ADDRESSED_IN_COMPLETED, query = "select t from Transit t where (t.status = 'ARRIVED' OR t.status= 'IN' OR t.status='COMPLETED') AND t.uid = :uid")
})
@BusinessKeySequence(prefix = "TRS", length = 10)
@StringifyAttributes(attributes = {"code"})
public class Transit extends StandardEntity implements eu.reply.lea.services.yard.model.Transit , CodeSupport {

    private static final long serialVersionUID = -2340319447443215507L;

    public static final String Q_FIND_BY_TRUCK_PLATE = "Transit.findByTruckPlate";
    public static final String Q_FIND_BY_DRIVER = "Transit.findByDriver";

    public static final String Q_FIND_BY_APP_CODE = "Transit.findByAppCode";

    public static final String Q_FIND_BY_APP_CODE_AND_STATUS = "Transit.findByAppCodeAndStatus";
    public static final String Q_FIND_BY_CODE = "Transit.findByCode";
    public static final String Q_FIND_BY_ORIGIN_TRANSIT_TRANSFER = "Transit.findByOriginTransitTransfer";
    public static final String Q_FIND_BY_UID_AND_STATUS_ADDRESSED_IN_COMPLETED = "Transit.findTransitByUidAndStatusArrivedOrInOrCompleted";

    public static final String P_CODE = "code";
    public static final String P_APP_CODE = "appointmentCode";

    public static final String P_STATUS = "status";
    public static final String P_PLATE = "truckPlate";
    public static final String P_LICENSE = "license";
    public static final String P_TRANSIT = "transit";
    public static final String P_UID = "uid";

    //this flag tells us if this transit has been created from
    //an already existing appointment
    private Boolean scheduled = false;

    /**
     * In case all the documents related to the transit
     * was signed.
     */
    private Boolean areDocumentsSigned = false;

    //this flag tells us if the handling requests associated to this
    // transit need to be automatic addressed
    private Boolean automaticAddressing = false;

    //is useful when automaticAddressing = true.
    //It tells us if already addressed
    private Boolean alreadyTriedAutomaticAddressing = false;

    //mapping activity -> dock addressed
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<ScheduledActivity> scheduledActivities = new HashSet<>();

    @Embedded
    @Getter
    @Setter
    private SpareData spareData;

    @NotNull
    @Size(min = 1)
    @Column(updatable = false)
    private String code;

    private String uid;

    //Attached documents
    @OneToMany( cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AttachedDocument> documents = new HashSet<>();

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    @Setter(value = AccessLevel.PRIVATE)
    private Status status;

    @Enumerated(EnumType.STRING)
    private ReasonCode reasonCode;

    @Size(min = 1)
    private String reasonDescription;

    @Size(min = 1)
    private String notes;

    @JsonProperty(access = Access.READ_ONLY)
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar checkInDate;

    @JsonProperty(access = Access.READ_ONLY)
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar checkOutDate;

    @Temporal(TemporalType.TIMESTAMP)
    @Setter(AccessLevel.PRIVATE)
    private Calendar expectedRegistrationDateFrom;

    @Temporal(TemporalType.TIMESTAMP)
    @Setter(AccessLevel.PRIVATE)
    private Calendar expectedRegistrationDateTo;

    @Temporal(TemporalType.TIMESTAMP)
    private Calendar registrationDate;

    private boolean urgent = false;

    private boolean locked = false;

    private boolean forcedOut = false;

    /**
     * Acceptance of the disclaimer at transit level by the driver.
     */
    private boolean disclaimerAccepted = false;


    /**
     *  This code will be used by external system to link
     * a transit.
     */
    private String externalCode;

    private String appointmentCode;

    private Integer notificationMode;

    public Transit(String externalCode,
                   String appointmentCode,
                   LicencePlate expectedTruckPlate,
                   DrivingLicence expectedDrivingLicence,
                   SiteReference siteReference,
                   CarrierReference carrier,
                   Calendar expectedRegistrationDateFrom,
                   Calendar expectedRegistrationDateTo){
        this.setExternalCode(externalCode);
        if(appointmentCode!=null){
            this.setAppointmentCode(appointmentCode);
        }
        this.setExpectedTruckPlate(expectedTruckPlate);
        this.setExpectedDrivingLicence(expectedDrivingLicence);
        this.setDestinationSite(siteReference);
        this.setCarrier(carrier);
        this.setExpectedRegistrationDateFrom(expectedRegistrationDateFrom);
        this.setExpectedRegistrationDateTo(expectedRegistrationDateTo);
    }


    /**
     * Adds a new scheduled activity to a collection of activities.
     * This method creates a ScheduledActivity based on the provided handling request type and dock reference,
     * and then attempts to add it to the existing collection of scheduled activities. If the addition is successful,
     * it also triggers updating of related states such as enabling automatic addressing and adding the
     * related handling request.
     *
     * @param hrType The type of handling request associated with the new scheduled activity.
     * @param dockReference A reference to the dock where the activity is to be scheduled. This parameter cannot be null.
     * @return true if the scheduled activity is successfully added; false otherwise.
     * @throws IllegalArgumentException if dockReference is null, indicating that a valid dock reference is mandatory for scheduling an activity.
     */
    public boolean addScheduledActivity(HandlingRequest.Type hrType,
                                     DockReference dockReference){
        if (dockReference == null){
            throw new IllegalArgumentException("dockReference can't be null");
        }
        ScheduledActivity scheduledActivity = new ScheduledActivity(code, hrType, dockReference);
        if (this.addChild(scheduledActivity, scheduledActivities)) {
            this.setAutomaticAddressing(true);
            this.addHandlingRequest(new HandlingRequest(hrType));
            return true;
        }
        return false;
    }

    private void setAppointmentCode(String appointmentCode){
        this.setScheduled(true);
        this.appointmentCode = appointmentCode;
    }

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "plateNumber", column = @Column(name = "expt_plateNumber", length = 20)),
        @AttributeOverride(name = "plateCountry", column = @Column(name = "expt_plateCountry", length = 20))})
    private LicencePlate expectedTruckPlate;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "plateNumber", column = @Column(name = "real_plateNumber", length = 20)),
        @AttributeOverride(name = "plateCountry", column = @Column(name = "real_plateCountry", length = 20))})
    private LicencePlate truckPlate;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "licenceNumber", column = @Column(name = "expt_licenceNumber", length = 20)),
        @AttributeOverride(name = "licenceCountry", column = @Column(name = "expt_licenceCountry", length = 20))})
    private DrivingLicence expectedDrivingLicence;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "licenceNumber", column = @Column(name = "real_licenceNumber", length = 20)),
        @AttributeOverride(name = "licenceCountry", column = @Column(name = "real_licenceCountry", length = 20))})
    private DrivingLicence drivingLicence;

    @OneToMany(mappedBy = "inboundTransit", cascade = CascadeType.ALL, orphanRemoval = true)
    private final Set<LoadingUnitResource> inboundLoadingUnits = new HashSet<>();

    @OneToMany(mappedBy = "outboundTransit", orphanRemoval = true)
    private final Set<LoadingUnitResource> outboundLoadingUnits = new HashSet<>();

    @OneToMany(mappedBy = "transit", cascade = CascadeType.ALL, orphanRemoval = true)
    private final Set<HandlingRequest> handlingRequests = new HashSet<>();

    @OneToMany(mappedBy = "transit", cascade = CascadeType.ALL, orphanRemoval = true)
    private final Set<ExpectedTrailer> expectedTrailers = new HashSet<>();

    @OneToMany(mappedBy = "transit", cascade = CascadeType.ALL, orphanRemoval = true)
    private final Set<ExpectedContainer> expectedContainers = new HashSet<>();

    @NonNull
    @NotNull
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "entityName", column = @Column(name = "carrier_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "carrier_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "carrier_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "carrier_entityId", length = 50))})
    private CarrierReference carrier;

    @OneToOne
    private Transit originTransitTransfer;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "entityName", column = @Column(name = "osite_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "osite_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "osite_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "osite_entityId", length = 50))})
    private SiteReference originSite;

    @NonNull
    @NotNull
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "entityName", column = @Column(name = "dsite_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "dsite_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "dsite_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "dsite_entityId", length = 50))})
    private SiteReference destinationSite;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "entityName", column = @Column(name = "driver_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "driver_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "driver_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "driver_entityId", length = 50))})
    private DriverReference driver;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = " businessKey", column = @Column(name = "truck_businessKey")),
        @AttributeOverride(name = " entityName", column = @Column(name = "truck_entityName")),
        @AttributeOverride(name = " module", column = @Column(name = "truck_module", length = 20)),
        @AttributeOverride(name = " entityId", column = @Column(name = "truck_entityId", length = 50))})
    private TruckReference truck;

    //
    // Getters and Setters
    //

    public void updateRegistrationInformation(final Calendar expectedRegistrationDateFrom,final Calendar expectedRegistrationDateTo){
        this.setExpectedRegistrationDateFrom(expectedRegistrationDateFrom);
        this.setExpectedRegistrationDateTo(expectedRegistrationDateTo);
    }

    @Override
    public Set<LoadingUnitResource> getInboundLoadingUnits() {
        return Collections.unmodifiableSet(inboundLoadingUnits);
    }

    public boolean addInboundUnit(final LoadingUnitResource container) {
        if (this.addChild(container, inboundLoadingUnits)) {
            container.setInboundTransit(this);
            return true;
        }
        return false;
    }

    public boolean removeInboundUnit(final LoadingUnitResource container) {
        return this.removeChild(container, inboundLoadingUnits);
    }

    @Override
    public Set<LoadingUnitResource> getOutboundLoadingUnits() {
        return Collections.unmodifiableSet(outboundLoadingUnits);
    }

    public boolean addOutboundUnit(final LoadingUnitResource containerResource) {
        if (this.addChild(containerResource, outboundLoadingUnits)) {
            containerResource.setOutboundTransit(this);
            return true;
        }
        return false;
    }

    public boolean removeOutboundUnit(final LoadingUnitResource container) {
        return this.removeChild(container, outboundLoadingUnits);
    }

    public void setHandlingRequests(final Set<HandlingRequest> handlingRequests) {
        handlingRequests.forEach(h -> {
            if (!this.addHandlingRequest(h)) {
                try {
                    throw new TransitActionException(TransitActionException.Codes.IDENTICAL_HANDLING_REQUESTS, getCode());
                } catch (TransitActionException e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
        });
    }

    public boolean addHandlingRequest(final HandlingRequest handlingRequest) {
        if (this.addChild(handlingRequest, handlingRequests)) {
            handlingRequest.setTransit(this);
            return true;
        }
        return false;
    }

    public boolean removeHandlingRequest(final HandlingRequest handlingRequest) {
        return this.removeChild(handlingRequest, handlingRequests);
    }

    @Override
    public Set<HandlingRequest> getHandlingRequests() {
        return Collections.unmodifiableSet(handlingRequests);
    }


    public void setExpectedLoadingUnits(final Set<ExpectedLoadingUnit> expectedLoadingUnits) {
        expectedLoadingUnits.forEach(e -> {
            this.addExpectedLoadingUnit(e);
        });
    }

    public boolean addExpectedContainer(final ExpectedContainer expectedContainer) {
        if (this.addChild(expectedContainer, expectedContainers)) {
            expectedContainer.setTransit(this);
            return true;
        }
        return false;
    }

    public boolean removeExpectedContainer(final ExpectedContainer expectedContainer) {
        if (this.removeChild(expectedContainer, expectedContainers)) {
            expectedContainer.setTransit(null);
            return true;
        }
        return false;
    }

    public Set<ExpectedContainer> getExpectedContainers() {
        return Collections.unmodifiableSet(expectedContainers);
    }

    @Deprecated //Use the one with the possibility to insert the plate number. The implementation related to the creation of the expected trailer Entity should hidden inside the transit class.
    public boolean addExpectedTrailer(final ExpectedTrailer expectedTrailer) {
        if (this.addChild(expectedTrailer, expectedTrailers)) {
            expectedTrailer.setTransit(this);
            return true;
        }
        return false;
    }

    /**
     * Adds an expected trailer to the transit using its licence plate.
     * This method creates an ExpectedTrailer instance from the given licence plate and attempts to add it to the collection
     * of expected trailers. If successful, it associates the trailer with the current transit.
     *
     * @param licencePlate The licence plate of the trailer to be added. This is a crucial identifier and cannot be null.
     * @return true if the expected trailer is successfully added to the collection; false otherwise.
     * @throws IllegalArgumentException if the licencePlate is null, indicating that a valid licence plate is required to add an expected trailer.
     */
    public boolean addExpectedTrailer(final LicencePlate licencePlate) {
        if (licencePlate == null){
            throw new IllegalArgumentException("licencePlate can't be null");
        }
        ExpectedTrailer expectedTrailer = new ExpectedTrailer(licencePlate);
        if (this.addChild(expectedTrailer, expectedTrailers)) {
            expectedTrailer.setTransit(this);
            return true;
        }
        return false;
    }


    public boolean removeExpectedTrailer(final ExpectedTrailer expectedTrailer) {
        if (this.removeChild(expectedTrailer, expectedTrailers)) {
            expectedTrailer.setTransit(null);
            return true;
        }
        return false;
    }

    public Set<ExpectedTrailer> getExpectedTrailers() {
        return Collections.unmodifiableSet(expectedTrailers);
    }

    @Override
    @JsonIgnore
    public Set<? extends ExpectedLoadingUnit> getExpectedLoadingUnits() {
        Set<ExpectedLoadingUnit> expectedUnits = new HashSet<>();
        expectedUnits.addAll(expectedTrailers);
        expectedUnits.addAll(expectedContainers);
        return Collections.unmodifiableSet(expectedUnits);
    }

    //
    // Methods
    //

    /**
     * set TransitStatus to DENIED
     */
    public void deny() {
        setStatus(Status.DENIED);
    }

    /**
     * set TransitStatus to WAITING
     */
    public void waiting() {
        setStatus(Status.WAITING);
    }

    /**
     * set TransitStatus to ARRIVED
     */
    public void arrived() {
        setStatus(Status.ARRIVED);
    }

    /**
     * set TransitStatus to IN
     */
    public void in() {
        setStatus(Status.IN);
        setCheckInDate(Calendar.getInstance());
        //this.getInboundLoadingUnits().stream().forEach(t -> t.moving());
    }

    public void fromCompletedToIn(){
        if (getStatus()!= Status.COMPLETED){
            throw new RuntimeException("You can only change the status from Completed To In");
        }
        setStatus(Status.IN);
    }

    /**
     * set TransitStatus to COMPLETED
     */
    public void complete() {
        setStatus(Status.COMPLETED);
    }

    /**
     * set TransitStatus to OUT
     */
    public void out() {
        setStatus(Status.OUT);
        setCheckOutDate(Calendar.getInstance());
    }

    /**
     * set TransitStatus to CANCELED
     */
    public void cancel() {
        setStatus(Status.CANCELED);
    }

    /**
     * set TransitStatus to TRANSFER
     */
    public void transfer() {
        setStatus(Status.TRANSFER);
    }

    /**
     * set locked to true
     *
     * @param reasonCode
     * @param reasonDescription
     */
    public void lock(@NonNull final Transit.ReasonCode reasonCode, final String reasonDescription) {
        this.locked = true;
        this.setReasonCode(reasonCode);
        this.setReasonDescription(reasonDescription);
    }

    /**
     * set locked to false
     */
    public void unlock() {
        this.locked = false;
    }

    /**
     * @return the flag locked
     */
    @Override
    public boolean isLocked() {
        return locked;
    }

    /**
     * Set urgent to true
     *
     * @param notes optional notes
     */
    public void urgent(final String notes) {
        this.urgent = true;
        if (StringUtils.isNotBlank(notes)) {
            this.setNotes(notes);
        }
    }

    /**
     * set urgent to false
     */
    public void notUrgent() {
        this.urgent = false;
    }

    /**
     * set forcedOut to true
     */
    public void forceOut() {
        this.out();
        this.forcedOut = true;
    }

    /**
     * @return the flag forcedOut
     */
    @Override
    public boolean isForcedOut() {
        return forcedOut;
    }

    //
    // Queries
    //

    public static Transit findBy(final EntityManager em, final String code) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_CODE, Transit.class).setParameter(P_CODE, code).getSingleResult();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(Transit.class.getSimpleName(), code);
        }
    }

    public static Transit findByCode(final EntityManager em, final String code) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_CODE, Transit.class).setParameter(P_CODE, code).getSingleResult();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(Transit.class.getSimpleName(), code);
        }
    }

    public static List<Transit> findByTruckPlate(final EntityManager em, final LicencePlate plate) {
        return em.createNamedQuery(Q_FIND_BY_TRUCK_PLATE, Transit.class).setParameter(P_PLATE, plate).getResultList();
    }

    public static List<Transit> findByDriver(final EntityManager em, final DrivingLicence driver) {
        return em.createNamedQuery(Q_FIND_BY_DRIVER, Transit.class).setParameter(P_LICENSE, driver).getResultList();
    }

    public static List<Transit> findByAppointmentCode(final EntityManager em, final String appointmentCode) {
        return em.createNamedQuery(Q_FIND_BY_APP_CODE, Transit.class).setParameter(P_APP_CODE, appointmentCode).getResultList();
    }

    public static Transit findByOriginTransitTransfer(final EntityManager em, final eu.reply.lea.services.yard.model.Transit transit) {
        try {
            return em.createNamedQuery(Q_FIND_BY_ORIGIN_TRANSIT_TRANSFER, Transit.class).setParameter(P_TRANSIT, transit).getSingleResult();
        } catch (final NoResultException e) {
            return null;
        }
    }

    /**
     * Get a request to database
     * to check if there is at least one transit
     * with uid given in input
     * and status = arrived or status = in or status = completed
     *
     * @param em  Entity Manager
     * @param uid UniversalIdentifier
     * @return
     */
    public static List<Transit> findTransitByUidAndStatusArrivedOrInOrCompleted(final EntityManager em, final String uid) {
        try {
            return em.createNamedQuery(Q_FIND_BY_UID_AND_STATUS_ADDRESSED_IN_COMPLETED, Transit.class).setParameter(P_UID, uid).getResultList();
        } catch (final NoResultException e) {
            return null;
        }
    }

    public boolean removeExpectedLoadingUnit(final ExpectedLoadingUnit expectedUnit) {
        if (expectedUnit instanceof ExpectedContainer) {
            return this.removeExpectedContainer((ExpectedContainer) expectedUnit);
        } else if (expectedUnit instanceof ExpectedTrailer) {
            return this.removeExpectedTrailer((ExpectedTrailer) expectedUnit);
        } else {
            return false;
        }
    }

    public boolean addExpectedLoadingUnit(final ExpectedLoadingUnit expectedUnit) {

        if (expectedUnit instanceof ExpectedContainer) {
            return this.addExpectedContainer((ExpectedContainer) expectedUnit);
        } else if (expectedUnit instanceof ExpectedTrailer) {
            return this.addExpectedTrailer((ExpectedTrailer) expectedUnit);
        } else {
            return false;
        }
    }
}

---------- End of ./entities/Transit.java ----------

---------- Start of ./entities/AttachmentReference.java ----------
package eu.reply.lea.services.yard.entities;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.annotation.Nonnull;
import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;


// Reference to an attachment of class Attachment present in SCE-Backend
@Embeddable
@Getter
@Setter
@NoArgsConstructor
public class AttachmentReference  implements Serializable {


    @NotNull
    @Size(min = 1)
    private String uuid; //Identifier of the Attacchment.

    public AttachmentReference(@Nonnull final String uuid) {
        if(uuid.isBlank()){
            throw new IllegalArgumentException("uuid" + " must not be blank");
        }
        this.uuid = uuid;
    }








}
---------- End of ./entities/AttachmentReference.java ----------

---------- Start of ./entities/LoadingUnitResource.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.common.embedded.GeoCoding;
import eu.reply.lea.services.common.model.EntityConstants;
import eu.reply.lea.services.masterdata.model.HaveGeoCoding;
import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.lea.services.masterdata.reference.LoadingUnitRegistryReference;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.yard.events.LoadingUnitDetachedFromTransitEventInfo;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitAttachedToTransitEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitChangedStatusEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitDetachedFromTransitEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitInboundExpectedSealChangedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitInboundExpectedSealChangedInfo;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitInboundExpectedWeightChangedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitInboundExpectedWeightChangedInfo;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitOutboundExpectedSealChangedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitOutboundExpectedSealChangedInfo;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitOutboundExpectedWeightChangedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitOutboundExpectedWeightChangedInfo;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.jee.event.Producer;

@Data
@ToString(of = {"code", "loadStatus", "confirmationStatus", "actualSealStatus", "droppable", "attachedVehicle"})
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"code", "status", "inboundTransit_id", "outboundTransit_id"}))
@EqualsAndHashCode(callSuper = false, exclude = {"inboundTransit", "outboundTransit", "attachedVehicle"})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
@NamedQueries({
    @NamedQuery(name = LoadingUnitResource.Q_FIND_BY_ATTACHED_TRANSIT, query =
        "select lu from LoadingUnitResource lu "
        + "where  lu.attachedTransit.entityId = :transitId and lu.status != 'OUT' ")
})
public abstract class LoadingUnitResource extends StandardEntity
    implements eu.reply.lea.services.yard.model.LoadingUnitResource, HaveGeoCoding {

    public static final String Q_FIND_BY_ATTACHED_TRANSIT = "LoadingUnitResource.Q_FIND_BY_ATTACHED_TRANSIT";
    private static final long serialVersionUID = 7990674516230010979L;

    @OneToMany(mappedBy = "loadingUnit", cascade = CascadeType.ALL, orphanRemoval = true)
    private final Set<CreateMissionRequest> sendRequests = new HashSet<>();

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AttachedDocument> documents = new HashSet<>();

    @NotNull
    @Size(min = 1)
    @Column(updatable = false)
    private String code;

    @Setter(AccessLevel.PRIVATE)
    private boolean droppable = false;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private LoadStatus loadStatus;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private ConfirmationStatus confirmationStatus;

    @Enumerated(EnumType.STRING)
    private SealStatus inboundSealStatus;

    @Size(min = 1)
    @Column(length = 30)
    @Setter(AccessLevel.PRIVATE)
    private String inboundRegisteredSeal;

    @Size(min = 1)
    @Column(length = 30)
    @Setter(AccessLevel.PRIVATE)
    private String outboundRegisteredSeal;
    @Size(min = 1)
    @Column(length = 30)
    @Setter(AccessLevel.PRIVATE)
    private String inboundExpectedSeal;

    @Size(min = 1)
    @Column(length = 30)
    @Setter(AccessLevel.PRIVATE)
    private String outboundExpectedSeal;


    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    @Setter(AccessLevel.PRIVATE)
    private BigDecimal outboundExpectedWeight;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    @Setter(AccessLevel.PRIVATE)
    private BigDecimal inboundExpectedWeight;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    @Setter(AccessLevel.PRIVATE)
    private BigDecimal outboundRegisteredWeight;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    @Setter(AccessLevel.PRIVATE)
    private BigDecimal inboundRegisteredWeight;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    private BigDecimal tare;

    @NonNull
    @NotNull
    @ManyToOne(optional = false)
    private Transit inboundTransit;

    @ManyToOne()
    private Transit outboundTransit;

    @Embedded
    @AttributeOverrides(
        {@AttributeOverride(name = "module", column = @Column(name = "last_loc_module")),
            @AttributeOverride(name = "entityName", column = @Column(name = "last_loc_entityName")),
            @AttributeOverride(name = "entityId", column = @Column(name = "last_loc_entityId")),
            @AttributeOverride(name = "businessKey", column = @Column(name = "last_loc_businessKey"))})
    private LocationReference lastLocation;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "module", column = @Column(name = "next_loc_module")),
        @AttributeOverride(name = "entityName", column = @Column(name = "next_loc_entityName")),
        @AttributeOverride(name = "entityId", column = @Column(name = "next_loc_entityId")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "next_loc_businessKey"))})
    private LocationReference nextLocation;


    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "module", column = @Column(name = "atc_vehicle_module")),
        @AttributeOverride(name = "entityName", column = @Column(name = "atc_vehicle_entityName")),
        @AttributeOverride(name = "entityId", column = @Column(name = "atc_vehicle_entityId")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "atc_vehicle_businessKey"))})
    private VehicleReference attachedVehicle;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "module", column = @Column(name = "transit_module")),
        @AttributeOverride(name = "entityName", column = @Column(name = "transit_entityName")),
        @AttributeOverride(name = "entityId", column = @Column(name = "transit_entityId")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "transit_businessKey"))})
    @Setter(AccessLevel.PRIVATE)
    private TransitReference attachedTransit;

    @Embedded
    private GeoCoding geocoding;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    @Setter(AccessLevel.NONE)
    private Status status = TrailerResource.Status.PARKED;

    @Embedded
    @Setter(value = AccessLevel.PRIVATE)
    private LoadingUnitRegistryReference loadingUnitRegistryReference;

    public LoadingUnitResource(final BigDecimal inboundExpectedWeight, final BigDecimal outboundExpectedWeight,
                               final String inboundExpectedSeal, final String outboundExpectedSeal,
                               final LoadingUnitRegistry loadingUnitRegistry) {
        this.setInboundExpectedWeight(inboundExpectedWeight);
        this.setOutboundExpectedWeight(outboundExpectedWeight);
        this.setOutboundExpectedSeal(outboundExpectedSeal);
        this.setInboundExpectedSeal(inboundExpectedSeal);
        this.configureLoadingUnitRegistryReference(loadingUnitRegistry);
    }

    public LoadingUnitResource(final LoadingUnitRegistry loadingUnitRegistry) {
        this.configureLoadingUnitRegistryReference(loadingUnitRegistry);
    }

    private void configureLoadingUnitRegistryReference(final LoadingUnitRegistry loadingUnitRegistry) {
        this.loadingUnitRegistryReference = new LoadingUnitRegistryReference(loadingUnitRegistry);
        this.setDroppable(loadingUnitRegistry.isDroppable());
    }

    public boolean isMoving(){
        return TrailerResource.Status.isMoving(this.getStatus());
    }

    public void registerInboundWeight(final BigDecimal inboundWeight) {
        setInboundRegisteredWeight(inboundWeight);
    }

    public void registerOutboundWeight(final BigDecimal outboundWeight) {
        setOutboundRegisteredWeight(outboundWeight);
    }

    public void registerInboundExpectedWeight(final BigDecimal inboundExpectedWeight,
                                              Producer<LoadingUnitInboundExpectedWeightChangedEvent> eventProducer) {
        if (getInboundRegisteredWeight() != null) {
            throw new IllegalStateException("It's not possible to modify the expected weight if the "
                                            + "weight has already been measured");
        }
        setInboundExpectedWeight(inboundExpectedWeight);
        eventProducer.fire(new LoadingUnitInboundExpectedWeightChangedEvent(
            new LoadingUnitInboundExpectedWeightChangedInfo(getInboundExpectedWeight(), new LoadingUnitReference(this))
        ));
    }

    public void registerOutboundExpectedWeight(final BigDecimal outboundExpectedWeight,
                                               Producer<LoadingUnitOutboundExpectedWeightChangedEvent> eventProducer) {
        if (getOutboundRegisteredWeight() != null) {
            throw new IllegalStateException("It's not possible to modify the expected weight if the "
                                            + "weight has already been measured");
        }
        setOutboundExpectedWeight(outboundExpectedWeight);
        eventProducer.fire(new LoadingUnitOutboundExpectedWeightChangedEvent(
            new LoadingUnitOutboundExpectedWeightChangedInfo(getOutboundExpectedWeight(), new LoadingUnitReference(this))
        ));
    }

    public void registerInboundExpectedSeal(final String inboundExpectedSeal,
                                            Producer<LoadingUnitInboundExpectedSealChangedEvent> eventProducer) {
        if (getInboundRegisteredSeal() != null) {
            throw new IllegalStateException("It's not possible to modify the expected seal if the "
                                            + "weight has already been measured");
        }
        setInboundExpectedSeal(inboundExpectedSeal);
        eventProducer.fire(new LoadingUnitInboundExpectedSealChangedEvent(
            new LoadingUnitInboundExpectedSealChangedInfo(getInboundExpectedSeal(), new LoadingUnitReference(this))
        ));
    }

    public void registerOutboundExpectedSeal(final String outboundExpectedSeal,
                                             Producer<LoadingUnitOutboundExpectedSealChangedEvent> eventProducer) {
        if (getOutboundRegisteredSeal() != null) {
            throw new IllegalStateException("It's not possible to modify the expected seal if the "
                                            + "weight has already been measured");
        }
        setOutboundExpectedSeal(outboundExpectedSeal);
        eventProducer.fire(new LoadingUnitOutboundExpectedSealChangedEvent(
            new LoadingUnitOutboundExpectedSealChangedInfo(getOutboundExpectedSeal(), new LoadingUnitReference(this))
        ));
    }

    public void registerInboundSeal(final String inboundSeal, final SealStatus sealStatus) {
        checkSealStatusValidity(inboundSeal, sealStatus);
        setInboundRegisteredSeal(inboundSeal);
        setInboundSealStatus(sealStatus);
    }

    public void registerOutboundSeal(final String outboundSeal) {
        setOutboundRegisteredSeal(outboundSeal);
    }

    private void checkSealStatusValidity(final String outboundSeal, final SealStatus sealStatus) {
        if (sealStatus == null) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.SEAL_STATUS_MISSING, this.getCode());
        }
        if (SealStatus.MISSING.equals(sealStatus) && !StringUtils.isBlank(outboundSeal)) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.SEAL_CODE_NOT_EXPECTED, this.getCode());
        }
        if (!SealStatus.MISSING.equals(sealStatus) && StringUtils.isBlank(outboundSeal)) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.SEAL_CODE_MISSING, this.getCode());
        }
    }


    private void setStatus(final Status status,
                           final ConfigurableEventProducer<LoadingUnitChangedStatusEvent> eventProducer){
        Objects.requireNonNull(status);
        this.status = status;
        eventProducer.fire(new LoadingUnitChangedStatusEvent(this));
    }

    /**
     * Set the status to {@link eu.reply.lea.services.yard.model.LoadingUnitResource.Status.MOVING}
     *
     * @param lastLocation Start Location for the LU
     * @param nextLocation End Location for the LU
     */
    public void moving(final LocationReference lastLocation,
                       final LocationReference nextLocation,
                       final ConfigurableEventProducer<LoadingUnitChangedStatusEvent> eventProducer) {
        setStatus(Status.MOVING,eventProducer);
        setLastLocation(lastLocation);
        setNextLocation(nextLocation);

    }

    /**
     * Set the status to {@link eu.reply.lea.services.yard.model.LoadingUnitResource.Status.IN_PLACE}
     *
     * @param lastLocation End Location for the LU
     */
    public void inPlace(final LocationReference lastLocation,
                        final ConfigurableEventProducer<LoadingUnitChangedStatusEvent> eventProducer) {
        setStatus(Status.IN_PLACE,eventProducer);
        setLastLocation(lastLocation);
        setNextLocation(null);
    }

    /**
     * Set the status to {@link eu.reply.lea.services.yard.model.LoadingUnitResource.Status.PARK}
     *
     * @param lastLocation End Location for the LU
     */
    public void park(final LocationReference lastLocation,
                     final ConfigurableEventProducer<LoadingUnitChangedStatusEvent> eventProducer) {
        setStatus(Status.PARKED,eventProducer);
        setLastLocation(lastLocation);
        setNextLocation(null);
    }

    /**
     * Set the status to {@link eu.reply.lea.services.yard.model.LoadingUnitResource.Status.OUT}
     */
    public void out(final ConfigurableEventProducer<LoadingUnitChangedStatusEvent> eventProducer) {
        setStatus(Status.OUT,eventProducer);
        setNextLocation(null);
    }


    @Override
    public boolean isAttachedTo(final VehicleReference vehicle) {
        return isAttachedToAVehicle() && getAttachedVehicle().equals(vehicle);
    }

    @Override
    public boolean attachToVehicle(final VehicleReference vehicle) {
        this.attachedVehicle = vehicle;
        return true;
    }

    public void attachTransit(final TransitReference attachedTransit, final ConfigurableEventProducer<LoadingUnitAttachedToTransitEvent> eventProducer) {
        Objects.requireNonNull(attachedTransit);
        if (this.attachedTransit == null || !this.attachedTransit.equals(attachedTransit)){
            this.attachedTransit = attachedTransit;
            eventProducer.fire(new LoadingUnitAttachedToTransitEvent(this, Instant.now()));
        }
    }

    @Override
    public boolean isAttachedToAVehicle() {
        return this.attachedVehicle != null;
    }

    @Override
    public void releaseFromAttachedVehicle(final ConfigurableEventProducer<LoadingUnitDetachedFromTransitEvent> eventProducer) {
        TransitReference oldAttachedTransit = this.attachedTransit;
        this.attachedVehicle = null;
        if (this.attachedTransit != null) {
            this.attachedTransit = null;
            eventProducer.fire(new LoadingUnitDetachedFromTransitEvent(
                new LoadingUnitDetachedFromTransitEventInfo(this, oldAttachedTransit,
                                                            this.lastLocation, this.resourceName(),
                                                            Instant.now())));
        }
    }
}




---------- End of ./entities/LoadingUnitResource.java ----------

---------- Start of ./entities/Tag.java ----------
package eu.reply.lea.services.yard.entities;

import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;


/**
 * The tags are particular strings
 * which have to be unique.
 * They are used to tag documents.*/
@Entity
@Setter
@Getter
@StringifyAttributes(attributes = {"tag"})
public class Tag extends StandardEntity {

    @Column(unique = true)
    @NotNull
    private String tag;


}

---------- End of ./entities/Tag.java ----------

---------- Start of ./entities/HandlingRequest.java ----------
package eu.reply.lea.services.yard.entities;

import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.ObjectUtils;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.exceptions.TransitActionException;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.BusinessKey;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Data
@RequiredArgsConstructor
@ToString(callSuper = false, of = { "transit", "type", "status" })
@EqualsAndHashCode(callSuper = false, exclude = { "units", "expectedUnits", "handlingRequestActivities" })
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(columnNames = { "transit_id", "type", "location_entityName", "location_entityId", "location_module" }) })
@NamedQueries({
        @NamedQuery(name = HandlingRequest.Q_FIND_BY_TRAILER, query = "select hr from HandlingRequest hr JOIN hr.handlingRequestActivities ta where ta.loadingUnit.id = :id") })
@StringifyAttributes(attributes = { "transit", "type", "status" })
@BusinessKeySequence(prefix = "HRQ", length = 10)
@BusinessKey(attributes = {"transit","type"})
public class HandlingRequest extends StandardEntity implements eu.reply.lea.services.yard.model.HandlingRequest {

    private static final long serialVersionUID = 8959965302830732917L;

    public static final String Q_FIND_BY_TRAILER = "HandlingRequest.findByExpectedTrailer";

    public static final String P_ID = "id";

    @NotNull
    @ManyToOne(optional = false)
    private Transit transit;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private Type type;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private Status status = Status.TODO;

    @Enumerated(EnumType.STRING)
    private ConfirmationStatus confirmationStatus;

    @Temporal(TemporalType.TIMESTAMP)
    private Calendar scheduledStart;

    @Temporal(TemporalType.TIMESTAMP)
    private Calendar scheduledEnd;

    @ManyToMany
    @Setter(value = AccessLevel.PROTECTED)
    private Set<LoadingUnitResource> units = new HashSet<>();

    @ManyToMany
    @Setter(value = AccessLevel.PROTECTED)
    private Set<ExpectedLoadingUnit> expectedUnits = new HashSet<>();

    @Setter(value = AccessLevel.PROTECTED)
    @OneToMany(mappedBy = "handlingRequest", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("positionIndex")
    private Set<HandlingRequestActivity> handlingRequestActivities = new LinkedHashSet<>();

    @Embedded
    @AttributeOverrides(value = { @AttributeOverride(name = "entityName", column = @Column(name = "location_entityName")),
            @AttributeOverride(name = "module", column = @Column(name = "location_module")),
            @AttributeOverride(name = "entityId", column = @Column(name = "location_entityId")),
            @AttributeOverride(name = "businessKey", column = @Column(name = "location_businessKey")) })
    private LocationReference location;

    public HandlingRequest(final Transit transit, @NonNull final Type type, @NonNull final Status status, final ConfirmationStatus confirmationStatus) {
        super();
        this.transit = transit;
        this.type = type;
        this.status = status;
        this.confirmationStatus = confirmationStatus;
    }

    public boolean addTrailer(final TrailerResource trailer) {
        return this.addChild(trailer, units);
    }

    public boolean addUnit(final LoadingUnitResource unit) {
        return this.addChild(unit, units);
    }

    public boolean removeTrailer(final TrailerResource trailer) {
        return this.removeChild(trailer, units);
    }

    public boolean removeContainer(final ContainerResource container) {
        return this.removeChild(container, units);
    }
    
    @Override
    public Set<LoadingUnitResource> getUnits() {
        return Collections.unmodifiableSet(units);
    }

    public boolean addExpectedContainer(final ExpectedLoadingUnit expectedLoadingUnit) {
        return this.addChild(expectedLoadingUnit, expectedUnits);
    }

    public boolean removeExpectedContainer(final ExpectedLoadingUnit expectedLoadingUnit) {
        return this.removeChild(expectedLoadingUnit, expectedUnits);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Set<ExpectedLoadingUnit> getExpectedUnits() {
        return Collections.unmodifiableSet(expectedUnits);
    }

    public boolean addHandlingRequestActivity(final HandlingRequestActivity trailerActivity) {
        if (this.addChild(trailerActivity, handlingRequestActivities)) {
            trailerActivity.setHandlingRequest(this);
            return true;
        }
        return false;
    }

    public boolean removeHandlingRequestActivity(final HandlingRequestActivity trailerActivity) {
        if (this.removeChild(trailerActivity, handlingRequestActivities)) {
            trailerActivity.setHandlingRequest(null);
            return true;
        }
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Set<HandlingRequestActivity> getHandlingRequestActivities() {
        return Collections.unmodifiableSet(handlingRequestActivities);
    }

    /**
     * set HandlingRequest to CANCELLED
     */
    public void cancelled() {
        setStatus(HandlingRequest.Status.CANCELLED);
    }
    
    /**
     * While creating/updating a transit, handling requests can be added.
     *
     * @throws TransitActionException
     */
    @PrePersist
    @PostUpdate
    public void handlingRequestsValidation() throws TransitActionException {

        Set<HandlingRequest> transitRequests = transit.getHandlingRequests();
        transitRequests = transitRequests.stream().filter(
            hr -> !hr.getStatus().equals(Status.CANCELLED) && (hr.getConfirmationStatus() == null || !hr.getConfirmationStatus()
                .equals(ConfirmationStatus.UNCONFIRMED))).collect(Collectors.toSet());

        if (transitRequests != null) {

            long load = transitRequests.stream()
                    .filter(request -> request.getLocation() == null && HandlingRequest.Type.LOAD.equals(request.getType())).count();
            long unload = transitRequests.stream()
                    .filter(request -> request.getLocation() == null && HandlingRequest.Type.UNLOAD.equals(request.getType())).count();
            long pickup = transitRequests.stream()
                    .filter(request -> request.getLocation() == null && HandlingRequest.Type.PICKUP.equals(request.getType())).count();
            long dropOff = transitRequests.stream()
                    .filter(request -> request.getLocation() == null && HandlingRequest.Type.DROPOFF.equals(request.getType())).count();
            if (load > 1 || unload > 1 || pickup > 1 || dropOff > 1) {
                throw new TransitActionException(TransitActionException.Codes.IDENTICAL_HANDLING_REQUESTS, transit.getCode());
            }

            for (final HandlingRequest request : transitRequests) {
                if (request.getScheduledEnd() != null ^ request.getScheduledStart() != null) {
                    throw new TransitActionException(TransitActionException.Codes.NOT_VALID_END_DATE, transit.getCode());
                }
                // check that the "end date" does not precede the "start date"
                if (request.getScheduledStart() != null && request.getScheduledEnd() != null
                        && ObjectUtils.compare(request.getScheduledEnd(), request.getScheduledStart()) <= 0) {
                    throw new TransitActionException(TransitActionException.Codes.NOT_VALID_END_DATE, transit.getCode());
                }
            }
        }
    }



    public static List<HandlingRequest> findBy(final EntityManager em, final LoadingUnitResource trailer) {
        //@formatter:off
        return em.createNamedQuery(Q_FIND_BY_TRAILER, HandlingRequest.class)
                .setParameter(P_ID, trailer.getId())
                .getResultList();
        //@formatter:on
    }

}

---------- End of ./entities/HandlingRequest.java ----------

---------- Start of ./entities/ExpectedLoadingUnit.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToMany;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;

import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import eu.reply.lea.services.common.model.EntityConstants;
import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.lea.services.yard.exceptions.ExpectedLoadingUnitActionException;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.sce.backend.core.entity.StandardEntity;

@ToString(of = {"transit", "inboundWeight", "inboundSeal"})
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter(AccessLevel.PRIVATE)
@Getter
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class ExpectedLoadingUnit extends StandardEntity implements eu.reply.lea.services.yard.model.ExpectedLoadingUnit {

    private static final long serialVersionUID = -3466990191444634898L;
    public static final String P_TRANSIT = "transit";


    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    private BigDecimal inboundWeight;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @DecimalMax(EntityConstants.DEFAULT_DECIMAL_MAX)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    private BigDecimal outboundWeight;

    @Column(length = 30)
    private String inboundSeal;

    @Column(length = 30)
    private String outboundSeal;

    @Setter(value = AccessLevel.PROTECTED)
    @ManyToMany(mappedBy = "expectedUnits")
    private Set<HandlingRequest> handlingRequests = new HashSet<>();


    public ExpectedLoadingUnit(final Transit transit, final BigDecimal inboundWeight, BigDecimal outboundWeight) {
        setTransit(transit);
        registerInboundWeight(inboundWeight);
        registerOutboundWeight(outboundWeight);
    }

    public ExpectedLoadingUnit(final Transit transit) {
        this.setTransit(transit);
    }

    protected boolean addHandlingRequest(final HandlingRequest handlingRequest) {
        return this.addChild(handlingRequest, handlingRequests);
    }

    protected boolean removeHandlingRequest(final HandlingRequest handlingRequest) {
        return this.removeChild(handlingRequest, handlingRequests);
    }

    public Set<HandlingRequest> getHandlingRequests() {
        return Collections.unmodifiableSet(handlingRequests);
    }

    public void registerInboundSeal(final String inboundSeal) {
        if (inboundSeal == null) {
            throw new ExpectedLoadingUnitActionException(ExpectedLoadingUnitActionException.Codes.SEAL_CODE_MISSING);
        }
        checkCanBeModified();
        this.setInboundSeal(inboundSeal);
    }


    public void registerOutboundSeal(final String outboundSeal) {
        if (outboundSeal == null) {
            throw new ExpectedLoadingUnitActionException(ExpectedLoadingUnitActionException.Codes.SEAL_CODE_MISSING);
        }
        checkCanBeModified();
        this.setOutboundSeal(outboundSeal);
    }

    public void registerOutboundWeight(final BigDecimal outboundWeight) {
        checkCanBeModified();
        this.setOutboundWeight(outboundWeight);
    }

    public void registerInboundWeight(final BigDecimal inboundWeight) {
        checkCanBeModified();
        this.setInboundWeight(inboundWeight);
    }

    public void checkCanBeModified() throws ExpectedLoadingUnitActionException {
        if (Transit.Status.isRegistered(getTransit().getStatus())) {
            throw new ExpectedLoadingUnitActionException(ExpectedLoadingUnitActionException.Codes.TRANSIT_STATUS_NOT_VALID);
        }
    }

    public abstract Transit getTransit();

    protected abstract void setTransit(Transit transit);

    public abstract <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T createLoadingUnit(final LoadingUnitResource.LoadStatus loadStatus,
                                                                                                            final LoadingUnitRegistry loadingUnitRegistry);


}

---------- End of ./entities/ExpectedLoadingUnit.java ----------

---------- Start of ./entities/TransitCreationValidationNotificationHandler.java ----------
package eu.reply.lea.services.yard.entities;


import eu.reply.lea.services.yard.ValidationNotificationHandler;
import eu.reply.lea.services.yard.exception.TransitAlreadyPresentException;

public class TransitCreationValidationNotificationHandler implements ValidationNotificationHandler {
    @Override
    public void handleError(final String aNotificationMessage) {
        throw new IllegalStateException(aNotificationMessage);
    }


    public void transitAlreadyPresentForAppointment(Long transitId) {
        throw new TransitAlreadyPresentException(TransitAlreadyPresentException.Codes.ALREADY_PRESENT_FOR_APPOINTMENT,
                                                 transitId);
    }
}

---------- End of ./entities/TransitCreationValidationNotificationHandler.java ----------

---------- Start of ./entities/NotificationMode.java ----------
package eu.reply.lea.services.yard.entities;


import java.util.EnumSet;

/**
 *
 * The aim of this enum is to define the possible
 * notification mode that must be applied to managing of yms task.
 *
 */
public enum NotificationMode {
    SMS(1),
    AUTOMATIC_CALL(2),
    EMAIL(4),
    DRIVER_APP(8);

    private int code;

    private NotificationMode(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

}

---------- End of ./entities/NotificationMode.java ----------

---------- Start of ./entities/HandlingRequestActivity.java ----------
package eu.reply.lea.services.yard.entities;

import eu.reply.lea.services.common.model.EntityConstants;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.model.HandlingRequest.Status;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import lombok.*;

import javax.persistence.*;
import javax.validation.constraints.DecimalMin;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;

@Data
@RequiredArgsConstructor
@ToString(callSuper = false, of = { "handlingRequest", "status" })
@EqualsAndHashCode(callSuper = false)
@Entity
@NamedQuery(name = HandlingRequestActivity.Q_FIND_BY_CONTAINER, query = "select h from HandlingRequestActivity h where h.loadingUnit = :containerResource")
@StringifyAttributes(attributes = { "handlingRequest", "status" })
public class HandlingRequestActivity extends StandardEntity implements eu.reply.lea.services.yard.model.HandlingRequestActivity {

    private static final long serialVersionUID = 4042849801174571440L;

    public static final String Q_FIND_BY_CONTAINER = "HandlingRequestActivity.findByContainer";
    public static final String P_CONTAINER = "containerResource";

    @NonNull
    @ManyToOne(optional = false)
    private LoadingUnitResource loadingUnit;

    @ManyToOne
    @Setter(value = AccessLevel.PROTECTED)
    private HandlingRequest handlingRequest;

    @NonNull
    @Enumerated(EnumType.STRING)
    private HandlingRequest.Status status = HandlingRequest.Status.TODO;

    @Enumerated(EnumType.STRING)
    private TrailerResource.ConfirmationStatus hrLoadingUnitsConfirmationStatus;
    private int positionIndex;
    @NonNull
    @Enumerated(EnumType.STRING)
    private PlannedStatus plannedStatus;

    @Temporal(TemporalType.TIMESTAMP)
    private Calendar startDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Calendar endDate;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    private BigDecimal movedWeight;
    
    @Embedded
    @AttributeOverrides(value= {
            @AttributeOverride(column=@Column(name="targetLocEntityName"),name="location.entityName"),
            @AttributeOverride(column=@Column(name="targetLocEntityId"),name="location.entityId"),
            @AttributeOverride(column=@Column(name="targetLocModule"),name="location.module"),
            @AttributeOverride(column=@Column(name="targetLocBusinessKey"),name="location.businessKey")
    })
    private LocationReference targetLocation;

    public HandlingRequestActivity() {
        this.status = HandlingRequest.Status.TODO;
    }
    
    public static List<HandlingRequestActivity> findBy(final EntityManager em, final LoadingUnitResource container) {
        return em.createNamedQuery(Q_FIND_BY_CONTAINER, HandlingRequestActivity.class).setParameter(P_CONTAINER, container).getResultList();
    }

    public void cancelled() {
        this.setStatus(Status.CANCELLED);
    }

}

---------- End of ./entities/HandlingRequestActivity.java ----------

---------- Start of ./entities/ContainerResource.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.sce.backend.core.entity.configuration.BusinessKey;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.ToString;

@Data
@ToString(callSuper = false, of = { "bic"})
@EqualsAndHashCode(callSuper = true)
@NamedQueries({
        @NamedQuery(name = ContainerResource.Q_FIND_BY_BIC, query = "select t from ContainerResource t where t.bic = :bic"),
        @NamedQuery(name = ContainerResource.Q_FIND_BY_BIC_AND_STATUS, query = "select t from ContainerResource t where t.bic = :bic and not t.status = :status")
})
@StringifyAttributes(attributes = { "bic" })
@BusinessKeySequence(prefix = "CTRR", length = 10)
@BusinessKey(attributes = {"bic"})
@NoArgsConstructor
@Entity
public class ContainerResource extends LoadingUnitResource implements eu.reply.lea.services.yard.model.ContainerResource {

	private static final long serialVersionUID = -2075386092317325455L;

	public static final String Q_FIND_BY_BIC = "ContainerResource.Q_FIND_BY_BIC";
	public static final String Q_FIND_BY_BIC_AND_STATUS = "ContainerResource.Q_FIND_BY_BIC_AND_STATUS";
    private static final String P_BIC = "bic";
    private static final String P_STATUS = "status";

    @NonNull
    @NotNull
    private String bic;



    public static List<ContainerResource> findByBic(final EntityManager em, final String bic){
        return em.createNamedQuery(Q_FIND_BY_BIC, ContainerResource.class).setParameter(P_BIC, bic).getResultList();
    }
    
    public static List<ContainerResource> findByBicAndStatus(final EntityManager em, final String bic, final Status status) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_BIC_AND_STATUS, ContainerResource.class)
                .setParameter(P_BIC, bic)
                .setParameter(P_STATUS, status).getResultList();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(ContainerResource.class.getSimpleName(), bic);
        }
    }

    public ContainerResource(final String bic,  final LoadStatus loadStatus, final ConfirmationStatus confirmationStatus,final Transit transit,
                             final LoadingUnitRegistry loadingUnitRegistry){
        super(loadingUnitRegistry);
        this.setConfirmationStatus(confirmationStatus);
        this.setLoadStatus(loadStatus);
        this.setInboundTransit(transit);
        this.bic= bic;
    }

    public ContainerResource(final String bic, final LoadStatus loadStatus,
                             final ConfirmationStatus confirmationStatus, final Transit transit,
                             final BigDecimal inboundExpectedWeight, final BigDecimal outboundExpectedWeight,
                             final String inboundExpectedSeal, final String outboundExpectedSeal,
                             final LoadingUnitRegistry loadingUnitRegistry) {
        super(inboundExpectedWeight, outboundExpectedWeight, inboundExpectedSeal, outboundExpectedSeal,loadingUnitRegistry);
        this.setConfirmationStatus(confirmationStatus);
        this.setLoadStatus(loadStatus);
        this.setInboundTransit(transit);
        this.bic= bic;
    }

}



---------- End of ./entities/ContainerResource.java ----------

---------- Start of ./entities/TransitCreationValidator.java ----------
package eu.reply.lea.services.yard.entities;


import static eu.reply.lea.services.yard.entities.Transit.Q_FIND_BY_APP_CODE_AND_STATUS;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.stream.Collectors;

import eu.reply.lea.services.yard.ValidationNotificationHandler;
import eu.reply.lea.services.yard.Validator;
import eu.reply.lea.services.yard.exception.TransitAlreadyPresentException;

public class TransitCreationValidator extends Validator {

    private Transit transit;

    private EntityManager em;

    public TransitCreationValidator(final Transit transit, final ValidationNotificationHandler aHandler,
                                    final EntityManager em) {
        super(aHandler);
        this.setTransit(transit);
        this.setEm(em);
    }

    public void setEm(EntityManager em){
        this.em = em;
    }

    public EntityManager getEm() {
        return this.em;
    }

    public void setTransit(final Transit transit) {
        this.transit = transit;
    }

    public Transit getTransit() {
        return transit;
    }

    public void validate() {
        if(this.getTransit().getAppointmentCode()!=null ){
            Long transitId = activeTransitPresentForAppointmentCode(this.getTransit());
            if(transitId!=null){
                this.notificationHandler().transitAlreadyPresentForAppointment(transitId);
            }
        }

    }

    /**
     * Verifies if an active transit is already present for a given appointment code.
     * This method queries the database using the provided EntityManager to check for existing transits with the specified appointment code.
     * If one or more active transits are found, it returns the id of the first transit that matches, otherwise returns null
     *
     * @param transit
     * @throws TransitAlreadyPresentException if one or more active transits with the given appointment code are found.
     */
    private Long activeTransitPresentForAppointmentCode(Transit transit) {
        List<Transit> activeTransits =
            getEm().createNamedQuery(Q_FIND_BY_APP_CODE_AND_STATUS, Transit.class)
                .setParameter(Transit.P_APP_CODE, transit.getAppointmentCode())
                .setParameter(Transit.P_STATUS, Transit.Status.getActiveStatusesList()).getResultList()
                .stream().filter(t -> !t.getId().equals(transit.getId())).collect(Collectors.toList());
        if (activeTransits.size() > 0) {
            return activeTransits.get(0).getId();
        }
        return null;
    }


    protected TransitCreationValidationNotificationHandler notificationHandler() {
        return (TransitCreationValidationNotificationHandler) super.notificationHandler();
    }

}
---------- End of ./entities/TransitCreationValidator.java ----------

---------- Start of ./entities/ScheduledActivityDTO.java ----------
package eu.reply.lea.services.yard.entities;

import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.lea.services.yard.model.HandlingRequest;

import lombok.Getter;

/**
 * Data Transfer Object (DTO) representing a scheduled activity.
 * This class encapsulates details about a specific handling request and its associated dock.
 * It is used to transfer necessary information about scheduled activities, such as the type of handling request and
 * the dock reference, before the creation of the entity.
 */
@Getter
public class ScheduledActivityDTO {

    public ScheduledActivityDTO(HandlingRequest.Type hrType,DockReference dockReference){
        this.dockReference=dockReference;
        this.hrType=hrType;
    }

    private HandlingRequest.Type hrType;

    private DockReference dockReference;

}

---------- End of ./entities/ScheduledActivityDTO.java ----------

---------- Start of ./entities/CreateMissionRequest.java ----------
package eu.reply.lea.services.yard.entities;


import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.yard.model.CreateMissionRequestStatus;
import eu.reply.sce.backend.core.entity.StandardEntity;
import lombok.*;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Calendar;

/**
 * The aim of this class is to save a new request to create an internal mission
 * from a specific Loading Unit
 */
@Data
@Table
@Entity
@Getter
@Setter
@EqualsAndHashCode(callSuper = false, exclude = {"loadingUnit", "createMissionRequestStatus", "from", "to"})
@NamedQueries
        ({
                @NamedQuery(name = CreateMissionRequest.Q_FIND_BY_ALL, query = "select c from CreateMissionRequest c where c.loadingUnit = :loadingUnit " +
                        "and c.from = :from and c.to = :to")
        })
public class CreateMissionRequest extends StandardEntity implements eu.reply.lea.services.yard.model.CreateMissionRequest {

    @Override
    public String resourceName() {
        return CreateMissionRequest.class.getSimpleName();
    }

    //region NamedQuery

    //region Q_FIND_BY_ALL
    public static final String Q_FIND_BY_ALL = "SendResourceRequest.findUsingAllParams";
    public static final String P_LOADING_UNIT = "loadingUnit";
    public static final String P_FROM = "from";
    public static final String P_TO = "to";
    //endregion

    //endregion

    //region Private Fields

    /**
     * Loading Unit that request a new internal sending
     * operation
     */
    @ManyToOne(optional = false)
    private LoadingUnitResource loadingUnit;

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "entityName", column = @Column(name = "site_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "site_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "site_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "site_entityId", length = 50)) })
    private SiteReference siteReference;


    /**
     * Get SendRequestStatus.
     */
    @Enumerated(EnumType.STRING)
    private CreateMissionRequestStatus createMissionRequestStatus;


    /**
     * Get error when working on this request.
     */
    private String error;


    /**
     * Location from the LU needs to move (start location)
     */
    @Embedded
    @AttributeOverrides(
            {@AttributeOverride(name = "module", column = @Column(name = "from_module")),
                    @AttributeOverride(name = "entityName", column = @Column(name = "from_entityName")),
                    @AttributeOverride(name = "entityId", column = @Column(name = "from_entityId")),
                    @AttributeOverride(name = "businessKey", column = @Column(name = "from_businessKey"))})
    private LocationReference from;


    /**
     * Location to the LU needs to reach (end location)
     */
    @Embedded
    @AttributeOverrides(
            {@AttributeOverride(name = "module", column = @Column(name = "to_module")),
                    @AttributeOverride(name = "entityName", column = @Column(name = "to_entityName")),
                    @AttributeOverride(name = "entityId", column = @Column(name = "to_entityId")),
                    @AttributeOverride(name = "businessKey", column = @Column(name = "to_businessKey"))})
    private LocationReference to;


    /**
     * Date in which the request was closed.
     */
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar completedDate;
    //endregion

    //region Constructors

    /**
     * Construct SendResourceRequest instance
     */
    public CreateMissionRequest() {

    }

    /**
     * Construct SendResourceRequest instance
     *
     * @param loadingUnit Loading Unit
     * @param from        Location From
     * @param to          Location To
     */
    public CreateMissionRequest(@NotNull final LoadingUnitResource loadingUnit,
                                @NotNull final LocationReference from,
                                @NotNull final LocationReference to,
                                @NotNull final SiteReference siteReference){
        this.loadingUnit = loadingUnit;
        this.from = from;
        this.to = to;
        this.createMissionRequestStatus = CreateMissionRequestStatus.NEW;
        this.siteReference=siteReference;

    }
    //endregion

    //region findSendResourceRequest

    /**
     * Get SendResourceRequest
     *
     * @param entityManager EntityManageer
     * @param loadingUnit Loading Unit to search
     * @param from Location from of Loading unit
     * @param to Location to of Loading unit
     * @return retrieved SendResourceRequest
     */
    public static CreateMissionRequest findSendResourceRequest(@NotNull final EntityManager entityManager,
                                                               @NotNull final LoadingUnitResource loadingUnit,
                                                               @NotNull final LocationReference from,
                                                               @NotNull final LocationReference to) {
        CreateMissionRequest result = null;

        try {
            return entityManager.createNamedQuery(Q_FIND_BY_ALL, CreateMissionRequest.class)
                    .setParameter(P_LOADING_UNIT, loadingUnit)
                    .setParameter(P_FROM, from)
                    .setParameter(P_TO, to)
                    .setFlushMode(FlushModeType.COMMIT)
                    .getSingleResult();
        } catch (final NoResultException e) {
            result = null;
        }

        return result;
    }


    //endregion
}

---------- End of ./entities/CreateMissionRequest.java ----------

---------- Start of ./entities/AttachedDocument.java ----------
package eu.reply.lea.services.yard.entities;

import eu.reply.sce.backend.core.entity.StandardEntity;
import lombok.Getter;
import lombok.Setter;


import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.Set;


/**
 * AttachmentDocument
 * This class is used to create a document. it contains a reference
 * to an attachment of class Attachment present in SCE-Backend
 * */
@Entity
@Getter
@Setter
public class AttachedDocument extends StandardEntity {

    @Column(unique = true)
    @NotNull
    private String documentId;

    @ManyToMany
    private Set<Tag> tags = new HashSet<>();

    private String note;

    // Reference to an attachment of class Attachment present in SCE-Backend
    @Embedded
    private AttachmentReference attachmentReference;

}

---------- End of ./entities/AttachedDocument.java ----------

---------- Start of ./entities/LoadingUnitActivity.java ----------
package eu.reply.lea.services.yard.entities;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.common.model.EntityConstants;
import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.ToString;

@Data
@ToString(callSuper = false, of = { "loadingUnit", "type", "status" })
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@NamedQueries({ @NamedQuery(name = LoadingUnitActivity.Q_FIND_BY_LOADING_UNIT, query = "select l from LoadingUnitActivity l where l.loadingUnit = :loadingUnit") })
@StringifyAttributes(attributes = { "loadingUnit", "type", "status" })
public class LoadingUnitActivity extends StandardEntity implements eu.reply.lea.services.yard.model.LoadingUnitActivity {

	private static final long serialVersionUID = -5280893186599984457L;

	public static final String Q_FIND_BY_LOADING_UNIT = "LoadingUnitActivity.findByLoadingUnit";

	public static final String P_LOADING_UNIT = "loadingUnit";

	@NonNull
	@NotNull
	@ManyToOne(fetch = FetchType.EAGER)
	private LoadingUnitResource loadingUnit;

	@Enumerated(EnumType.STRING)
	@Setter(value = AccessLevel.PRIVATE)
	private Status status;

	@NonNull
	@NotNull
	@Enumerated(EnumType.STRING)
	@Setter(value = AccessLevel.PRIVATE)
	private Type type;
	
	@AttributeOverrides({ @AttributeOverride(name = "businessKey", column = @Column(name = "dock_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "dock_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "dock_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "dock_entityId", length = 50)) })
	private DockReference dock;
	
	@DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
	private BigDecimal movedWeight;

	@Temporal(TemporalType.TIMESTAMP)
    private Calendar startDate;
	
	@Temporal(TemporalType.TIMESTAMP)
    private Calendar endDate;
	
	public LoadingUnitActivity(@NonNull final LoadingUnitResource loadingUnit, @NonNull final Type type) {
		this.loadingUnit = loadingUnit;
		this.type = type;
		this.status = Status.TO_DO;
	}
	
	//
	// Methods
	//
	
	private void setStartDate(final Calendar startDate) {
		this.startDate = startDate;
	}

	private void setEndDate(final Calendar endDate) {
		this.endDate = endDate;
	}

	/**
	 * set Status to TO_DO
	 */
	public void todo() {
		setStatus(Status.TO_DO);
	}

	/**
	 * set Status to CONFIRMED
	 */
	public void confirmed(final DockReference dock) {
		setStatus(Status.CONFIRMED);
		setDock(dock);
	}

	/**
	 * set Status to EXECUTING
	 */
	public void inProgress() {
		setStartDate(Calendar.getInstance());
		setStatus(Status.IN_PROGRESS);
	}

	/**
	 * set Status to COMPLETED
	 */
	public void completed() {
		setEndDate(Calendar.getInstance());
		setStatus(Status.COMPLETED);
	}


	//
	// Queries
	//

	public static List<LoadingUnitActivity> findByLoadingUnit(final EntityManager em, final LoadingUnitResource loadingUnit) {
		try {
			return em.createNamedQuery(Q_FIND_BY_LOADING_UNIT,LoadingUnitActivity.class).setParameter(P_LOADING_UNIT, loadingUnit).getResultList();
		} catch (final NoResultException e) {
			return null;
		}
	}

}

---------- End of ./entities/LoadingUnitActivity.java ----------

---------- Start of ./entities/LoadingUnitMovement.java ----------
package eu.reply.lea.services.yard.entities;

import java.util.List;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;

@Entity
@NamedQueries({ @NamedQuery(name = LoadingUnitMovement.Q_FIND_BY_CODE, query = "select l from LoadingUnitMovement l where l.code = :code"),
	@NamedQuery(name = LoadingUnitMovement.Q_FIND_BY_LOADING_UNIT, query = "select l from LoadingUnitMovement l where l.logisticUnitRef.module = :module "
                                                                           + "and l.logisticUnitRef.entityName = :entityName "
                                                                           + "and l.logisticUnitRef.entityId = :entityId")})
@BusinessKeySequence(prefix = "LUM", length = 10)
@StringifyAttributes(attributes = { "code" })
public class LoadingUnitMovement extends Movement implements eu.reply.lea.services.yard.model.LoadingUnitMovement {

    public static final String Q_FIND_BY_LOADING_UNIT = "LoadingUnitMovement.findByLoadingUnit";


    public LoadingUnitMovement(@NonNull final LoadingUnitReference loadingUnitRef, final LocationReference sourceLocation, final LocationReference destinationLocation ) {
		this.logisticUnitRef = new EntityReference(loadingUnitRef.getModule(), loadingUnitRef.getEntityName(), loadingUnitRef.getEntityId(),null, loadingUnitRef.getBusinessKey());
		this.destinationLocation = destinationLocation;
        this.sourceLocation = sourceLocation;
	}

    public LoadingUnitMovement(@NonNull final EntityReference loadingUnitRef, final LocationReference sourceLocation, final LocationReference destinationLocation ) {
        this.logisticUnitRef = loadingUnitRef;
        this.destinationLocation = destinationLocation;
        this.sourceLocation = sourceLocation;
    }

    public LoadingUnitMovement() {

    }


    public static List<LoadingUnitMovement> findByLoadingUnit(final EntityManager em, final LoadingUnitReference loadingUnitReference) {
		try {
			return em.createNamedQuery(Q_FIND_BY_LOADING_UNIT, LoadingUnitMovement.class)
                .setParameter("module", loadingUnitReference.getModule())
                .setParameter("entityName", loadingUnitReference.getEntityName())
                .setParameter("entityId", loadingUnitReference.getEntityId())
					.getResultList();
		} catch (final NoResultException e) {
			return null;
		}
	}

    @Override
    @JsonIgnore
    public LoadingUnitReference getLoadingUnitRef() {
        return new LoadingUnitReference(getLogisticUnitRef().getEntityName(), getLogisticUnitRef().getEntityId(), getLogisticUnitRef().getBusinessKey());
    }
}

---------- End of ./entities/LoadingUnitMovement.java ----------

---------- Start of ./entities/LoadingUnitResourceRepository.java ----------
package eu.reply.lea.services.yard.entities;


import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Scope;
import javax.persistence.EntityManager;

import java.util.List;

import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityReferenceHandler;
import eu.reply.sce.backend.core.jee.log.Logged;

@ApplicationScoped
@Logged
public class LoadingUnitResourceRepository {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Inject
    private EntityReferenceHandler entityReferenceHandler;

    public List<LoadingUnitResource> findLoadingUnitByAttachedTransit(final TransitReference transitReference){
        return em.createNamedQuery(LoadingUnitResource.Q_FIND_BY_ATTACHED_TRANSIT,
                                   LoadingUnitResource.class
                                   ).setParameter("transitId", transitReference.getEntityId()).getResultList();
    }

    public LoadingUnitResource findByEntityRef(final LoadingUnitReference loadingUnitReference){
        return entityReferenceHandler.getEntity(loadingUnitReference.toEntityReference(), em);
    }

}

---------- End of ./entities/LoadingUnitResourceRepository.java ----------

---------- Start of ./entities/Movement.java ----------
package eu.reply.lea.services.yard.entities;

import java.time.Instant;
import java.util.Calendar;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.events.movement.MovementStatusChangedEvent;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Setter
@Getter
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"code"})})
public abstract class Movement extends StandardEntity
    implements eu.reply.lea.services.yard.model.Movement {

    public static final String Q_FIND_BY_CODE = "Movement.findByCode";
    public static final String P_CODE = "code";
    private static final long serialVersionUID = -600697287133946990L;

    @NotNull
    @Size(min = 1)
    @Column(updatable = false)
    protected String code;

    @NonNull
    @NotNull
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "businessKey", column = @Column(name = "logisticUnit_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "logisticUnit_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "logisticUnit_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "logisticUnit_entityId", length = 50)),
        @AttributeOverride(name = "usageType", column = @Column(name = "logisticUnit_usageType"))
    })
    protected EntityReference logisticUnitRef;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "businessKey", column = @Column(name = "sLocation_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "sLocation_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "sLocation_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "sLocation_entityId", length = 50))})
    protected LocationReference sourceLocation;

    @NonNull
    @NotNull
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "businessKey", column = @Column(name = "dLocation_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "dLocation_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "dLocation_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "dLocation_entityId", length = 50))})
    protected LocationReference destinationLocation;


    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    @Setter(value = AccessLevel.PRIVATE)
    private Status status = Status.TO_DO;
    /**
     * When the movement start
     */
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar movementStartDate;
    /**
     * When the movement was completed
     */
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar movementEndDate;


    /**
     * set Status to TO_DO
     */
    public void todo(final ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer) {
        Status oldStatus = this.getStatus();
        setStatus(Status.TO_DO);
        statusChangedEventProducer.fire(new MovementStatusChangedEvent(this, oldStatus, Instant.now()));
    }

    /**
     * set Status to EXECUTING
     */
    public void executing(final ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer) {
        Status oldStatus = this.getStatus();
        setStatus(Status.EXECUTING);
        this.setMovementStartDate(Calendar.getInstance());
        statusChangedEventProducer.fire(new MovementStatusChangedEvent(this, oldStatus, Instant.now()));
    }

    /**
     * set Status to COMPLETED
     */
    public void completed(final ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer) {
        Status oldStatus = this.getStatus();
        setStatus(Status.COMPLETED);
        this.setMovementEndDate(Calendar.getInstance());
        statusChangedEventProducer.fire(new MovementStatusChangedEvent(this, oldStatus, Instant.now()));
    }

    /**
     * set Status to CANCELED
     */
    public void cancel(final ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer) {
        Status oldStatus = this.getStatus();
        setStatus(Status.CANCELED);
        statusChangedEventProducer.fire(new MovementStatusChangedEvent(this, oldStatus, Instant.now()));
    }

    /**
     * This method is public only for test porpuses
     */
    public void setStatus(Status status) {
        this.status = status;
    }

}

---------- End of ./entities/Movement.java ----------

---------- Start of ./entities/Switcher.java ----------
package eu.reply.lea.services.yard.entities;

import java.io.InvalidClassException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import com.fasterxml.jackson.annotation.JsonIgnore;

import eu.reply.lea.services.common.model.CodeSupport;
import eu.reply.lea.services.common.model.EntityConstants;
import eu.reply.lea.services.masterdata.model.vehicle.Vehicle;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.lea.services.yard.reference.SwitcherReference;
import eu.reply.sce.backend.core.entity.StandardEntity;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;
import groovy.transform.ToString;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@ToString(includeSuper = false, includes = { "code", "status", "physicalStatus" })
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "code" }) })
@NamedQueries({ @NamedQuery(name = Switcher.Q_FIND_BY_CODE, query = "select s from Switcher s where s.code = :code"),
    @NamedQuery(name = Switcher.Q_FIND_BY_SITE, query = "select s from Switcher s where s.site = :site") })
@BusinessKeySequence(prefix = "SWT", length = 10)
@StringifyAttributes(attributes = { "code" })
public class Switcher extends StandardEntity implements eu.reply.lea.services.yard.model.vehicle.Switcher, CodeSupport {

    private static final long serialVersionUID = -2855401027033017001L;

    public static final String Q_FIND_BY_CODE = "Switcher.findByCode";
    public static final String Q_FIND_BY_SITE = "Switcher.findBySite";

    public static final String P_CODE = "code";
    public static final String P_SITE = "site";

    @NonNull
    @NotNull
    @Size(min = 1)
    @Column(updatable = false)
    private String code;

    @Size(min = 1)
    private String description;

    @DecimalMin(EntityConstants.DEFAULT_DECIMAL_MIN)
    @Column(precision = EntityConstants.DEFAULT_PRECISION, scale = EntityConstants.DEFAULT_SCALE)
    private BigDecimal weight;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private Status status = Status.FREE;

    @NonNull
    @NotNull
    @Enumerated(EnumType.STRING)
    private PhysicalStatus physicalStatus = PhysicalStatus.AVAILABLE;

    @OneToOne(optional = true)
    private eu.reply.lea.services.yard.entities.LoadingUnitResource attachedUnit;
    
    @NonNull
    @NotNull
    @Embedded
    @Column(updatable=false)
    @AttributeOverrides({ @AttributeOverride(name = "entityName", column = @Column(name = "site_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "site_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "site_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "site_entityId", length = 50)) })
    private SiteReference site;

    private String vin;

    private String model;

    public static Switcher findBy(final EntityManager em, final String code) throws EntityNotFoundException {
        try {
            return em.createNamedQuery(Q_FIND_BY_CODE, Switcher.class).setParameter(P_CODE, code).getSingleResult();
        } catch (final NoResultException e) {
            throw new EntityNotFoundException(Switcher.class.getSimpleName(), code);
        }
    }
    
    public static List<Switcher> findBy(final EntityManager em, final SiteReference site) {
        return em.createNamedQuery(Q_FIND_BY_SITE, Switcher.class).setParameter(P_SITE, site).getResultList();
    }

    @JsonIgnore
    public SwitcherReference getReference(){
        return new SwitcherReference(this);
    }

    @Override
    public void detachLoadingUnit(final LoadingUnitResource loadingUnitResource) {
        loadingUnitResource.releaseFromAttachedVehicle(null);
        this.attachedUnit=null;
    }

    @Override
    public void attachLoadingUnit(final LoadingUnitResource loadingUnitResource) throws InvalidClassException {
        loadingUnitResource.attachToVehicle(new VehicleReference(this));
        this.setStatus(Switcher.Status.BUSY);
    }

    @Override
    @JsonIgnore
    public Collection<LoadingUnitResource> getAttachedLoadingUnits() {
        return Arrays.asList(new eu.reply.lea.services.yard.entities.LoadingUnitResource[]{attachedUnit});
    }

    @Override
    public boolean canAttachUnits() {
        return isAvailable();
    }

    @Override
    @JsonIgnore
    public Vehicle getAttachingVehicle() {
        return this;
    }

    @Override
    @JsonIgnore
    public VehicleReference getVehicleReference() {
        return new VehicleReference(new SwitcherReference(this));
    }
    
    @Override
    public void detachUnit() {
        eu.reply.lea.services.yard.model.vehicle.Switcher.super.detachUnit();
        setStatus(Status.FREE);
    }
    
}

---------- End of ./entities/Switcher.java ----------

---------- Start of ./entities/ScheduledActivity.java ----------
package eu.reply.lea.services.yard.entities;

import eu.reply.lea.services.masterdata.reference.DockReference;

import eu.reply.sce.backend.core.entity.StandardEntity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;
import java.util.Objects;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class ScheduledActivity extends StandardEntity implements eu.reply.lea.services.yard.model.ScheduledActivity {

    @NotNull
    private String transitCode;

    @NotNull
    private HandlingRequest.Type type;

    @NotNull
    private DockReference dockReference;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ScheduledActivity that = (ScheduledActivity) o;
        return Objects.equals(transitCode, that.transitCode) &&
               Objects.equals(type, that.type) &&
               Objects.equals(dockReference, that.dockReference);
    }

    @Override
    public int hashCode() {
        return Objects.hash(transitCode, type, dockReference);
    }

}

---------- End of ./entities/ScheduledActivity.java ----------

---------- Start of ./entities/TransitMovement.java ----------
package eu.reply.lea.services.yard.entities;

import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import lombok.NonNull;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.entity.configuration.StringifyAttributes;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;

@Entity
@BusinessKeySequence(prefix = "TRM", length = 10)
@NamedQueries({
    @NamedQuery(name = TransitMovement.Q_FIND_BY_TRANSIT_REFERENCE,
        query = "select t from TransitMovement t where t.logisticUnitRef.module = :module "
                + "and t.logisticUnitRef.entityName = :entityName "
                + "and t.logisticUnitRef.entityId = :entityId")})
@StringifyAttributes(attributes = {"code"})
public class TransitMovement extends Movement implements eu.reply.lea.services.yard.model.TransitMovement {

    public static final String Q_FIND_BY_TRANSIT_REFERENCE = "TransitMovement.findByTransitReference";

    public TransitMovement(@NonNull final TransitReference transitReference, final LocationReference sourceLocation,
                           final LocationReference destinationLocation) {
        this.logisticUnitRef =
            new EntityReference(transitReference.getModule(), transitReference.getEntityName(), transitReference.getEntityId(), null,
                                transitReference.getBusinessKey());
        this.destinationLocation = destinationLocation;
        this.sourceLocation = sourceLocation;
    }

    public TransitMovement(@NonNull final EntityReference transitReference, final LocationReference sourceLocation,
                           final LocationReference destinationLocation) {
        this.logisticUnitRef = transitReference;
        this.destinationLocation = destinationLocation;
        this.sourceLocation = sourceLocation;
    }

    public TransitMovement() {

    }
}

---------- End of ./entities/TransitMovement.java ----------

---------- Start of ./domainservice/TransitMovementDomainService.java ----------
package eu.reply.lea.services.yard.domainservice;

import java.util.List;
import javax.enterprise.context.ApplicationScoped;

import lombok.NonNull;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.entities.Movement;
import eu.reply.lea.services.yard.entities.TransitMovement;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.jee.log.Logged;

/**
 * Service class for managing transit movements.
 * This service provides methods to start and complete transit movements,
 * leveraging the functionalities of the abstract {@link MovementDomainService}.
 */
@ApplicationScoped
@Logged
public class TransitMovementDomainService extends MovementDomainService {


    /**
     * Starts a new transit movement or continues an existing one for a transit reference to a specified destination location.
     *
     * @param transitMovements    List of existing transit movements.
     * @param transitReference    Reference of the transit.
     * @param destinationLocation The destination location for the movement.
     */
    public void createNewMovement(final List<TransitMovement> transitMovements, final TransitReference transitReference, final LocationReference destinationLocation) {
        super.createNewMovement(transitMovements, transitReference.toEntityReference(), destinationLocation);
    }


    /**
     * Completes an existing transit movement for a transit reference to a specified park location.
     *
     * @param transitMovements List of existing transit movements.
     * @param transitReference Reference of the transit.
     * @param parkLocation     The park location for the movement.
     */
    public void completeMovement(final List<TransitMovement> transitMovements, final TransitReference transitReference, final LocationReference parkLocation) {
        super.completeMovement(transitMovements, transitReference.toEntityReference(), parkLocation);
    }


    /**
     * Creates a new instance of a {@link TransitMovement}.
     *
     * @param logisticUnitRef  Reference of the logistic unit.
     * @param sourceLocation   The source location for the movement.
     * @param destinationLocation The destination location for the movement.
     * @return A new instance of {@link TransitMovement}.
     */
    @Override
    protected Movement createNewInstance(final @NonNull EntityReference logisticUnitRef, final LocationReference sourceLocation,
                                         final LocationReference destinationLocation) {
        return new TransitMovement(logisticUnitRef, sourceLocation, destinationLocation);
    }
}

---------- End of ./domainservice/TransitMovementDomainService.java ----------

---------- Start of ./domainservice/LoadingUnitMovementDomainService.java ----------
package eu.reply.lea.services.yard.domainservice;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.util.List;

import lombok.NonNull;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.entities.LoadingUnitMovement;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.entities.Movement;
import eu.reply.lea.services.yard.events.movement.MovementStatusChangedEvent;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.jee.log.Logged;

/**
 * Service class for managing loading unit movements.
 * This service provides methods to start and complete movements for loading units,
 * ensuring consistency and adherence to business rules.
 */
@ApplicationScoped
@Logged
public class LoadingUnitMovementDomainService extends MovementDomainService {

    @Inject
    private ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer;


    /**
     * Starts a new movement or continues an existing one for a loading unit to a specified destination location.
     *
     * @param loadingUnitMovements List of existing loading unit movements.
     * @param loadingUnitRef  The loading unit resource ref.
     * @param destinationLocation  The destination location for the movement.
     */
    public void createNewMovement(final List<LoadingUnitMovement> loadingUnitMovements, final LoadingUnitReference loadingUnitRef,
                                  final LocationReference destinationLocation) {
        super.createNewMovement(loadingUnitMovements, loadingUnitRef.toEntityReference(),
                                destinationLocation);
    }

    public void createNewMovement(@NotNull final LoadingUnitMovement loadingUnitMovement) {
        loadingUnitMovement.executing(statusChangedEventProducer);
    }

    public void completeMovement(@NotNull final LoadingUnitMovement loadingUnitMovement) {
        loadingUnitMovement.completed(statusChangedEventProducer);
    }

    /**
     * Completes the movement for a loading unit and parks it at a specified location if it is moving.
     *
     * @param loadingUnitMovements List of existing loading unit movements.
     * @param loadingUnitReference  The loading unit resource reference.
     * @param parkLocation         The park location.
     */
    public void completeMovement(final List<LoadingUnitMovement> loadingUnitMovements,
                                 final LoadingUnitReference loadingUnitReference, final LocationReference parkLocation) {
        super.completeMovement(loadingUnitMovements, loadingUnitReference.toEntityReference(),
                                   parkLocation);

    }

    @Override
    protected Movement createNewInstance(final @NonNull EntityReference logisticUnitRef, final LocationReference sourceLocation,
                                         final LocationReference destinationLocation) {
        return new LoadingUnitMovement(logisticUnitRef, sourceLocation, destinationLocation);
    }


}

---------- End of ./domainservice/LoadingUnitMovementDomainService.java ----------

---------- Start of ./domainservice/MovementDomainService.java ----------
package eu.reply.lea.services.yard.domainservice;

import java.util.Comparator;
import java.util.List;
import org.slf4j.Logger;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import lombok.NonNull;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.entities.Movement;
import eu.reply.lea.services.yard.events.movement.MovementStatusChangedEvent;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
public abstract class MovementDomainService { //TODO it's probably more appropriate to create an entity "TransitMovementSequence" and "LoadingUnitMovementSequence"

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Inject
    private ConfigurableEventProducer<MovementStatusChangedEvent> statusChangedEventProducer;

    @Inject
    private Logger log;


    <K extends Movement> Movement createNewMovement(final List<K> existingMovements, final EntityReference logisticUnit, final LocationReference destinationLocation) {
        completeExecutingMovementsToOtherLocations(existingMovements, destinationLocation);
        cancelToDoMovementsToOtherLocations(existingMovements, destinationLocation);
        K lastCompletedMovement = findLastCompletedMovement(existingMovements);

        if( lastCompletedMovement != null && lastCompletedMovement.getDestinationLocation().equals(destinationLocation)) {
            log.info("The last completed movement has the same destination, therefore the movement will not be created, completed movement: {}", lastCompletedMovement.getCode());
            return lastCompletedMovement;
        }

        List<K> executingMovements = findByStatusAndDestination(existingMovements, Movement.Status.EXECUTING, destinationLocation);
        List<K> toDoMovements = findByStatusAndDestination(existingMovements, Movement.Status.TO_DO, destinationLocation);

        validateAtMostOneExecutionOrTodoMovementIsPresent(executingMovements, toDoMovements, destinationLocation, logisticUnit);
        if (!executingMovements.isEmpty()) {
            return executingMovements.get(0);
        }else if (!toDoMovements.isEmpty()) {
            toDoMovements.get(0).executing(statusChangedEventProducer);
            return toDoMovements.get(0);
        }else {
            LocationReference lastLocation = lastCompletedMovement != null ? lastCompletedMovement.getDestinationLocation() : null;
            Movement newMovement = createAndPersistNewMovement(lastLocation, logisticUnit, destinationLocation);
            newMovement.executing(statusChangedEventProducer);
            return newMovement;
        }
    }


    public <K extends Movement> K completeMovement(final List<K> existingMovements, final EntityReference logisticUnit, final LocationReference destinationLocation) {
        completeExecutingMovementsToOtherLocations(existingMovements,destinationLocation);
        cancelToDoMovementsToOtherLocations(existingMovements, destinationLocation);

        K lastCompletedMovement = findLastCompletedMovement(existingMovements);
        if( lastCompletedMovement != null && lastCompletedMovement.getDestinationLocation().equals(destinationLocation)) {
            log.info("The last completed movement has the same destination, completed movement: {}", lastCompletedMovement.getCode());
            return lastCompletedMovement;
        }

        List<K> executingMovements = findByStatusAndDestination(existingMovements, Movement.Status.EXECUTING, destinationLocation);

        if (executingMovements.isEmpty()) {
            throw new IllegalStateException(String.format("No movements in execution to the destination location %s for logisticUnit %s", destinationLocation, logisticUnit ));
        }
        if(executingMovements.size() > 1) {
            throw new IllegalStateException(String.format("Too many movements in execution to the destination location %s for logisticUnit %s", destinationLocation, logisticUnit ));
        }
        executingMovements.get(0).completed(statusChangedEventProducer);
        return executingMovements.get(0);
    }

    protected abstract <K extends Movement> K createNewInstance(@NonNull final EntityReference logisticUnitRef, final LocationReference sourceLocation,
                                              final LocationReference destinationLocation);


    private <K extends Movement>  void validateAtMostOneExecutionOrTodoMovementIsPresent(List<K> executingMovements, List<K> toDoMovements, LocationReference destinationLocation, EntityReference logisticUnit) {
        int executingSize = executingMovements.size();
        int toDoSize = toDoMovements.size();

        if (executingSize > 1) {
            throw new IllegalStateException(String.format("Too many movements in execution to the destination location %s for logisticUnit %s", destinationLocation, logisticUnit));
        }

        if (executingSize == 1 && toDoSize > 0) {
            throw new IllegalStateException(String.format("There are movements in both todo and executing for the same destination for logisticUnit %s and destination %s", logisticUnit, destinationLocation));
        }

        if (toDoSize > 1) {
            throw new IllegalStateException(String.format("Too many movements in TODO to the destination location %s for logisticUnit %s", destinationLocation, logisticUnit));
        }
    }

    public void completeExecutingMovementsToOtherLocations(List<? extends Movement> movements, LocationReference destinationLocation) {
        movements.stream()
            .filter(mov -> Movement.Status.isExecuting(mov.getStatus()) && !mov.getDestinationLocation().equals(destinationLocation))
            .forEach(mov -> mov.completed(statusChangedEventProducer));
    }

    public void cancelToDoMovementsToOtherLocations(List<? extends Movement> movements, LocationReference destinationLocation) {
        movements.stream()
            .filter(mov -> Movement.Status.isTodo(mov.getStatus()) && !mov.getDestinationLocation().equals(destinationLocation))
            .forEach(mov -> mov.cancel(statusChangedEventProducer));
    }

    private <K extends Movement> List<K> findByStatusAndDestination(List<K> movements, Movement.Status status, LocationReference destinationLocation) {
        return movements.stream()
            .filter(mov -> mov.getStatus().equals(status) && mov.getDestinationLocation().equals(destinationLocation))
            .collect(Collectors.toList());
    }

    private <K extends Movement> K createAndPersistNewMovement(LocationReference lastLocation, EntityReference logisticUnit, LocationReference destinationLocation) {
        K newMovement = createNewInstance(logisticUnit, lastLocation, destinationLocation);
        em.persist(newMovement);
        return newMovement;
    }

    public <K extends Movement> K findLastCompletedMovement(List<K> movements){
        return movements.stream()
            .filter(mov -> mov.getStatus().equals(Movement.Status.COMPLETED))
            .max(Comparator.comparing(Movement::getMovementEndDate)).orElse(null);
    }

}

---------- End of ./domainservice/MovementDomainService.java ----------

---------- Start of ./ValidationNotificationHandler.java ----------
package eu.reply.lea.services.yard;

public interface ValidationNotificationHandler {

    public void handleError(String aNotificationMessage);
    
}

---------- End of ./ValidationNotificationHandler.java ----------

---------- Start of ./YardUtils.java ----------
package eu.reply.lea.services.yard;

import java.util.Objects;

import eu.reply.lea.services.masterdata.model.Location;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.entity.TypedEntityReference;

public class YardUtils {

   public static boolean sameReference(final TypedEntityReference<?> ref1, final TypedEntityReference<?> ref2) {
       return sameReference(ref1, ref2, false);
   }

   public static boolean sameReference(final TypedEntityReference<?> ref1, final TypedEntityReference<?> ref2, final boolean excludeBusinessKey) {
       
       if(ref1==null || ref2==null) {
           return false;
       }
       boolean samebusinessKey = excludeBusinessKey || Objects.equals(ref1.getBusinessKey(),ref2.getBusinessKey());
       boolean sameEntityname = Objects.equals(ref1.getEntityName(), ref2.getEntityName());
       boolean sameEntityId = Objects.equals(ref1.getEntityId(), ref2.getEntityId());
       boolean sameModule = Objects.equals(ref1.getModule(), ref2.getModule());
       
       return sameModule && sameEntityId && sameEntityname && samebusinessKey;
   }

   public EntityReference getReference(final TypedEntityReference<?> reference) {
       return new EntityReference(reference.getModule(), reference.getEntityName(), reference.getEntityId(),TypedEntityReference.NULL_VALUE,reference.getBusinessKey());
   }

    public static EntityReference getEntityReference(final TypedEntityReference<?> r) {
        if(r == null) {
            return null;
        }
        return new EntityReference(r.getModule(), r.getEntityName(), r.getEntityId(), EntityReference.NULL_VALUE, r.getBusinessKey());
    }

    public static LocationReference getLocationReference(final TypedEntityReference<? extends Location> r) {
        if(r == null) {
            return null;
        }
        return new LocationReference(r);
    }

}

---------- End of ./YardUtils.java ----------

---------- Start of ./boundary/ExpectedContainerProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundWeightAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundWeightAction;
import eu.reply.lea.services.yard.entities.ExpectedContainer;
import eu.reply.lea.services.yard.entities.ExpectedLoadingUnit;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitCreatedEvent;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitDeletedEvent;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.ExpectedLoadingUnitActionException;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = ExpectedContainer.class)
public class ExpectedContainerProcessor extends AbstractExpectedLoadingUnitProcessor<ExpectedContainer> {

    @Override
    public void persisting(final ExpectedContainer entity) throws ExpectedLoadingUnitActionException {
        super.persisting(entity);
    }

    @Override
    public void persisted(final ExpectedContainer entity) {
        super.persisted(entity);
    }

    @Override
    public void merging(final ExpectedContainer entity) throws ExpectedLoadingUnitActionException {
        super.merging(entity);
    }

    @Override
    public void merged(final ExpectedContainer entity) {
        super.merged(entity);
    }

    @Override
    public void removing(final ExpectedContainer entity) throws ExpectedLoadingUnitActionException {
        super.removing(entity);
    }

    @Override
    public void removed(final ExpectedContainer entity) {
        super.removed(entity);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedContainer action(final ExpectedContainer expectedLoadingUnit,
                                    final ExpectedLoadingUnitRegisterInboundWeightAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedContainer action(final ExpectedContainer expectedLoadingUnit,
                                    final ExpectedLoadingUnitRegisterOutboundWeightAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedContainer action(final ExpectedContainer expectedLoadingUnit,
                                    final ExpectedLoadingUnitRegisterInboundSealAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedContainer action(final ExpectedContainer expectedLoadingUnit,
                                    final ExpectedLoadingUnitRegisterOutboundSealAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }
}


---------- End of ./boundary/ExpectedContainerProcessor.java ----------

---------- Start of ./boundary/LoadingUnitMovementProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.yard.entities.LoadingUnitMovement;
import eu.reply.lea.services.yard.events.LoadingUnitMovementCreatedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitMovementDeletedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitMovementUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitMovementActionException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = LoadingUnitMovement.class)
public class LoadingUnitMovementProcessor
    extends AbstractProcessor<LoadingUnitMovementCreatedEvent, LoadingUnitMovementDeletedEvent, LoadingUnitMovementUpdatedEvent> {


    // Lifecycle methods

    public void persisting(final LoadingUnitMovement entity)
        throws LoadingUnitMovementActionException, MasterdataServiceException {
        List<LoadingUnitMovement> movements =
            ListUtils.emptyIfNull(LoadingUnitMovement.findByLoadingUnit(getEm(), entity.getLoadingUnitRef()));
        if (LoadingUnitMovement.Status.isActive(entity.getStatus()) && movements.stream()
            .anyMatch(m -> LoadingUnitMovement.Status.isActive(m.getStatus()))) {
            throw new LoadingUnitMovementActionException(LoadingUnitMovementActionException.Codes.MOVEMENT_ON_GOING, null);
        }
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(this.generateCode(LoadingUnitMovement.class, null));
        }
    }


    //region CRUD
    public void persisted(final LoadingUnitMovement entity) {
        super.fireCreated(new LoadingUnitMovementCreatedEvent(entity));
    }

    public void merging(final LoadingUnitMovement entity) {
    }

    public void merged(final LoadingUnitMovement entity) {
        super.fireUpdated(new LoadingUnitMovementUpdatedEvent(entity));
    }

    public void removed(final LoadingUnitMovement entity) {
        super.fireDeleted(new LoadingUnitMovementDeletedEvent(entity));
    }
    //endregion


}

---------- End of ./boundary/LoadingUnitMovementProcessor.java ----------

---------- Start of ./boundary/TransitProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import java.io.InvalidClassException;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.yard.actions.transit.*;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitAttachedToTransitEvent;
import eu.reply.lea.services.yard.events.transit.TransitDenyingAccessDataEvent;
import eu.reply.lea.services.yard.events.transit.TransitDenyingAccessEvent;
import eu.reply.lea.services.yard.events.transit.TransitForcingOutDataEvent;
import eu.reply.lea.services.yard.events.transit.TransitForcingOutEvent;
import eu.reply.lea.services.yard.events.transit.TransitLockingDataEvent;
import eu.reply.lea.services.yard.events.transit.TransitLockingEvent;
import eu.reply.lea.services.yard.entities.*;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;

import com.google.common.base.Objects;

import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.carrier.Carrier;
import eu.reply.lea.services.masterdata.model.carrier.Driver;
import eu.reply.lea.services.masterdata.model.Container;
import eu.reply.lea.services.masterdata.model.goods.LoadingUnitRegistry;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.model.map.Site;
import eu.reply.lea.services.masterdata.model.Trailer;
import eu.reply.lea.services.masterdata.model.vehicle.Truck;
import eu.reply.lea.services.masterdata.pojo.carrier.DriverPojo;
import eu.reply.lea.services.masterdata.pojo.vehicle.TrailerPojo;
import eu.reply.lea.services.masterdata.pojo.vehicle.TruckPojo;
import eu.reply.lea.services.masterdata.reference.CarrierReference;
import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.lea.services.masterdata.reference.DriverReference;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.masterdata.reference.TruckReference;
import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.yard.YardUtils;
import eu.reply.lea.services.yard.events.transit.TransitArrivedEvent;
import eu.reply.lea.services.yard.events.transit.TransitCancelledEvent;
import eu.reply.lea.services.yard.events.transit.TransitCheckedInEvent;
import eu.reply.lea.services.yard.events.transit.TransitCheckedOutEvent;
import eu.reply.lea.services.yard.events.transit.TransitCreatedEvent;
import eu.reply.lea.services.yard.events.transit.TransitDeletedEvent;
import eu.reply.lea.services.yard.events.transit.TransitDeniedEvent;
import eu.reply.lea.services.yard.events.transit.TransitForcedOutEvent;
import eu.reply.lea.services.yard.events.transit.TransitLockedEvent;
import eu.reply.lea.services.yard.events.transit.TransitStatusChangedEvent;
import eu.reply.lea.services.yard.events.transit.TransitUnlockedEvent;
import eu.reply.lea.services.yard.events.transit.TransitUpdatedEvent;
import eu.reply.lea.services.yard.events.transit.TransitUrgencyChangedEvent;
import eu.reply.lea.services.yard.exceptions.TransitActionException;
import eu.reply.lea.services.yard.model.ContainerIdentification;
import eu.reply.lea.services.yard.model.HandlingRequest.ConfirmationStatus;
import eu.reply.lea.services.yard.model.HandlingRequestActivity.PlannedStatus;
import eu.reply.lea.services.yard.model.LoadingUnitResource.LoadStatus;
import eu.reply.lea.services.yard.model.LoadingUnitRegistrationInfo;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.configuration.Condition.Attribute;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.jee.log.Logged;
import lombok.NonNull;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = Transit.class)
public class TransitProcessor extends AbstractProcessor<TransitCreatedEvent, TransitDeletedEvent, TransitUpdatedEvent> {

    @Inject
    private LoadingUnitResourceHandler loadingUnitResourceHandler;

    @Inject
    private DefaultMasterdataService masterdataService;

    @Inject
    private Producer<TransitStatusChangedEvent> statusChangedEventProducer;

    @Inject
    private Producer<TransitCheckedInEvent> checkedInEventProducer;

    @Inject
    private Producer<TransitCheckedOutEvent> checkedOutEventProducer;

    @Inject
    private Producer<TransitForcedOutEvent> forcedOutEventProducer;

    @Inject
    private Producer<TransitForcingOutEvent> forcingOutEventProducer;

    @Inject
    private Producer<TransitUrgencyChangedEvent> urgencyChangedEventProducer;

    @Inject
    private Producer<TransitCancelledEvent> canceledEventProducer;

    @Inject
    private Producer<TransitArrivedEvent> arrivedEventProducer;

    @Inject
    private Producer<TransitDenyingAccessEvent> transitDenyingAccessEvent;

    @Inject
    private Producer<TransitDeniedEvent> deniedEventProducer;

    @Inject
    private Producer<TransitLockedEvent> lockedEventProducer;

    @Inject
    private Producer<TransitLockingEvent> lockingEventProducer;

    @Inject
    private Producer<TransitUnlockedEvent> unlockedEventProducer;

    @Inject
    private ConfigurableEventProducer<LoadingUnitAttachedToTransitEvent> loadingUnitAttachedToTransitProducer;


    // Lifecycle methods

    public void persisting(final Transit entity) throws MasterdataServiceException {
        TransitCreationValidator transitCreationValidator = new TransitCreationValidator(entity,new TransitCreationValidationNotificationHandler(),getEm());
        transitCreationValidator.validate();
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(this.generateCode(Transit.class, null));
        }

        updateReferences(entity);

        //set notification inside the transit.
        this.updateNotificationMode(entity, EnumSet.allOf(NotificationMode.class).stream().mapToInt(NotificationMode::getCode).sum());

        // By default, set the transit status of a new transit in WAITING
        //The status is not changed if it's TRANSFER
        if (!eu.reply.lea.services.yard.model.Transit.Status.TRANSFER.equals(entity.getStatus())) {
            entity.waiting();
        }
    }

    public void persisted(final Transit entity) {
        super.fireCreated(new TransitCreatedEvent(entity));
    }

    public void merging(final Transit entity) {
        Transit oldTransit = this.getEm().find(Transit.class, entity.getId());
        for (HandlingRequest hr : entity.getHandlingRequests()){
            if (hr.getId()== null){
                continue;
            }
            HandlingRequest hrOfOldTransit = oldTransit
                                                 .getHandlingRequests()
                                                 .stream()
                                                 .filter(oldHr -> oldHr.getId()
                                                 .equals(hr.getId()))
                                                 .findFirst().orElse(null);

            for (eu.reply.lea.services.yard.entities.LoadingUnitResource oldLoadingUnit : hrOfOldTransit.getUnits()){
                hr.addUnit(oldLoadingUnit);
            }
        }
        if(oldTransit.getCheckInDate()!=null){
            entity.setCheckInDate(oldTransit.getCheckInDate());
        }
        if(oldTransit.getCheckOutDate()!=null){
            entity.setCheckOutDate(oldTransit.getCheckOutDate());
        }
    }

    public void merged(final Transit entity) {
        super.fireUpdated(new TransitUpdatedEvent(entity));
    }

    public void removed(final Transit entity) {
        super.fireDeleted(new TransitDeletedEvent(entity));
    }

    // Actions methods

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"ARRIVED"}),
            @Attribute(name = "locked", values = {"false"})})
    //@formatter:on
    public Transit sendTransitArrived(final Transit transit) {

        if (transit.getStatus().equals(Transit.Status.ARRIVED)) {
            this.arrivedEventProducer.fire(new TransitArrivedEvent(transit));
        }
        return transit;
    }

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"WAITING"}),
            @Attribute(name = "locked", values = {"false"})})
    //@formatter:on
    public Transit sendTransitCreated(final Transit transit) {

        if (transit.getStatus().equals(Transit.Status.WAITING)) {
            super.fireCreated(new TransitCreatedEvent(transit));
        }
        return transit;
    }

    @Condition({@Attribute(name = "locked", values = {"true"})})
    public Transit sendTransitLocked(final Transit transit) {
        this.lockedEventProducer.fire(new TransitLockedEvent(transit));
        return transit;
    }

    @Condition({@Attribute(name = "locked", values = {"false"})})
    public Transit sendTransitUnlocked(final Transit transit) {
        this.unlockedEventProducer.fire(new TransitUnlockedEvent(transit));
        return transit;
    }

    /**
     * Set the transit to urgent. <br>
     * The following events are triggered:
     * <ol>
     * <li>TransitUrgencyChangedEvent
     * </ol>
     *
     * @param transit
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "urgent", values = {"false"}),
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"WAITING", "ARRIVED", "IN", "COMPLETED"})})
    //@formatter:on
    public Transit markAsUrgent(final Transit transit) throws TransitActionException {

        checkTransitCanSwitchToUrgent(transit);

        transit.urgent(null);
        this.urgencyChangedEventProducer.fire(new TransitUrgencyChangedEvent(transit));

        return transit;
    }

    /**
     * Set the transit to not urgent. <br>
     * The following events are triggered:
     * <ol>
     * <li>TransitUrgencyChangedEvent
     * </ol>
     *
     * @param transit
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "urgent", values = {"true"}),
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"WAITING", "ARRIVED", "IN", "COMPLETED"})})
    //@formatter:on
    public Transit markAsNotUrgent(final Transit transit) throws TransitActionException {
        checkTransitCanSwitchToNotUrgent(transit);
        transit.notUrgent();
        this.urgencyChangedEventProducer.fire(new TransitUrgencyChangedEvent(transit));
        return transit;
    }

    /**
     * Change the status of the transit to IN. <br>
     * Change the status of the inboundTrailers to MOVING. <br>
     * The following events are triggered:
     * <ol>
     * <li>TransitCheckedInEvent
     * <li>TransitStatusChangedEvent
     * </ol>
     *
     * @param transit
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"ARRIVED"})})
    //@formatter:on
    public Transit checkIn(final Transit transit) throws TransitActionException {
        checkTransitStatusCanSwitchToIn(transit);

        Transit.Status oldStatus = transit.getStatus();
        transit.in();

        this.checkedInEventProducer.fire(new TransitCheckedInEvent(transit));
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));

        return transit;
    }

    /**
     * Change the status of the transit to OUT. <br>
     * Change the status of the inboundTrailers to OUT. <br>
     * The following events are triggered:
     * <ol>
     * <li>TransitCheckedOutEvent
     * <li>TransitStatusChangedEvent
     * </ol>
     *
     * @param transit
     * @throws TransitActionException
     * @throws MasterdataServiceException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"COMPLETED"})})
    //@formatter:on
    public Transit checkOut(final Transit transit)
            throws TransitActionException, MasterdataServiceException {

        checkTransitStatusCanSwitchToOut(transit);
        Transit.Status oldStatus = transit.getStatus();
        transit.out();
        this.setLoadingUnitOut(transit);
        this.checkedOutEventProducer.fire(new TransitCheckedOutEvent(transit));
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));

        return transit;
    }

    /**
     *
     * Change the status of the transit to OUT.
     * Change the status of the inboundTrailers to OUT.
     * Fires forcingOutEventProducer which communicates with the YMS so
     * that the YMS can cancel the task from the transit.
     * @param transit
     * @return Transit in status OUT
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"IN", "COMPLETED"})})
    //@formatter:on
    public Transit forceCheckOut(final Transit transit) throws TransitActionException {
        checkTransitCanBeForcedOut(transit);
        Transit.Status oldStatus = transit.getStatus();

        transit.forceOut();
        this.getEm().flush();
        this.forcingOutEventProducer.fire(new TransitForcingOutEvent(new TransitForcingOutDataEvent(new TransitReference(transit), oldStatus)));
        return transit;
    }


    /**
     * Action called from the yms to confirm that the module has managed to complete the actions that he had
     * to do after the checkout of a transit without errors.
     * @param transit transit
     * @param transitForcedOutConfirmedAction the action containing information necessary for confirmation
     * @return transit
     */
    public Transit action(final Transit transit, TransitForcedOutConfirmedAction transitForcedOutConfirmedAction) {
        Transit.Status oldStatus = transitForcedOutConfirmedAction.getOldStatus();
        this.setLoadingUnitOut(transit);
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));
        this.forcedOutEventProducer.fire(new TransitForcedOutEvent(transit));
        return transit;
    }


    /**
     * Action called from the yms to confirm that the module hasn't been able to complete the actions that he had
     * to do after the checkout of a transit without errors.
     * @param transit transit
     * @param transitForcedOutFailedAction the action containing information necessary for rollbacking
     * @return transit
     */
    public Transit action(final Transit transit, TransitForcedOutFailedAction transitForcedOutFailedAction) {
        Transit.Status oldStatus = transitForcedOutFailedAction.getOldStatus();
        if(oldStatus.equals(eu.reply.lea.services.yard.model.Transit.Status.IN)){
            transit.in();
        } else if (oldStatus.equals(eu.reply.lea.services.yard.model.Transit.Status.COMPLETED)){
            transit.complete();
        }
        return transit;
    }

    /**
     * Change the status of the transit to CANCELED. <br>
     * The following events are triggered:
     * <ol>
     * <li>TransitDeletedEvent
     * <li>TransitStatusChangedEvent
     * </ol>
     *
     * @param transit
     * @throws TransitActionException
     */
    @Condition({@Attribute(name = "status", values = {"WAITING"})})
    public Transit cancel(final Transit transit) throws TransitActionException {
        checkTransitStatusCanSwitchToCanceled(transit);

        Transit.Status oldStatus = transit.getStatus();
        transit.cancel();

        this.canceledEventProducer.fire(new TransitCancelledEvent(transit));
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));

        return transit;
    }

    /**
     * Change the status of the transit to DENIED.
     * Fires TransitDenyingAccessEvent which communicates with the YMS so
     * that the YMS can cancel the task from the transit.
     * @return Transit in status DENIED
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"true"}),
            @Attribute(name = "status", values = {"WAITING", "ARRIVED"})})
    //@formatter:on
    public Transit denyTransitAccess(final Transit transit) throws TransitActionException {
        checkTransitIsLockedAndActiveButNotIn(transit);
        Transit.Status oldStatus = transit.getStatus();

        transit.deny();
        this.getEm().flush();
        this.transitDenyingAccessEvent.fire(new TransitDenyingAccessEvent(new TransitDenyingAccessDataEvent(new TransitReference(transit), oldStatus)));
        return transit;
    }



    /**
     * Action called from the yms to confirm that the module has managed to complete the actions that he had
     * to do after the denyAccess of a transit without errors.
     * @param transit transit
     * @param transitDeniedAccessFailedAction the action containing information necessary for confirmation
     * @return transit
     */
    @Condition({
        //@formatter:off
        @Attribute(name = "locked", values = {"true"}),
        @Attribute(name = "status", values = {"DENIED"})})
    public Transit action(final Transit transit, TransitDeniedAccessConfirmedAction transitDeniedAccessFailedAction) {
        Transit.Status oldStatus = transitDeniedAccessFailedAction.getOldStatus();
        this.setLoadingUnitOut(transit);
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));
        this.deniedEventProducer.fire(new TransitDeniedEvent(transit));
        return transit;
    }


    /**
     * Action called from the yms to confirm that the module hasn't been able to complete the actions that he had
     * to do after the DenyAccess of a transit without errors.
     * @param transit transit
     * @param transitDeniedAccessFailedAction the action containing information necessary for rollbacking
     * @return transit
     */
    @Condition({
        //@formatter:off
        @Attribute(name = "locked", values = {"true"}),
        @Attribute(name = "status", values = {"DENIED"})})
    public Transit action(final Transit transit, TransitDeniedAccessFailedAction transitDeniedAccessFailedAction) {
        Transit.Status oldStatus = transitDeniedAccessFailedAction.getOldStatus();
        if(oldStatus.equals(eu.reply.lea.services.yard.model.Transit.Status.ARRIVED)){
            transit.arrived();
        } else if (oldStatus.equals(eu.reply.lea.services.yard.model.Transit.Status.WAITING)){
            transit.waiting();
        }
        return transit;
    }


    /**
     * Set the flag locked of the transit to true<br>
     * The following events are triggered:
     * <ol>
     * <li>TransitLockedEvent
     * </ol>
     *
     * @return locked transit
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"false"}),
            @Attribute(name = "status", values = {"WAITING", "ARRIVED", "IN", "COMPLETED"})})
    //@formatter:on
    public Transit action(@Nonnull final Transit transit, final TransitLockAction action) throws TransitActionException {
        checkTransitIsUnlockedAndActive(transit);

        if (action.getReasonCode() == null) {
            throw new TransitActionException(TransitActionException.Codes.REASON_CODE_MISSING, transit.getCode());
        }
        TransitLockedConfirmedAction transitLockedAction= new TransitLockedConfirmedAction(action.getReasonCode(), action.getReasonDescription());
        transit.lock(action.getReasonCode(), action.getReasonDescription());
        this.getEm().flush();
        this.lockingEventProducer.fire(new TransitLockingEvent(new TransitLockingDataEvent(new TransitReference(transit), transitLockedAction)));
        return transit;
    }


    /**
     * Action called from the yms to confirm that the module has managed to complete the actions that he had
     * to do after the lock of a transit without errors.
     * @param transit transit
     * @param action the action containing information necessary for confirmation
     * @return transit
     */
    public Transit action(@Nonnull final Transit transit, final TransitLockedConfirmedAction action) throws TransitActionException {
        this.lockedEventProducer.fire(new TransitLockedEvent(transit));
        return transit;
    }


    /**
     * Action called from the yms to confirm that the module hasn't been able to complete the actions that he had
     * to do after the lock of a transit without errors.
     * @param transit transit
     * @return transit
     */
    public Transit lockedFailed(final Transit transit) {
        transit.unlock();
        return transit;
    }

    /**
     * Set the flag locked of the transit to false<br>
     * The following events are triggered:
     * <ol>
     * <li>TransitUnlockedEvent
     * </ol>
     * <p>
     *            transit
     *
     * @return unlocked transit
     * @throws TransitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "locked", values = {"true"}),
            @Attribute(name = "status", values = {"WAITING", "ARRIVED", "IN", "COMPLETED"})})
    //@formatter:on
    public Transit unlockTransit(final Transit transit) throws TransitActionException {

        checkTransitIsLockedAndActive(transit);

        transit.unlock();
        this.unlockedEventProducer.fire(new TransitUnlockedEvent(transit));

        return transit;
    }

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"ARRIVED", "IN", "COMPLETED"})})
    //@formatter:on
    public Transit action(final Transit originTransit, final TransitSetTransferDestinationAction action) throws TransitActionException {

        @NonNull SiteReference destinationSite = action.getDestinationSite();
        if (YardUtils.sameReference(originTransit.getDestinationSite(), destinationSite, true)) {
            throw new TransitActionException(TransitActionException.Codes.DESTINATION_SITE_SAME_AS_ORIGIN, originTransit.getCode());
        }

        Transit transitTransfer = Transit.findByOriginTransitTransfer(getEm(), originTransit);
        if (transitTransfer != null) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_TRANSFER_ALREADY_EXISTS, originTransit.getCode());
        }

        transitTransfer = createTargetTransitFromOriginTransit(originTransit, destinationSite);

        getEm().persist(transitTransfer);

        updateTransitTransfer(originTransit, transitTransfer);


        return originTransit;
    }

    private Transit createTargetTransitFromOriginTransit(final Transit originTransit, @NonNull final SiteReference destinationSite) {
        Transit transitTransfer;
        transitTransfer = new Transit(eu.reply.lea.services.yard.model.Transit.Status.TRANSFER, originTransit.getCarrier(), destinationSite);
        transitTransfer.setOriginTransitTransfer(originTransit);
        transitTransfer.setOriginSite(originTransit.getDestinationSite());
        transitTransfer.setTruck(originTransit.getTruck());
        transitTransfer.setTruckPlate(originTransit.getTruckPlate());
        transitTransfer.setDriver(originTransit.getDriver());
        transitTransfer.setDrivingLicence(originTransit.getDrivingLicence());
        return transitTransfer;
    }

    /**
     * Updates transitTransfer info starting from originTransit. <br>
     *
     * @param originTransit
     * @param transitTransfer
     */
    private void updateTransitTransfer(final eu.reply.lea.services.yard.model.Transit originTransit, final Transit transitTransfer) {
        //all origin outbound units
        Set<? extends LoadingUnitResource> outboundUnits = originTransit.getOutboundLoadingUnits();

        //origin EMPTY outbound units
        List<LoadingUnitResource> originEmptyUnits = outboundUnits == null ? Collections.emptyList() : outboundUnits.stream().filter(t -> LoadingUnitResource.LoadStatus.EMPTY.equals(t.getLoadStatus())).collect(Collectors.toList());

        //origin FULL outbound units
        List<LoadingUnitResource> originFullUnits = outboundUnits == null ? Collections.emptyList() : outboundUnits.stream().filter(t -> LoadingUnitResource.LoadStatus.FULL.equals(t.getLoadStatus())).collect(Collectors.toList());

        //LOAD handling request needed
        boolean loadHrNeeded = !CollectionUtils.isEmpty(originEmptyUnits);

        //UNLOAD handling request needed
        boolean unloadHrNeeded = !CollectionUtils.isEmpty(originFullUnits);

        //all transfer handling requests
        Set<HandlingRequest> transferHrs = transitTransfer.getHandlingRequests();

        //transfer LOAD Handling Request
        HandlingRequest transferLoadHr = transferHrs == null ? null : transferHrs.stream().filter(hr -> HandlingRequest.Type.LOAD.equals(hr.getType())).findFirst().orElse(null);

        //transfer UNLOAD Handling Request
        HandlingRequest transferUnloadHr = transferHrs == null ? null : transferHrs.stream().filter(hr -> HandlingRequest.Type.UNLOAD.equals(hr.getType())).findFirst().orElse(null);

        //remove unnecessary transfer LOAD Handling Requests
        if (transferLoadHr != null && !loadHrNeeded) {
            transitTransfer.removeHandlingRequest(transferLoadHr);
            transferLoadHr = null;
        }

        //remove unnecessary transfer UNLOAD Handling Requests
        if (transferUnloadHr != null && !unloadHrNeeded) {
            transitTransfer.removeHandlingRequest(transferUnloadHr);
            transferUnloadHr = null;
        }

        //remove unnecessary transfer LOAD HandlingRequest-Trailer
        if (transferLoadHr != null) {
            final HandlingRequest hr = transferLoadHr;
            //transfer LOAD HR-Trailers
            Set<ExpectedLoadingUnit> transferLoadHrTrailers = transferLoadHr.getExpectedUnits() == null ? Collections.emptySet() : transferLoadHr.getExpectedUnits();

            transferLoadHrTrailers.stream()
                    .filter(t -> !findContainer(originEmptyUnits, t).isPresent())
                    .forEach(t -> hr.removeExpectedContainer(t));
        }

        //remove unnecessary transfer UNLOAD HandlingRequest-Trailer
        if (transferUnloadHr != null) {
            final HandlingRequest hr = transferUnloadHr;
            //transfer UNLOAD HR-Trailers
            Set<ExpectedLoadingUnit> transferUnloadHrTrailers = transferUnloadHr.getExpectedUnits() == null ? Collections.emptySet() : transferUnloadHr.getExpectedUnits();

            transferUnloadHrTrailers.stream()
                    .filter(t -> findContainer(originFullUnits, t).isPresent())
                    .forEach(t -> hr.removeExpectedContainer(t));
        }

        //transfer ExpectedTrailers
        Set<? extends ExpectedLoadingUnit> transferExpectedContainers = transitTransfer.getExpectedLoadingUnits() == null ? Collections.emptySet() : transitTransfer.getExpectedLoadingUnits();

        //remove unnecessary transfer ExpectedTrailers
        transferExpectedContainers.stream()
                .filter(t -> !findContainer(outboundUnits, t).isPresent())
                .forEach(t -> transitTransfer.removeExpectedLoadingUnit(t));

        //create needed transfer LOAD Handling Request
        if (transferLoadHr == null && loadHrNeeded) {
            transferLoadHr = new HandlingRequest(transitTransfer, HandlingRequest.Type.LOAD, HandlingRequest.Status.TODO, ConfirmationStatus.UNCONFIRMED);
            getEm().persist(transferLoadHr);
            transitTransfer.addHandlingRequest(transferLoadHr);
        }

        //create needed transfer UNLOAD Handling Request
        if (transferUnloadHr == null && unloadHrNeeded) {
            transferUnloadHr = new HandlingRequest(transitTransfer, HandlingRequest.Type.UNLOAD, HandlingRequest.Status.TODO, ConfirmationStatus.UNCONFIRMED);
            getEm().persist(transferUnloadHr);
            transitTransfer.addHandlingRequest(transferUnloadHr);
        }

        //map outboundUnits - transferExpectedContainers
        Map<LoadingUnitResource, ExpectedLoadingUnit> containersMap = new HashMap<>();

        //TODO fixme in this part for refactoring
        //create or update transfer ExpectedTrailers
        for (LoadingUnitResource tr : outboundUnits) {
            ExpectedLoadingUnit et;
            Optional<? extends ContainerIdentification> alreadyExistingTrailer = findContainer(transferExpectedContainers, tr);
            if (alreadyExistingTrailer.isPresent()) {
                et = (ExpectedLoadingUnit) alreadyExistingTrailer.get();
            } else {
                //et = new ExpectedLoadingUnit(transitTransfer, tr.getIdentificationData());
                if (tr.getIdentificationData() instanceof LicencePlate) {
                    et = new ExpectedTrailer(transitTransfer, (LicencePlate) tr.getIdentificationData());
                } else {
                    et = new ExpectedContainer(transitTransfer, tr.getIdentificationData().toString());
                }
                getEm().persist(et);
                transitTransfer.addExpectedLoadingUnit(et);
            }
            containersMap.put(tr, et);
            et.registerInboundSeal(tr.getOutboundRegisteredSeal());
            et.registerInboundWeight(tr.getOutboundRegisteredWeight());
        }

        //create or update transfer LOAD HandlingRequest-Trailer
        if (loadHrNeeded) {
            //transfer LOAD HR-Trailers
            transferUnits(originEmptyUnits, transferLoadHr, containersMap);
        }

        //create or update transfer UNLOAD HandlingRequest-Trailer
        if (unloadHrNeeded) {
            //transfer UNLOAD HR-Trailers
            transferUnits(originFullUnits, transferUnloadHr, containersMap);
        }
    }

    private void transferUnits(final List<LoadingUnitResource> sourceContainers, final HandlingRequest transferHr, final Map<LoadingUnitResource, ExpectedLoadingUnit> containersMap) {
        Set<ExpectedLoadingUnit> transferContainers = transferHr.getExpectedUnits() == null ? Collections.emptySet() : transferHr.getExpectedUnits();
        for (Map.Entry<LoadingUnitResource, ExpectedLoadingUnit> tr : containersMap.entrySet()) {
            if (sourceContainers.contains(tr.getKey()) && !findContainer(transferContainers, tr.getKey()).isPresent()) {
                transferHr.addExpectedContainer(tr.getValue());
            }
        }
    }

    public void updateTransitTransfer(final eu.reply.lea.services.yard.model.Transit originTransit) {
        Transit transitTransfer = Transit.findByOriginTransitTransfer(getEm(), originTransit);
        if (transitTransfer == null) {
            return;
        }
        updateTransitTransfer(originTransit, transitTransfer);
    }

    private Optional<? extends ContainerIdentification> findContainer(final Collection<? extends ContainerIdentification> containers, final ContainerIdentification container) {
        if (container == null || CollectionUtils.isEmpty(containers)) {
            return Optional.empty();
        }
        return containers.stream().filter(t -> ((ContainerIdentification) t).isSameContainer(container)).findAny();
    }

    public Transit action(@Nonnull final Transit transit, final TransitAddExpectedRegistrationDatesAction action) {
        transit.updateRegistrationInformation(action.getExpectedRegistrationDateFrom(), action.getExpectedRegistrationDateTo());
        return transit;
    }

        /**
         * Change the status of the transit to ARRIVED. <br>
         * The following events are triggered:
         * <ol>
         * <li>TransitArrivedEvent
         * <li>TransitStatusChangedEvent
         * </ol>
         *
         * @param transit, transitRegistrationAction
         * @throws TransitActionException
         * @throws MasterdataServiceException
         * @throws InvalidClassException
         * @throws EntityNotFoundException
         */
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"WAITING"}),
            @Attribute(name = "locked", values = {"false"})})
    //@formatter:on
    public Transit action(@Nonnull final Transit transit, final TransitRegistrationAction action) throws TransitActionException, MasterdataServiceException, InvalidClassException, EntityNotFoundException {

        checkTransitCanPerformRegistration(transit);
        // Update transit urgency
        if (action.getUrgent() != null) {
            if (transit.isUrgent() && !action.getUrgent()) {
                markAsNotUrgent(transit);
            } else if (!transit.isUrgent() && action.getUrgent()) {
                markAsUrgent(transit);
            }
        }

        //set notification inside the transit.
        this.updateNotificationMode(transit, action.getNotificationModes());

        // Update transit notes, if action.notes is null do nothing
        if (StringUtils.isNotBlank(action.getNotes())) {
            transit.setNotes(action.getNotes());
        }

        //update badges, if action.getUid is not null
        if (StringUtils.isNotBlank(action.getUid())) {
            //check if there is a same uid inside the plant
            checkIfUidIsAlreadyInPlant(action.getUid());
            //if result of check is clear, can set the uid to the transit
            transit.setUid(action.getUid());
        } else {
            //if uid is empty, automatic setting it with transitCode
            transit.setUid(transit.getCode());
        }

        // Check if the input truck plate matches a truck in masterdata. If not,
        // throw exception.
        Truck truck = null;
        if (action.getTruckReference() != null) {
            truck = this.masterdataService.get(action.getTruckReference());
        } else {
            truck = this.masterdataService.getByLicencePlate(Truck.RESOURCE_NAME, action.extractLicencePlate(), TruckPojo.class).get(0);
        }

        if (action.isEnabledWrongCarrierCheck())
            checkCarrier(transit, truck);
        //use truck.getLicencePlate() instead of action.extractDrivingLicence()
        List<Transit> transitList = Transit.findByTruckPlate(this.getEm(), truck.getLicencePlate());
        checkTruckAlreadyInsideThePlant(transit, transitList);

        transit.setTruck(new TruckReference(truck));
        transit.setTruckPlate(truck.getLicencePlate());

        // If present, check if the input driver license matches a driver in masterdata. If not, throw exception.
        if (action.getDriverLicense() != null && action.getDriverLicenseCountry() != null) {
            Driver driver = this.masterdataService.getByDrivingLicence(Driver.RESOURCE_NAME, action.extractDrivingLicence(), DriverPojo.class).get(0);
            checkDriverAlreadyInsideThePlant(transit, driver);
            transit.setDriver(new DriverReference(driver));
            transit.setDrivingLicence(driver.getDrivingLicence());
        }

        Set<HandlingRequest> transitRequests = transit.getHandlingRequests();
        // Set all HR confirmation status to UNCONFIRMED; the HR used in
        // Registration will be set as EXPECTED/UNEXPECTED.
        transitRequests.stream().forEach(hr -> hr.setConfirmationStatus(HandlingRequest.ConfirmationStatus.UNCONFIRMED));

        // If present, cycle over the list of loading units inserted in registration
        // (loadingUnitRegistrationInfo)

        if (action.getLoadingUnitRegistrationInfo() != null) {
            processRegistrationLoadingUnits(transit, action, transitRequests);
        }

        Transit.Status oldStatus = transit.getStatus();
        transit.arrived();
        transit.setRegistrationDate(Calendar.getInstance());
        this.statusChangedEventProducer.fire(new TransitStatusChangedEvent(transit, oldStatus));
        this.arrivedEventProducer.fire(new TransitArrivedEvent(transit));

        return transit;
    }

    private void processRegistrationLoadingUnits(final Transit transit, final TransitRegistrationAction action, final Set<HandlingRequest> transitRequests) throws TransitActionException, MasterdataServiceException, InvalidClassException, EntityNotFoundException {
        for (LoadingUnitRegistrationInfo registrationInfo : action.getLoadingUnitRegistrationInfo()) {
            Boolean isPickup = registrationInfo.isPickup();
            validateTrailerDataAndRequest(transit, registrationInfo);
            // If PICKUP has to be performed, it means that the loading unit is already inside the plant -> it must not be created
            eu.reply.lea.services.yard.entities.LoadingUnitResource
                loadingUnit = registerLoadingUnitResource(transit, registrationInfo, isPickup);

            // The HRTrailerActivity is considered EXPECTED only if the HR
            // of the Transit are associated to ExpectedTrailers
            // and both (HR and ExpectedLoadingUnit) are confirmed at
            // registration. Otherwise it is UNEXPECTED
            Set<HandlingRequest.Type> registrationRequestTypes = populateAndCheckTrailerRequestsTypeSet(transit, registrationInfo, loadingUnit);

            for (HandlingRequest.Type registrationRequestType : registrationRequestTypes) {

                Set<HandlingRequest> expectedHandlingRequests = transitRequests.stream()
                        .filter(hr -> hr.getType().equals(registrationRequestType)).collect(Collectors.toSet());

                if (!expectedHandlingRequests.isEmpty()) {
                    for (HandlingRequest expectedHandlingRequest : expectedHandlingRequests) {
                        if (!HandlingRequest.ConfirmationStatus.UNEXPECTED.equals(expectedHandlingRequest.getConfirmationStatus())) {
                            expectedHandlingRequest.setConfirmationStatus(HandlingRequest.ConfirmationStatus.EXPECTED);
                        }
                        if (findExpectedTrailer(registrationInfo, expectedHandlingRequest.getExpectedUnits()) != null) {
                            expectedHandlingRequest.addHandlingRequestActivity(new HandlingRequestActivity(loadingUnit, PlannedStatus.EXPECTED));
                            expectedHandlingRequest.addUnit(loadingUnit);
                        } else {
                            expectedHandlingRequest.addHandlingRequestActivity(new HandlingRequestActivity(loadingUnit, PlannedStatus.UNEXPECTED));
                            expectedHandlingRequest.addUnit(loadingUnit);
                        }
                        getEm().merge(expectedHandlingRequest);
                    }
                } else {
                    HandlingRequest request = createHandlingRequest(transit, loadingUnit, registrationRequestType);

                    DockReference requestDock = registrationInfo.getDockReference();

                    if (requestDock != null) {
                        //check if the dock reference inside the detail corresponds to an existing dock.
                        Dock dock = masterdataService.get(requestDock);
                        request.setLocation(new LocationReference(dock));
                    }
                    getEm().persist(request);
                }
            }
        }
    }

    private eu.reply.lea.services.yard.entities.LoadingUnitResource registerLoadingUnitResource(final Transit transit, final LoadingUnitRegistrationInfo registrationInfo, final Boolean isPickup) throws MasterdataServiceException, TransitActionException, EntityNotFoundException {
        LoadingUnitRegistry loadingUnitRegistry = findLoadingUnitRegistry(transit, registrationInfo);
        eu.reply.lea.services.yard.entities.LoadingUnitResource loadingUnit = null;
        if (!isPickup) {
            List<? extends LoadingUnitResource> loadingUnits = getLoadingUnits(loadingUnitRegistry);
            errorIfUnitsAreStillInsideThePlant(transit, loadingUnits);

            Object loadingUnitIdentification = registrationInfo.getLoadingUnitIdentification();
            ExpectedLoadingUnit matchingUnit = findMatchingExpectedLoadingUnits(transit, loadingUnitIdentification);
            if(matchingUnit==null){
                loadingUnit = createLoadingUnit(transit, registrationInfo, loadingUnitRegistry);

            }else {
                loadingUnit = matchingUnit.createLoadingUnit(registrationInfo.getLoadStatus(), loadingUnitRegistry);
            }
            this.getEm().persist(loadingUnit);
        } else {
            List<? extends eu.reply.lea.services.yard.entities.LoadingUnitResource> loadingUnits = getLoadingUnitsInThePlant(loadingUnitRegistry);
            if (loadingUnits.isEmpty()) {
                throw new TransitActionException(TransitActionException.Codes.PICKUP_UNIT_NOT_INSIDE_THE_PLANT, transit.getCode());
            } else {
                loadingUnit = loadingUnits.get(0);
            }
        }

        return loadingUnit;
    }

    private ExpectedLoadingUnit findMatchingExpectedLoadingUnits(final Transit transit, final Object loadingUnitIdentification) {
        return transit.getExpectedLoadingUnits()
                .stream()
                .filter(expected -> {
                    return expected.getIdentificationData().equals(loadingUnitIdentification);
                })
                .findFirst().orElse(null);
    }

    private List<? extends eu.reply.lea.services.yard.entities.LoadingUnitResource> getLoadingUnits(final LoadingUnitRegistry loadingUnitRegistry) {
        return loadingUnitRegistry instanceof Container ? ContainerResource.findByBic(getEm(), ((Container) loadingUnitRegistry).getBic()) :
                TrailerResource.findBy(getEm(), ((Trailer) loadingUnitRegistry).getLicencePlate());
    }

    private List<? extends eu.reply.lea.services.yard.entities.LoadingUnitResource> getLoadingUnitsInThePlant(final LoadingUnitRegistry loadingUnitRegistry) throws EntityNotFoundException {
        return loadingUnitRegistry instanceof Container ? ContainerResource.findByBicAndStatus(getEm(), ((Container) loadingUnitRegistry).getBic(), LoadingUnitResource.Status.OUT) :
                TrailerResource.findByPlateAndStatus(getEm(), ((Trailer) loadingUnitRegistry).getLicencePlate(), LoadingUnitResource.Status.OUT);
    }

    private LoadingUnitRegistry findLoadingUnitRegistry(final Transit transit, final LoadingUnitRegistrationInfo registrationInfo) throws MasterdataServiceException, TransitActionException {
        if (registrationInfo.isContainer()) {
            return findContainer(transit, registrationInfo.getBic());
        } else {
            return findTrailer(transit, registrationInfo.extractLicencePlate());
        }
    }

    private eu.reply.lea.services.yard.entities.LoadingUnitResource createLoadingUnit(final Transit transit, final LoadingUnitRegistrationInfo registrationInfo, final LoadingUnitRegistry loadingUnitRegistry) {
        eu.reply.lea.services.yard.entities.LoadingUnitResource loadingUnit = null;
        if (loadingUnitRegistry instanceof Container) {
            Container container = (Container) loadingUnitRegistry;
            loadingUnit = new ContainerResource(container.getBic(), registrationInfo.getLoadStatus(), LoadingUnitResource.ConfirmationStatus.UNEXPECTED, transit, loadingUnitRegistry);
        } else {
            loadingUnit = new TrailerResource(registrationInfo.extractLicencePlate(), registrationInfo.getLoadStatus(), LoadingUnitResource.ConfirmationStatus.UNEXPECTED, transit, loadingUnitRegistry);
        }
        return loadingUnit;
    }

    private ExpectedLoadingUnit findExpectedTrailer(final LoadingUnitRegistrationInfo registrationInfo, final Set<ExpectedLoadingUnit> expectedLoadingUnits) {
        return expectedLoadingUnits != null ? expectedLoadingUnits.stream()
                .filter(exp -> exp.getIdentificationData().equals(registrationInfo.getLoadingUnitIdentification())).findFirst().orElse(null) : null;
    }

    private HandlingRequest createHandlingRequest(final Transit transit, final eu.reply.lea.services.yard.entities.LoadingUnitResource container, final HandlingRequest.Type registrationRequestType, Boolean createHRActivity) {
        HandlingRequest request = new HandlingRequest(registrationRequestType);
        transit.addHandlingRequest(request);
        request.setConfirmationStatus(HandlingRequest.ConfirmationStatus.UNEXPECTED);
        request.addUnit(container);
        if (createHRActivity) {
            request.addHandlingRequestActivity(new HandlingRequestActivity(container, PlannedStatus.UNEXPECTED));
        }
        return request;
    }

    private HandlingRequest createHandlingRequest(final Transit transit, final eu.reply.lea.services.yard.entities.LoadingUnitResource container, final HandlingRequest.Type registrationRequestType) {
        return createHandlingRequest(transit, container, registrationRequestType, true);
    }



    private void updateReferences(final Transit entity) throws MasterdataServiceException {

        if (entity.getCarrier() != null) {
            Carrier carrier = null;
            String carrierEntityId = entity.getCarrier().getEntityId();
            String businessKey = entity.getCarrier().getBusinessKey();
            if (carrierEntityId == null || carrierEntityId.isEmpty()) {
                String carrierCode = "";
                String companyCode = "";

                if (businessKey.isEmpty())
                    throw new RuntimeException("Carrier.getBusinessKey cannot be empty!");

                String charForSplit = " ";
                if (businessKey.contains(",")) {
                    charForSplit = ",";
                    businessKey = businessKey.trim();
                }

                String[] businessKeySplitted = businessKey.split(charForSplit);
                if (businessKeySplitted.length >= 1) {
                    companyCode = businessKeySplitted[0];
                    carrierCode = businessKeySplitted[1];
                }

                if (carrierCode.isEmpty())
                    throw new RuntimeException("CarrierCode inside businessKey cannot be empty!");

                if (companyCode.isEmpty())
                    throw new RuntimeException("CompanyCode inside businessKey cannot be empty!");

                carrier = masterdataService.getCarrier(carrierCode, companyCode);

            } else {
                carrier = masterdataService.get(entity.getCarrier());
            }

            if (carrier == null)
                throw new RuntimeException("Cannot retrieve carrier info");

            entity.setCarrier(new CarrierReference(carrier));
        }

        Site destinationSite = null;

        if (entity.getDestinationSite() != null) {
            String destinationSiteEntityId = entity.getDestinationSite().getEntityId();
            if (destinationSiteEntityId == null || destinationSiteEntityId.isEmpty()) {
                String siteCode = entity.getDestinationSite().getBusinessKey();
                destinationSite = masterdataService.getSite(siteCode);
            } else {
                destinationSite = masterdataService.get(entity.getDestinationSite());
            }

            if (destinationSite == null)
                throw new RuntimeException("Cannot retrieve destinationSite info");

            entity.setDestinationSite(new SiteReference(destinationSite));
        }

        Site originSite = null;
        if (entity.getOriginSite() != null) {
            if (destinationSite != null && Long.toString(destinationSite.getId()).equals(entity.getOriginSite().getEntityId())) {
                //If here means that the destination and the original site are equals
                //avoid another access inside database.
                originSite = destinationSite;
            } else {
                String originSiteEntityId = entity.getOriginSite().getEntityId();
                if (originSiteEntityId == null || originSiteEntityId.isEmpty()) {
                    String siteCode = entity.getOriginSite().getBusinessKey();
                    originSite = masterdataService.getSite(siteCode);
                } else {
                    originSite = masterdataService.get(entity.getOriginSite());
                }
            }

            if (originSite == null)
                throw new RuntimeException("Cannot retrieve originSite info");

            entity.setOriginSite(new SiteReference(originSite));
        }
    }

    private Trailer findTrailer(final Transit transit, final LicencePlate plate) throws MasterdataServiceException, TransitActionException {
        List<TrailerPojo> trailers = masterdataService.getByLicencePlate(Trailer.RESOURCE_NAME, plate, TrailerPojo.class);
        if (!CollectionUtils.isEmpty(trailers)) {
            return trailers.get(0);
        } else {
            throw new TransitActionException(TransitActionException.Codes.TRAILER_MASTERDATA_NOT_FOUND, transit.getCode());
        }

    }

    private Container findContainer(final Transit transit, final String bic) throws MasterdataServiceException, TransitActionException {
        List<? extends Container> containers = masterdataService.getByBic(bic);
        if (!CollectionUtils.isEmpty(containers)) {
            return containers.get(0);
        } else {
            throw new TransitActionException(TransitActionException.Codes.TRAILER_MASTERDATA_NOT_FOUND, transit.getCode());
        }

    }


    //
    // Methods that check if exceptions should be thrown
    //

    private void checkTransitCanSwitchToUrgent(final Transit transit) throws TransitActionException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.isActive(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
        if (transit.isUrgent()) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_IS_URGENT, transit.getCode());
        }
    }

    private void checkTransitCanSwitchToNotUrgent(final Transit transit) throws TransitActionException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.isActive(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
        if (!transit.isUrgent()) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_IS_NOT_URGENT, transit.getCode());
        }
    }

    private void checkTransitStatusCanSwitchToCanceled(final Transit transit) throws TransitActionException {
        if (!Transit.Status.WAITING.equals(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
    }

    /**
     * Check if the transit is locked and the status in WAITING,ARRIVED
     *
     * @param transit
     * @throws TransitActionException
     */
    private void checkTransitIsLockedAndActiveButNotIn(final Transit transit) throws TransitActionException {
        checkTransitIsLocked(transit);
        if (!Transit.Status.isActive(transit.getStatus()) || Transit.Status.isIn(transit.getStatus()))
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
    }

    /**
     * Check if the transit is locked and the status in "WAITING", "ARRIVED",
     * "IN", "COMPLETED"
     *
     * @param transit
     * @throws TransitActionException
     */
    private void checkTransitIsLockedAndActive(final Transit transit) throws TransitActionException {
        checkTransitIsLocked(transit);
        if (!Transit.Status.isActive(transit.getStatus()))
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
    }

    /**
     * Check if the transit is unlocked and the status in "WAITING", "ARRIVED",
     * "IN", "COMPLETED"
     *
     * @param transit
     * @throws TransitActionException
     */
    private void checkTransitIsUnlockedAndActive(final Transit transit) throws TransitActionException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.isActive(transit.getStatus()))
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
    }

    private void checkTransitStatusCanSwitchToIn(final Transit transit) throws TransitActionException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.ARRIVED.equals(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
        if (transit.getTruck() == null) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_WITH_NO_TRUCK, transit.getCode());
        }
        if (transit.getCarrier() == null) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_WITH_NO_CARRIER, transit.getCode());
        }
        if ((transit.getInboundLoadingUnits() == null && transit.getOutboundLoadingUnits() == null)
                || (transit.getInboundLoadingUnits().size() + transit.getOutboundLoadingUnits().size() == 0)) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_WITH_NO_TRAILERS, transit.getCode());
        }
        if (transit.getInboundLoadingUnits().stream().anyMatch(it -> {
            return HandlingRequestActivity.findBy(getEm(), it).size() == 0;
        })) {
            throw new TransitActionException(TransitActionException.Codes.TRAILER_WITH_NO_REQUESTS, transit.getCode());
        }
    }

    private void checkTransitStatusCanSwitchToOut(final Transit transit) throws TransitActionException, MasterdataServiceException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.COMPLETED.equals(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }

        // check the units attached to the outgoing truck are the same
        // contained in the transit set outboundTrailers
        Truck truck = masterdataService.get(transit.getTruck());
        Set<? extends LoadingUnitResource> attachedUnits = getCurrentlyAttachedUnits(transit, truck);

        if (!attachedUnits.equals(transit.getOutboundLoadingUnits())) {
            throw new TransitActionException(TransitActionException.Codes.OUTGOING_TRANSIT_WITH_WRONG_ATTACHED_TRAILERS, transit.getCode());
        }
    }

    private Set<eu.reply.lea.services.yard.entities.LoadingUnitResource> getCurrentlyAttachedUnits(final Transit transit, final Truck truck) {
        return SetUtils.union(transit.getInboundLoadingUnits(), transit.getOutboundLoadingUnits()).stream()
                .filter(itr -> itr.isAttachedTo(new VehicleReference(new TruckReference(truck)))).collect(Collectors.toSet());
    }

    private void checkTransitCanBeForcedOut(final Transit transit) throws TransitActionException {
        if (!Transit.Status.isIn(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
    }

    private void checkTransitIsUnlocked(final Transit transit) throws TransitActionException {
        if (transit.isLocked()) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_LOCKED, transit.getCode());
        }
    }

    private void checkTransitIsLocked(final Transit transit) throws TransitActionException {
        if (!transit.isLocked()) {
            throw new TransitActionException(TransitActionException.Codes.TRANSIT_NOT_LOCKED, transit.getCode());
        }
    }

    private void checkTransitCanPerformRegistration(final Transit transit) throws TransitActionException {
        checkTransitIsUnlocked(transit);
        if (!Transit.Status.WAITING.equals(transit.getStatus())) {
            throw new TransitActionException(TransitActionException.Codes.STATUS_NOT_VALID, transit.getCode());
        }
    }

    /**
     * Check that the truck inserted in registration is not already inside the
     * plant: if the truck belongs to a Transit in status "ARRIVED", "IN" or
     * "COMPLETED", raise an exception.
     *
     * @param transit
     * @throws TransitActionException
     */
    private void checkTruckAlreadyInsideThePlant(final Transit transit, final List<Transit> transitList) throws TransitActionException {
        if (!transitList.isEmpty()) {
            for (Transit matchedTransit : transitList) {
                if (Transit.Status.isActive(matchedTransit.getStatus()) && !Transit.Status.WAITING.equals((matchedTransit.getStatus()))) {
                    throw new TransitActionException(TransitActionException.Codes.TRUCK_ALREADY_INSIDE_THE_PLANT, transit.getCode());
                }
            }
        }
    }

    /**
     * Check that the driver inserted in registration is not already inside the
     * plant: if the driver belongs to a Transit in status "ARRIVED", "IN" or
     * "COMPLETED", raise an exception.
     *
     * @param transit
     * @param driver
     * @throws TransitActionException
     */
    private void checkDriverAlreadyInsideThePlant(final Transit transit, final Driver driver) throws TransitActionException {
        if (driver == null) {
            return;
        }

        List<Transit> transitList = Transit.findByDriver(getEm(), driver.getDrivingLicence());
        if (transitList != null && transitList.stream().anyMatch(t -> !t.getCode().equals(transit.getCode()) && Transit.Status.isActive(t.getStatus())
                && !Transit.Status.WAITING.equals(t.getStatus()))) {
            throw new TransitActionException(TransitActionException.Codes.DRIVER_ALREADY_INSIDE_THE_PLANT, transit.getCode());
        }
    }

    /**
     * Check that the loading unit inserted in registration is not already
     * inside/outside the plant: if the loading unit is found in status "MOVING",
     * "IN_PLACE" or "PARKED", raise an exception if HR is NOT a PICKUP.
     *
     * @param transit
     * @return
     * @throws TransitActionException
     */
    private void errorIfUnitsAreStillInsideThePlant(final Transit transit, final List<? extends LoadingUnitResource> loadingUnits) throws TransitActionException {
        if (!loadingUnits.isEmpty()) {
            for (LoadingUnitResource matchedUnit : loadingUnits) {
                if (TrailerResource.Status.isIn(matchedUnit.getStatus())) {
                    throw new TransitActionException(TransitActionException.Codes.LOADING_UNIT_ALREADY_INSIDE_THE_PLANT, transit.getCode());
                }
            }
        }
    }

    private Set<HandlingRequest.Type> populateAndCheckTrailerRequestsTypeSet(final Transit transit,
                                                                             final LoadingUnitRegistrationInfo loadingUnitRegistrationInfo, final eu.reply.lea.services.yard.entities.LoadingUnitResource loadingUnit) throws TransitActionException {

        Set<HandlingRequest.Type> loadingUnitRequestTypeSet = new HashSet<>();
        if (loadingUnitRegistrationInfo.isLoading()) {
            loadingUnitRequestTypeSet.add(HandlingRequest.Type.LOAD);
            transit.addInboundUnit(loadingUnit);
            transit.addOutboundUnit(loadingUnit);
            loadingUnit.setAttachedVehicle(new VehicleReference(transit.getTruck()));
            loadingUnit.attachTransit(new TransitReference(transit), loadingUnitAttachedToTransitProducer);
        }
        if (loadingUnitRegistrationInfo.isUnloading()) {
            loadingUnitRequestTypeSet.add(HandlingRequest.Type.UNLOAD);
            transit.addInboundUnit(loadingUnit);
            transit.addOutboundUnit(loadingUnit);
            loadingUnit.setAttachedVehicle(new VehicleReference(transit.getTruck()));
            loadingUnit.attachTransit(new TransitReference(transit), loadingUnitAttachedToTransitProducer);
        }
        if (loadingUnitRegistrationInfo.isPickup()) {
            loadingUnitRequestTypeSet.add(HandlingRequest.Type.PICKUP);
            transit.addOutboundUnit(loadingUnit);
        }
        if (loadingUnitRegistrationInfo.isDropOff()) {
            loadingUnitRequestTypeSet.add(HandlingRequest.Type.DROPOFF);
            transit.addInboundUnit(loadingUnit);
            loadingUnit.setAttachedVehicle(new VehicleReference(transit.getTruck()));
            loadingUnit.attachTransit(new TransitReference(transit), loadingUnitAttachedToTransitProducer);
        }
        if (loadingUnitRequestTypeSet == null || loadingUnitRequestTypeSet.size() == 0) {
            throw new TransitActionException(TransitActionException.Codes.TRAILER_WITH_NO_REQUEST_TYPE, transit.getCode());
        }

        return loadingUnitRequestTypeSet;
    }

    private void checkCarrier(final Transit transit, final Truck truck) throws TransitActionException {
        if (!transit.getCarrier().equals(new CarrierReference(truck.getCarrier()))) {
            throw new TransitActionException(TransitActionException.Codes.WRONG_CARRIER, transit.getCode());
        }
    }

    /**
     * Throw exception if:
     * - loadingUnit is EMPTY and the request is of type UNLOADING;
     * - loadingUnit is FULL and the request is of type LOADING;
     * - loadingUnit identification data is blank and at least one request (LOADING/UNLOADING) has been specified.
     *
     * @param transit, loadingUnitRegistrationInfo
     * @throws TransitActionException
     */
    private void validateTrailerDataAndRequest(final Transit transit, final LoadingUnitRegistrationInfo loadingUnitRegistrationInfo) throws TransitActionException {
        Object unitIdentification = loadingUnitRegistrationInfo.getLoadingUnitIdentification();
        LoadStatus loadStatus = loadingUnitRegistrationInfo.getLoadStatus();
        Boolean isLoading = loadingUnitRegistrationInfo.isLoading();
        Boolean isUnloading = loadingUnitRegistrationInfo.isUnloading();
        Boolean isPickup = loadingUnitRegistrationInfo.isPickup();
        Boolean isDropOff = loadingUnitRegistrationInfo.isDropOff();

        if (isPickup && (isLoading || isUnloading || isDropOff)) {
            throw new TransitActionException(TransitActionException.Codes.PICKUP_AND_OTHER_REQUESTS, transit.getCode());
        }
        if (isDropOff && (isLoading || isUnloading || isPickup)) {
            throw new TransitActionException(TransitActionException.Codes.DROPOFF_AND_OTHER_REQUESTS, transit.getCode());
        }
        if ((unitIdentification == null || loadStatus == null) && (isLoading || isUnloading)) {
            throw new TransitActionException(TransitActionException.Codes.REQUEST_WITHOUT_TRAILER, transit.getCode());
        }
        if (Objects.equal(loadStatus, LoadStatus.EMPTY) && isUnloading && !isLoading) {
            throw new TransitActionException(TransitActionException.Codes.UNLOAD_EMPTY_TRAILER, transit.getCode());
        }
        if (Objects.equal(loadStatus, LoadStatus.FULL) && !isUnloading && isLoading) {
            throw new TransitActionException(TransitActionException.Codes.LOAD_FULL_TRAILER, transit.getCode());
        }
    }

    /**
     * The aim of this method is to check if
     * is already inside the plant a transit
     * with the same uid.
     *
     * @param uid UniversalIdentificator
     * @throws TransitActionException
     */
    private void checkIfUidIsAlreadyInPlant(@Nonnull final String uid) throws TransitActionException {
        //get the list of transits with this uid
        //and status arrived, in or completed
        List<Transit> transits = Transit.findTransitByUidAndStatusArrivedOrInOrCompleted(getEm(), uid);
        //check if is already inside plant
        //a transit with same uid
        if (transits.size() > 0)
            throw new TransitActionException(TransitActionException.Codes.BADGE_ALREADY_IN_PLANT, "Transit with same uid is already inside plant!");

    }


    /**
     * The aim of this method is to set
     *
     * @param transit           Transit to be updated
     * @param notificationModes notificationMode to be set inside transit
     */
    private void updateNotificationMode(final Transit transit, final int notificationModes) {
        int notificationValue = 0;

        if (notificationModes == 0) {
            notificationValue = EnumSet.allOf(NotificationMode.class).stream().mapToInt(NotificationMode::getCode).sum();
        } else {
            //In case we valorize the notification mode we need to translate it.
            EnumSet<NotificationMode> notificationReceived = EnumSet.noneOf(NotificationMode.class);
            EnumSet.allOf(NotificationMode.class).stream().forEach(item -> {
                if ((item.getCode() & notificationModes) == item.getCode()) {
                    notificationReceived.add(item);
                }
            });

            notificationValue = notificationReceived.stream().mapToInt(NotificationMode::getCode).sum();
        }
        transit.setNotificationMode(notificationValue);
    }

    //region Loading Unit Management

    /**
     * Exit resource linked to current transit.
     *
     * @param transit Current transit
     * @throws LoadingUnitActionException
     */
    private void setLoadingUnitOut(final @NotNull Transit transit) {

        Set<eu.reply.lea.services.yard.entities.LoadingUnitResource> loadingUnitsToTake = new ArrayList<>(transit.getOutboundLoadingUnits()).size() > 0 ? transit.getOutboundLoadingUnits() :
                new ArrayList<>(transit.getInboundLoadingUnits()).size() > 0 ? transit.getInboundLoadingUnits() : new HashSet<>();

        for (LoadingUnitResource loadingUnitResource : loadingUnitsToTake) {

            this.debug("[TransitProcessor.TransitCode:[{}]].setLoadingUnitOut => We [{}] set Loading unit:[{}] has out because getAttachedVehicle():[{}] ",
                       transit.getCode(),
                       loadingUnitResource.getAttachedVehicle() != null ? "WILL" : "WON'T",
                       loadingUnitResource.getAttachedVehicle() != null ? "IS NULL" : "IS NOT NULL");

            if (loadingUnitResource.getAttachedVehicle() != null) {
                this.loadingUnitResourceHandler.forceOut((eu.reply.lea.services.yard.entities.LoadingUnitResource) loadingUnitResource);
            }
        }
    }
    //endregion

    //region Loading Unit Management


}

---------- End of ./boundary/TransitProcessor.java ----------

---------- Start of ./boundary/transitcreation/TransitCreationCommandObserver.java ----------
package eu.reply.lea.services.yard.boundary.transitcreation;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

import eu.reply.lea.services.masterdata.client.InvalidResultException;
import eu.reply.sce.backend.core.event.ModuleEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.log.Logged;


@Observer
@Logged
@ApplicationScoped
public class TransitCreationCommandObserver {

    @Inject
    private TransitCreationCommandAdapter transitCreationCommandAdapter;


    public void dispatcher(
        @Observes @ModuleEvent("appointmentTransitCreationCommand")
        final TransitCreationCommandInfo transitCreationCommandInfo) {
        try {
            Long transitId = transitCreationCommandAdapter.processTransitCreation(transitCreationCommandInfo);
            transitCreationCommandAdapter.processScheduledActivities(transitId, transitCreationCommandInfo);
            transitCreationCommandAdapter.processTrailers(transitId, transitCreationCommandInfo);
        } catch (InvalidResultException e) { //Some necessary query didn't find the expected results
            throw new IllegalStateException(e.getMessage(), e.getCause());
        }

    }


}

---------- End of ./boundary/transitcreation/TransitCreationCommandObserver.java ----------

---------- Start of ./boundary/transitcreation/TransitCreationCommandInfo.java ----------
package eu.reply.lea.services.yard.boundary.transitcreation;

import java.util.Calendar;
import java.util.List;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TransitCreationCommandInfo {

    private String appointmentCode;
    private String siteCode;
    private String carrierCode;
    private String carrierCompanyCode;
    private String driverLicence;
    private String driverName;
    private String numberPlate;
    private String numberPlateTrailer;

    private Calendar appointmentStartTime;
    private List<ConfirmedActivityInfo>  confirmedActivities;

    @Getter
    @Setter
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public static class ConfirmedActivityInfo {
        private String dockActivityType;
        private Calendar elapsedFrom;
        private Calendar elapsedTo;
        private String dockCode;
    }


}

---------- End of ./boundary/transitcreation/TransitCreationCommandInfo.java ----------

---------- Start of ./boundary/transitcreation/TransitCreationCommandAdapter.java ----------
package eu.reply.lea.services.yard.boundary.transitcreation;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import com.neovisionaries.i18n.CountryCode;

import eu.reply.lea.services.common.embedded.DrivingLicence;
import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.InvalidResultException;
import eu.reply.lea.services.masterdata.model.carrier.Carrier;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.model.map.Site;
import eu.reply.lea.services.masterdata.reference.CarrierReference;
import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.yard.application.TransitApplicationService;
import eu.reply.lea.services.yard.entities.ScheduledActivityDTO;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exception.TransitAlreadyPresentException;
import eu.reply.lea.services.yard.model.HandlingRequest;
import eu.reply.sce.backend.core.jee.log.Logged;


/**
 * Adapter class for processing transit creation commands.
 * This class serves as a bridge between the transit application service and masterdata services,
 * facilitating the creation and management of transit-related entities such as drivers, trucks, and trailers.
 * It also handles the association of scheduled activities with transits.
 */
@Logged
@ApplicationScoped
public class TransitCreationCommandAdapter {

    @Inject
    private TransitApplicationService transitApplicationService;

    @Inject
    private DefaultMasterdataService masterdataService;


    /**
     * Processes the creation of a transit.
     * It involves creating or validating the truck and driver based on the provided licence plates and driving licence.
     * If the transit already exists, the existing transit ID is returned instead of creating a new one.
     *
     * @param transitCreationCommandInfo Information needed for creating a transit, including site code, carrier details, and vehicle information.
     * @return The ID of the created or existing transit.
     */
    Long processTransitCreation(TransitCreationCommandInfo transitCreationCommandInfo) {
        LicencePlate truckLicencePlate = null;
        DrivingLicence drivingLicence = null;
        Site site = masterdataService.getSite(transitCreationCommandInfo.getSiteCode());

        Carrier carrier = masterdataService.getCarrier(transitCreationCommandInfo.getCarrierCode(),
                                                       transitCreationCommandInfo.getCarrierCompanyCode());
        CarrierReference carrierReference = new CarrierReference(carrier);

        if (transitCreationCommandInfo.getNumberPlate() != null) {
            truckLicencePlate = new LicencePlate(transitCreationCommandInfo.getNumberPlate(),
                                                 CountryCode.IT);
            masterdataService.createTruckIfNotPresent(truckLicencePlate, carrierReference);
        }

        if (transitCreationCommandInfo.getDriverLicence() != null) {
            drivingLicence = new DrivingLicence(transitCreationCommandInfo.getDriverLicence(),
                                                CountryCode.IT);
            masterdataService.createDriverIfNotPresent(drivingLicence, transitCreationCommandInfo.getDriverName() == null ?
                                                                       "-" : transitCreationCommandInfo.getDriverName(),
                                                       "-", carrierReference);
        }

        try {
            Transit transit = transitApplicationService.createTransit(transitCreationCommandInfo.getAppointmentCode(),
                                                                      transitCreationCommandInfo.getAppointmentCode(),
                                                                      truckLicencePlate,
                                                                      drivingLicence,
                                                                      new SiteReference(site),
                                                                      carrierReference,
                                                                      transitCreationCommandInfo.getAppointmentStartTime(),
                                                                      null
                                                                      );
            return transit.getId();
        } catch (TransitAlreadyPresentException e) {
            return e.getTransitId();
        }
    }

    /**
     * Processes the trailers associated with a transit.
     * It registers a new trailer if it does not exist and associates it with the given transit.
     *
     * @param transitId The ID of the transit to which the trailer(s) are to be associated.
     * @param transitCreationCommandInfo Information about the trailers to be processed.
     */
    void processTrailers(Long transitId, TransitCreationCommandInfo transitCreationCommandInfo) {
        if (transitCreationCommandInfo.getNumberPlateTrailer() != null) {
            LicencePlate trailerLicencePlate = new LicencePlate(transitCreationCommandInfo.getNumberPlateTrailer(),
                                                                CountryCode.IT);
            masterdataService.createTrailerIfNotPresent(trailerLicencePlate);
            transitApplicationService.addExpectedTrailers(transitId, Collections.singleton(trailerLicencePlate));
        }
    }

    /**
     * Processes scheduled activities for a transit.
     * It converts the confirmed activity information into scheduled activities DTOs and associates them with the given transit.
     *
     * @param transitId The ID of the transit for which activities are scheduled.
     * @param transitCreationCommandInfo Information about the confirmed activities to be processed.
     */
    void processScheduledActivities(Long transitId, TransitCreationCommandInfo transitCreationCommandInfo) {
        Site site = masterdataService.getSite(transitCreationCommandInfo.getSiteCode());

        Set<ScheduledActivityDTO> scheduledActivitiesDTO =
            convertActivityInfo(transitCreationCommandInfo.getConfirmedActivities(), new SiteReference(site));

        transitApplicationService.addScheduledActivities(transitId, scheduledActivitiesDTO);
    }

    /**
     * Converts a list of confirmed activity information into a set of ScheduledActivityDTO.
     * This method specifically focuses on referencing docks, which involves querying and validating dock information
     * from the masterdata service. Each confirmed activity is processed to create a corresponding DTO with accurate
     * dock references, ensuring alignment with the site-specific context provided.
     *
     * @param confirmedActivitiesInfo A list of confirmed activities, each containing details such as dock code and activity type.
     * @param siteReference A reference to the site associated with these activities, used for contextual validation and lookup in the masterdata service.
     * @return A set of ScheduledActivityDTO, each representing a confirmed activity, complete with validated dock references.
     * @throws IllegalStateException Thrown when the masterdata service returns invalid or inconsistent data for the specified docks.
     */
    private Set<ScheduledActivityDTO> convertActivityInfo(
        List<TransitCreationCommandInfo.ConfirmedActivityInfo> confirmedActivitiesInfo, SiteReference siteReference) {
        try {
            Set<ScheduledActivityDTO> scheduledActivityDTO = new HashSet<>();

            for (TransitCreationCommandInfo.ConfirmedActivityInfo confirmedActivityInfo : confirmedActivitiesInfo) {
                Dock currentDock = masterdataService.getDockByCodeAndSite(confirmedActivityInfo.getDockCode(), siteReference);
                DockReference dockReference = new DockReference(currentDock);
                scheduledActivityDTO.add(
                    new ScheduledActivityDTO(HandlingRequest.Type.valueOf(confirmedActivityInfo.getDockActivityType()),
                                             dockReference));
            }
            return scheduledActivityDTO;
        } catch (InvalidResultException e) {
            throw new IllegalStateException(e.getMessage(), e.getCause());
        }
    }
}

---------- End of ./boundary/transitcreation/TransitCreationCommandAdapter.java ----------

---------- Start of ./boundary/AbstractExpectedLoadingUnitProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundWeightAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundWeightAction;
import eu.reply.lea.services.yard.entities.ExpectedLoadingUnit;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitCreatedEvent;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitDeletedEvent;
import eu.reply.lea.services.yard.events.ExpectedLoadingUnitUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.ExpectedLoadingUnitActionException;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@EntityProcessor(entityClass = ExpectedLoadingUnit.class)
public abstract class AbstractExpectedLoadingUnitProcessor<T extends ExpectedLoadingUnit> extends AbstractProcessor<ExpectedLoadingUnitCreatedEvent, ExpectedLoadingUnitDeletedEvent, ExpectedLoadingUnitUpdatedEvent> {


    public void persisting(final T entity) throws ExpectedLoadingUnitActionException {
        entity.checkCanBeModified();
    }

    public void persisted(final T entity) {
        super.fireCreated(new ExpectedLoadingUnitCreatedEvent(entity));
    }

    public void merging(final T entity) throws ExpectedLoadingUnitActionException {
        entity.checkCanBeModified();
    }

    public void merged(final T entity) {
        super.fireUpdated(new ExpectedLoadingUnitUpdatedEvent(entity));
    }

    public void removing(final T entity) throws ExpectedLoadingUnitActionException {
        entity.checkCanBeModified();
    }

    public void removed(final T entity) {
        super.fireDeleted(new ExpectedLoadingUnitDeletedEvent(entity));
    }



    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public T action(final T expectedLoadingUnit,
                                      final ExpectedLoadingUnitRegisterInboundWeightAction action) throws ExpectedLoadingUnitActionException {
        expectedLoadingUnit.registerInboundWeight(action.getWeight());
        return expectedLoadingUnit;
    }

    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public T action(final T expectedLoadingUnit,
                                      final ExpectedLoadingUnitRegisterOutboundWeightAction action) throws ExpectedLoadingUnitActionException {
        expectedLoadingUnit.registerOutboundWeight(action.getWeight());
        return expectedLoadingUnit;
    }

    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public T action(final T expectedLoadingUnit,
                                      final ExpectedLoadingUnitRegisterInboundSealAction action) throws ExpectedLoadingUnitActionException {
        expectedLoadingUnit.registerInboundSeal(action.getSeal());
        return expectedLoadingUnit;
    }

    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public T action(final T expectedLoadingUnit,
                                      final ExpectedLoadingUnitRegisterOutboundSealAction action) throws ExpectedLoadingUnitActionException {
        expectedLoadingUnit.registerOutboundSeal(action.getSeal());
        return expectedLoadingUnit;
    }

}

---------- End of ./boundary/AbstractExpectedLoadingUnitProcessor.java ----------

---------- Start of ./boundary/ExpectedTrailerProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterInboundWeightAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundSealAction;
import eu.reply.lea.services.yard.actions.expectedLoadingUnit.ExpectedLoadingUnitRegisterOutboundWeightAction;
import eu.reply.lea.services.yard.entities.ExpectedTrailer;
import eu.reply.lea.services.yard.exceptions.ExpectedLoadingUnitActionException;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = ExpectedTrailer.class)
public class ExpectedTrailerProcessor extends AbstractExpectedLoadingUnitProcessor<ExpectedTrailer> {

    @Override
    public void persisting(final ExpectedTrailer entity) throws ExpectedLoadingUnitActionException {
        super.persisting(entity);
    }

    @Override
    public void persisted(final ExpectedTrailer entity) {
        super.persisted(entity);
    }

    @Override
    public void merging(final ExpectedTrailer entity) throws ExpectedLoadingUnitActionException {
        super.merging(entity);
    }

    @Override
    public void merged(final ExpectedTrailer entity) {
        super.merged(entity);
    }

    @Override
    public void removing(final ExpectedTrailer entity) throws ExpectedLoadingUnitActionException {
        super.removing(entity);
    }

    @Override
    public void removed(final ExpectedTrailer entity) {
        super.removed(entity);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedTrailer action(final ExpectedTrailer expectedLoadingUnit,
                                  final ExpectedLoadingUnitRegisterInboundWeightAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedTrailer action(final ExpectedTrailer expectedLoadingUnit,
                                  final ExpectedLoadingUnitRegisterOutboundWeightAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedTrailer action(final ExpectedTrailer expectedLoadingUnit,
                                  final ExpectedLoadingUnitRegisterInboundSealAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }

    @Override
    @Condition({ @Condition.Attribute(name = "transit.status", values = { "WAITING" }) })
    public ExpectedTrailer action(final ExpectedTrailer expectedLoadingUnit,
                                  final ExpectedLoadingUnitRegisterOutboundSealAction action) throws ExpectedLoadingUnitActionException {
        return super.action(expectedLoadingUnit, action);
    }
}


---------- End of ./boundary/ExpectedTrailerProcessor.java ----------

---------- Start of ./boundary/TransitMovementProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.yard.entities.TransitMovement;
import eu.reply.lea.services.yard.events.TransitMovementCreatedEvent;
import eu.reply.lea.services.yard.events.TransitMovementDeletedEvent;
import eu.reply.lea.services.yard.events.TransitMovementUpdatedEvent;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = TransitMovement.class)
public class TransitMovementProcessor
    extends AbstractProcessor<TransitMovementCreatedEvent, TransitMovementDeletedEvent, TransitMovementUpdatedEvent> {


    public void persisting(final TransitMovement entity) {
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(this.generateCode(TransitMovement.class, null));
        }
    }


    public void persisted(final TransitMovement entity) {
        super.fireCreated(new TransitMovementCreatedEvent(entity));
    }

    public void merging(final TransitMovement entity) {
    }

    public void merged(final TransitMovement entity) {
        super.fireUpdated(new TransitMovementUpdatedEvent(entity));
    }

    public void removed(final TransitMovement entity) {
        super.fireDeleted(new TransitMovementDeletedEvent(entity));
    }


}

---------- End of ./boundary/TransitMovementProcessor.java ----------

---------- Start of ./boundary/AbstractProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.slf4j.Logger;

import eu.reply.sce.backend.core.entity.IdentifiableEntity;
import eu.reply.sce.backend.core.event.ConfigurableEvent;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration.Module;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeyGenerator;
import lombok.AccessLevel;
import lombok.Getter;

@Getter(value = AccessLevel.PROTECTED)
public abstract class AbstractProcessor<C extends ConfigurableEvent<?>, D extends ConfigurableEvent<?>, U extends ConfigurableEvent<?>> {

    //region Injected Fields

    //region Logger
    @Inject
    private Logger log;

    //region Logger Methods

    /**
     * The aim of this method is to use the debug method
     * to log debug information.
     *
     * @param message Message to be logged
     * @param params  Params used to construct log message.
     */
    protected void debug(String message, Object... params) {
        if (this.log != null) {
            this.log.debug(message, params);
        }
    }


    /**
     * The aim of this method is to use the error method
     * to log error information.
     *
     * @param message Message to be logged
     * @param params  Params used to construct log message.
     */
    protected void error(String message, Object... params) {
        if (this.log != null) {
            this.log.error(message, params);
        }
    }

    //endregion

    //endregion

    //endregion

    @Inject
    @Module(Module.CURRENT)
    private EntityManager em;

    @Inject
    @Getter(value = AccessLevel.NONE)
    private BusinessKeyGenerator businessKeyGenerator;

    @Inject
    private Producer<C> createdEvent;

    @Inject
    private Producer<D> deletedEvent;

    @Inject
    private Producer<U> updatedEvent;

    protected void fireCreated(final C event) {
        this.createdEvent.fire(event);
    }

    protected void fireUpdated(final U event) {
        this.updatedEvent.fire(event);
    }

    protected void fireDeleted(final D event) {
        this.deletedEvent.fire(event);
    }

    protected <E> String generateCode(final Class<E> entityClass, final E payload) {
        return this.businessKeyGenerator.generateCode(entityClass, payload);
    }

}

---------- End of ./boundary/AbstractProcessor.java ----------

---------- Start of ./boundary/rest/YardPublisher.java ----------
package eu.reply.lea.services.yard.boundary.rest;

import static eu.reply.lea.services.yard.ModuleConfiguration.MODULE_NAME;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import eu.reply.sce.backend.core.jee.jaxrs.AttachmentPublisher;
import eu.reply.sce.backend.core.jee.jaxrs.EntityPublisher;
import eu.reply.sce.backend.core.jee.log.Logged;
import eu.reply.sce.backend.core.jee.log.NotLogged;
import eu.reply.sce.backend.core.sequence.SequenceHandler;

@Logged
@ApplicationScoped
@Transactional(Transactional.TxType.REQUIRED)
@Path(MODULE_NAME)
@Consumes(MediaType.APPLICATION_JSON)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class YardPublisher extends EntityPublisher {

    @Inject
    private SequenceHandler sequenceHandler;

    @Inject
    private AttachmentPublisher attachmentPublisher;

    @POST
    @Path("/initBusinessKeySequences")
    public void initBusinessKeySequences() {
        sequenceHandler.initBusinessKeySequences();
    }

    //This is necessary to handle attachment in the YMS
    @Path("Attachment")
    @NotLogged
    public AttachmentPublisher getAttachmentPublisher() {
        return attachmentPublisher;
    }
}

---------- End of ./boundary/rest/YardPublisher.java ----------

---------- Start of ./boundary/LoadingUnitResourceProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.inject.Inject;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.yard.actions.loadingUnit.*;
import eu.reply.lea.services.yard.application.LoadingUnitMovementApplicationService;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.events.LoadingUnitResourceCreatedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitResourceDeletedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitResourceUpdatedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.*;
import eu.reply.lea.services.yard.events.trailer.TrailerResourceParkedEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.vehicles.SwitcherProviderProxy;
import eu.reply.lea.services.yard.vehicles.TruckProviderProxy;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.configuration.Condition.Attribute;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityReferenceHandler;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.jee.log.Logged;
import lombok.Getter;
import lombok.Setter;

import java.io.InvalidClassException;

@Logged
@Getter
@Setter
public abstract class LoadingUnitResourceProcessor<T extends LoadingUnitResource, A extends LoadingUnitResourceCreatedEvent, B extends LoadingUnitResourceDeletedEvent, C extends LoadingUnitResourceUpdatedEvent> extends AbstractProcessor<A, B, C> {

    //region Inject Fields
    @Inject
    private Producer<LoadingUnitOutEvent> outEventProducer;

    @Inject
    private Producer<LoadingUnitReleasedEvent> releasedEventProducer;

    @Inject
    private LoadingUnitResourceHandler loadingUnitResourceHandler;

    @Inject
    private Producer<LoadingUnitSealRegisteredEvent> loadingUnitSealRegisteredEventProducer;

    @Inject
    private EntityReferenceHandler entityReferenceHandler;

    @Inject
    private Producer<LoadingUnitDropOffPerformedEvent> loadingUnitDropOffPerformedEvent;

    @Inject
    private Producer<LoadingUnitPickupPerformedEvent> loadingUnitPickupPerformedEvent;

    @Inject
    private Producer<TrailerResourceParkedEvent> parkedEventProducer;

    @Inject
    private Producer<LoadingUnitUndockedEvent> undockedEventProducer;

    @Inject
    private Producer<LoadingUnitHookedEvent> hookedEventProducer;

    @Inject
    private Producer<LoadingUnitInboundExpectedWeightChangedEvent> loadingUnitInboundExpectedWeightChangedEventProducer;
    @Inject
    private Producer<LoadingUnitOutboundExpectedWeightChangedEvent> loadingUnitOutboundExpectedWeightChangedEventProducer;
    @Inject
    private Producer<LoadingUnitInboundExpectedSealChangedEvent> loadingUnitInboundExpectedSealChangedEventProducer;
    @Inject
    private Producer<LoadingUnitOutboundExpectedSealChangedEvent> loadingUnitOutboundExpectedSealChangedEventChangedEventProducer;
    @Inject
    private SwitcherProviderProxy switcherProviderProxy;

    @Inject
    private LoadingUnitMovementApplicationService loadingUnitMovementApplicationService;

    @Inject
    private TruckProviderProxy truckProviderProxy;

    public T action(final T loadingUnit, final RegisterInboundWeightAction registerInboundWeightAction) {
        loadingUnit.registerInboundWeight(registerInboundWeightAction.getWeight());
        return loadingUnit;
    }

    public T action(final T loadingUnit, final RegisterOutboundWeightAction registerOutboundWeightAction) {
        loadingUnit.registerOutboundWeight(registerOutboundWeightAction.getWeight());
        return loadingUnit;
    }

    public T action(final T loadingUnit, final RegisterInboundExpectedWeightAction registerInboundExpectedWeightAction) {
        loadingUnit.registerInboundExpectedWeight(registerInboundExpectedWeightAction.getWeight(), loadingUnitInboundExpectedWeightChangedEventProducer);
        return loadingUnit;
    }

    public T action(final T loadingUnit, final RegisterOutboundExpectedWeightAction registerOutboundExpectedWeightAction) {
        loadingUnit.registerOutboundExpectedWeight(registerOutboundExpectedWeightAction.getWeight(), loadingUnitOutboundExpectedWeightChangedEventProducer);
        return loadingUnit;
    }

    ///
    public T action(final T loadingUnit, final RegisterInboundSealAction registerInboundSealAction) {
        loadingUnit.registerInboundSeal(registerInboundSealAction.getSeal(),registerInboundSealAction.getSealStatus());
        return loadingUnit;
    }

    public T action(final T loadingUnit, final RegisterOutboundSealAction registerOutboundSealAction) {
        loadingUnit.registerOutboundSeal(registerOutboundSealAction.getSeal());
        return loadingUnit;
    }

    public T action(final T loadingUnit, final RegisterInboundExpectedSealAction registerInboundExpectedSealAction) {
        loadingUnit.registerInboundExpectedSeal(registerInboundExpectedSealAction.getSeal(),loadingUnitInboundExpectedSealChangedEventProducer);
        return loadingUnit;
    }

    public T action(final T loadingUnit,final RegisterOutboundExpectedSealAction registerOutboundExpectedSealAction) {
        loadingUnit.registerOutboundExpectedSeal(registerOutboundExpectedSealAction.getSeal(), loadingUnitOutboundExpectedSealChangedEventChangedEventProducer);
        return loadingUnit;
    }

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"MOVING"}),
            @Attribute(name = "inboundTransit.status", values = {"IN"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.status", values = {"IN"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    public <D extends DockingAction> T action(@NotNull final T loadingUnit,
                                                       @NotNull final D dockingAction) throws LoadingUnitActionException{
        return this.getLoadingUnitResourceHandler().docking(loadingUnit, dockingAction);
    }

    //endregion Docking Action

    //region out Management

    /**
     * Change the status to OUT
     *
     * @param
     * @throws LoadingUnitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"MOVING"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    public T out(final T loadingUnitParam) throws LoadingUnitActionException{
        T loadingUnitLocal = this.getLoadingUnitResourceHandler().out(loadingUnitParam);
        this.getOutEventProducer().fire(new LoadingUnitOutEvent(loadingUnitLocal));
        return loadingUnitLocal;
    }
    //endregion out Management

    //region moving Management
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"IN_PLACE", "PARKED"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "attachedVehicle", values = {"<> null"})})
    //@formatter:on
    public <D extends MovingAction> T action(@NotNull final T loadingUnit,
                                                      @NotNull final D loadingUnitMovingAction) throws LoadingUnitActionException{
        this.loadingUnitMovementApplicationService.createNewMovement(new LoadingUnitReference(loadingUnit),
                                                           loadingUnitMovingAction.getNextLocation());
        return loadingUnit;

    }
    //endregion moving Management

    public T action(final T loadingUnit,
                    @NotNull final PickupAction pickupAction) throws LoadingUnitActionException,
        EntityNotFoundException, MasterdataServiceException {

        HookTruckAction action =
            new HookTruckAction(entityReferenceHandler.getEntity(pickupAction.getTransitReference(), Transit.class).getTruck());

        loadingUnitResourceHandler.hookLoadingUnit(loadingUnit, action, truckProviderProxy);

        loadingUnitPickupPerformedEvent.fire(new LoadingUnitPickupPerformedEvent(loadingUnit));

        return loadingUnit;
    }

    public T performDropOff( final T loadingUnit) throws LoadingUnitActionException {

        loadingUnitResourceHandler.release(loadingUnit);
        loadingUnitDropOffPerformedEvent.fire(new LoadingUnitDropOffPerformedEvent(loadingUnit));

        return loadingUnit;
    }
    //region parked Management

    /**
     * Change the status to PARKED
     *
     * @throws LoadingUnitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"MOVING"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    public <A extends ParkedAction> T action(@NotNull final T loadingUnit,
                                                      @NotNull final A loadingUnitParkedAction) throws LoadingUnitActionException{
        this.loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(loadingUnit), loadingUnitParkedAction.getLastLocation());
        return loadingUnit;
    }
    //endregion parked Management

    //region inPlace Management

    /**
     * Change the status to IN_PLACE
     *
     * @throws LoadingUnitActionException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"MOVING", "IN_PLACE"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    public <A extends InPlaceAction> T action(@NotNull final T loadingUnit,
                                                       @NotNull final A loadingUnitInPlaceAction)
            throws LoadingUnitActionException{
        this.loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(loadingUnit), loadingUnitInPlaceAction.getLastLocation());
        return loadingUnit;
    }

    //endregion inPlace Management

    //region release Management

    /**
     * Release the container
     *
     * @param
     * @throws LoadingUnitActionException
     * @throws MasterdataServiceException
     */
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"IN_PLACE", "PARKED"}),
            @Attribute(name = "attachedVehicle", values = {"<> null"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"}),
            @Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    public T release(final T loadingUnitParam) throws LoadingUnitActionException, MasterdataServiceException{
        T loadingUnitLocal = this.getLoadingUnitResourceHandler().release(loadingUnitParam);
        this.getReleasedEventProducer().fire(new LoadingUnitReleasedEvent(loadingUnitLocal));
        return loadingUnitLocal;
    }

    //endregion release Management

    //region undocking Management
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"IN_PLACE"}),
            @Attribute(name = "lastLocation", values = {"<> null"}),
            @Attribute(name = "inboundTransit.status", values = {"IN", "COMPLETED"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.status", values = {"IN", "COMPLETED"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    public T undocking(final T loadingUnitParam) throws LoadingUnitActionException{
        T loadingUnitLocal = this.getLoadingUnitResourceHandler().undocking(loadingUnitParam);
        this.getUndockedEventProducer().fire(new LoadingUnitUndockedEvent(loadingUnitLocal));
        return loadingUnitLocal;
    }
    //endregion undocking Management

    //endregion Movements Actions

    //region HookTruckAction Management


    @Condition({
            //@formatter:off
            @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
            @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Condition.Attribute(name = "outboundTransit.locked", values = {"false"}),
            @Condition.Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    public <D extends HookTruckAction> T action(@NotNull final T loadingUnit,
                                                         @NotNull final D loadingUnitHookTruckAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException{
        VehicleReference previousVehicle = loadingUnit.getAttachedVehicle();
        this.getLoadingUnitResourceHandler().hookLoadingUnit(loadingUnit, loadingUnitHookTruckAction, this.getTruckProviderProxy());
        this.getHookedEventProducer()
            .fire(new LoadingUnitHookedEvent(loadingUnit, loadingUnit.getAttachedVehicle(), previousVehicle));
        return loadingUnit;
    }
    //endregion HookTruckAction Management

    //region HookSwitcherAction Management

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
            @Attribute(name = "inboundTransit.locked", values = {"false"}),
            @Attribute(name = "outboundTransit.locked", values = {"false"}),
            @Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    public <D extends HookSwitcherAction> T action(@NotNull final T loadingUnit,
                                                            @NotNull final D loadingUnitHookSwitcherAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException{
        VehicleReference previousVehicle = loadingUnit.getAttachedVehicle();
        this.getLoadingUnitResourceHandler().hookLoadingUnit(loadingUnit, loadingUnitHookSwitcherAction, this.getSwitcherProviderProxy());
        this.getHookedEventProducer()
            .fire(new LoadingUnitHookedEvent(loadingUnit, loadingUnit.getAttachedVehicle(), previousVehicle));
        return loadingUnit;
    }
    //endregion HookSwitcherAction Management



    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
            @Attribute(name = "lastLocation", values = {"<> null"}),
            @Attribute(name = "attachedVehicle", values = {"null"})
            //@formatter:on
    })
    public <D extends CreateActivityAction> T action(@NotNull final T loadingUnit,
                                                              @NotNull final D createActivityAction) throws LoadingUnitActionException{
        return this.getLoadingUnitResourceHandler().createActivity(loadingUnit, createActivityAction.getActivityType());
    }


    //region VerifyWeightAction Management

    //endregion VerifyWeightAction Management

    //region Send Management

    //region SendToDockAction Management

    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"PARKED"}),
            @Attribute(name = "lastLocation", values = {"<> null"}),
            @Attribute(name = "attachedVehicle", values = {"null"})
            //@formatter:on
    })
    public <D extends SendToDockAction> T action(@NotNull final T loadingUnit,
                                                          @NotNull final D loadingUnitSendToDockAction)
        throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException{
        return this.getLoadingUnitResourceHandler().sendToDock(loadingUnit, loadingUnitSendToDockAction.getLocationReference(), loadingUnitSendToDockAction.getHandlingRequestType());
    }

    //endregion SendToDockAction Management

    //region SendToZoneAction Management
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
            @Attribute(name = "lastLocation", values = {"<> null"}),
            @Attribute(name = "attachedVehicle", values = {"null"})
            //@formatter:on
    })
    public <D extends SendToZoneAction> T action(@NotNull final T loadingUnit,
                                                          @NotNull final D sendToZoneAction) throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException{
        return this.getLoadingUnitResourceHandler().sendToZone(loadingUnit, sendToZoneAction.getLocationReference());
    }

    //endregion SendToZoneAction Management

    //region SendToYardAction Management
    @Condition({
            //@formatter:off
            @Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
            @Attribute(name = "lastLocation", values = {"<> null"}),
            @Attribute(name = "attachedVehicle", values = {"null"})
            //@formatter:on
    })
    public <D extends SendToYardAction> T action(@NotNull final T loadingUnit,
                                                          @NotNull final D sendToYardAction){
        return this.getLoadingUnitResourceHandler().sendToYard(loadingUnit, sendToYardAction.getLocationReference());
    }

    //endregion SendToYardAction Management


    //endregion Send Management

    //endregion Actions
}

---------- End of ./boundary/LoadingUnitResourceProcessor.java ----------

---------- Start of ./boundary/LoadingUnitResourceHandler.java ----------
package eu.reply.lea.services.yard.boundary;

import java.io.InvalidClassException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.yard.actions.loadingUnit.*;
import eu.reply.lea.services.yard.application.LoadingUnitMovementApplicationService;
import eu.reply.lea.services.yard.entities.*;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitChangedStatusEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitInPlaceEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitDetachedFromTransitEvent;
import eu.reply.lea.services.yard.events.movement.MovementStatusChangedEvent;
import eu.reply.lea.services.yard.model.CreateMissionRequest;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.jee.log.Logged;
import org.apache.commons.collections4.ListUtils;

import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.model.map.Zone;
import eu.reply.lea.services.masterdata.model.vehicle.Vehicle;
import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.masterdata.reference.ZoneReference;
import eu.reply.lea.services.yard.actions.loadingUnitActivity.LoadingUnitActivityConfirmAction;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitHookedEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActivityActionException;
import eu.reply.lea.services.yard.model.LoadingUnitActivity.Status;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacher;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacherProxy;
import eu.reply.lea.services.yard.model.vehicle.Switcher;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.event.Producer;
import lombok.Getter;
import org.slf4j.Logger;

import static eu.reply.lea.services.yard.exceptions.LoadingUnitActionException.Codes.LOAD_STATUS_NOT_VALID;

@Getter
@ApplicationScoped
@Logged
public class LoadingUnitResourceHandler {

    //region Inject Fields
    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Inject
    private ConfigurableEventProducer<LoadingUnitChangedStatusEvent> loadingUnitChangedStatusEventProducer;

    @Inject
    protected DefaultMasterdataService masterdataService;

    @Inject
    private LoadingUnitActivityProcessor loadingUnitActivityProcessor;

    @Inject
    private ConfigurableEventProducer<LoadingUnitDetachedFromTransitEvent> loadingUnitDetachedFromTransitProducer;

    @Inject
    private LoadingUnitMovementApplicationService loadingUnitMovementApplicationService;

    //region Logging

    //region Inject Fields
    @Inject
    protected Logger logger;
    //endregion


    //endregion

    //endregion

    /**
     * Checks if the loading unit is moving
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> void checkLoadingUnitIsMoving(final T loadingUnit) throws LoadingUnitActionException {
        if (!eu.reply.lea.services.yard.entities.LoadingUnitResource.Status.MOVING.equals(loadingUnit.getStatus())) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.STATUS_NOT_VALID, loadingUnit.getCode());
        }
    }

    /**
     * Checks if the loading unit is in place
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> void checkLoadingUnitIsInPlace(final T loadingUnit) throws LoadingUnitActionException {
        if (!eu.reply.lea.services.yard.entities.LoadingUnitResource.Status.IN_PLACE.equals(loadingUnit.getStatus())) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.STATUS_NOT_VALID, loadingUnit.getCode());
        }
    }

    /**
     * Checks if the loading unit can be released
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     * @throws MasterdataServiceException
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> void checkLoadingUnitCanBeReleased(final T loadingUnit) throws LoadingUnitActionException, MasterdataServiceException {
        if (!eu.reply.lea.services.yard.entities.LoadingUnitResource.Status.isInNotMoving(loadingUnit.getStatus())) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.STATUS_NOT_VALID, loadingUnit.getCode());
        }
        if (!loadingUnit.isDroppable()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_NOT_DETACHABLE, loadingUnit.getCode());
        }
        if (loadingUnit.getAttachedVehicle() == null) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_NOT_HOOKED, loadingUnit.getCode());
        }
    }

    /**
     * Checks if the loading unit can be hooked
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> void checkLoadingUnitCanBeHooked(final T loadingUnit) throws LoadingUnitActionException {
        if (!eu.reply.lea.services.yard.entities.LoadingUnitResource.Status.isInNotMoving(loadingUnit.getStatus())) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.STATUS_NOT_VALID, loadingUnit.getCode());
        }
        if (!loadingUnit.isDroppable()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.UNIT_NOT_ATTACHABLE, loadingUnit.getCode());
        }
    }


    /**
     * Checks that the inbound transit is not locked
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    private <T extends LoadingUnitResource> void checkInboundTransitIsNotLocked(final T loadingUnit) throws LoadingUnitActionException {
        if (loadingUnit.getInboundTransit() != null && loadingUnit.getInboundTransit().isLocked()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.INBOUND_TRANSIT_LOCKED, loadingUnit.getCode());
        }
    }

    /**
     * Checks that the outbound transit is not locked
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    private <T extends LoadingUnitResource> void checkOutboundTransitIsNotLocked(final T loadingUnit) throws LoadingUnitActionException {
        if (loadingUnit.getOutboundTransit() != null && loadingUnit.getOutboundTransit().isLocked()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.OUTBOUND_TRANSIT_LOCKED, loadingUnit.getCode());
        }
    }

    /**
     * Change the status to OUT
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T out(final T loadingUnit) throws LoadingUnitActionException {
        checkLoadingUnitIsInPlace(loadingUnit);
        checkInboundTransitIsNotLocked(loadingUnit);
        checkOutboundTransitIsNotLocked(loadingUnit);
        loadingUnit.out(loadingUnitChangedStatusEventProducer);
        return loadingUnit;
    }


    /**
     * This method is used when we need to force a check out of
     * a LU.
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     */
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T forceOut(final T loadingUnit){
        loadingUnit.out(loadingUnitChangedStatusEventProducer);
        return loadingUnit;
    }
    //endregion out Management

    //region release Management

    /**
     * Release the loading unit
     *
     * @param loadingUnit
     * @throws LoadingUnitActionException
     * @throws MasterdataServiceException
     */
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T release(final T loadingUnit) throws LoadingUnitActionException, MasterdataServiceException {
        checkLoadingUnitCanBeReleased(loadingUnit);
        checkInboundTransitIsNotLocked(loadingUnit);
        checkOutboundTransitIsNotLocked(loadingUnit);
        setSwitcherFree(loadingUnit);
        loadingUnit.releaseFromAttachedVehicle(loadingUnitDetachedFromTransitProducer);
        return loadingUnit;
    }

    //endregion release Management

    //region docking Management
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T docking(final T loadingUnit,
                                                                                         final DockingAction action) throws LoadingUnitActionException {

        loadingUnitMovementApplicationService.completeMovement(new LoadingUnitReference(loadingUnit), action.getDockReference());
        return loadingUnit;
    }

    //endregion undocking Management

    //region undocking Management

    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T undocking(final T loadingUnit) throws LoadingUnitActionException {
        checkLoadingUnitIsInPlace(loadingUnit);
        checkInboundTransitIsNotLocked(loadingUnit);
        checkOutboundTransitIsNotLocked(loadingUnit);
        return loadingUnit;
    }

    //endregion undocking Management

    //endregion Movements Actions

    //region HookTruckAction Management
    public void hookLoadingUnit(final eu.reply.lea.services.yard.entities.LoadingUnitResource loadingUnit, final BaseLoadingUnitHookVehicleAction action, final LoadingUnitAttacherProxy attacherProxy)
            throws LoadingUnitActionException, EntityNotFoundException, MasterdataServiceException {
        action(loadingUnit, action, attacherProxy);
    }

    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T action(final T loadingUnit, final BaseLoadingUnitHookVehicleAction action, final LoadingUnitAttacherProxy loadingUnitAttacherProxy) throws LoadingUnitActionException, EntityNotFoundException, MasterdataServiceException {

        // the new vehicle cannot be null
        if (action.isHookingVehicleDataMissing()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.HOOKING_VEHICLE_MISSING, loadingUnit.getCode());
        }
        checkLoadingUnitCanBeHooked(loadingUnit);
        checkInboundTransitIsNotLocked(loadingUnit);
        checkOutboundTransitIsNotLocked(loadingUnit);

        LoadingUnitAttacher unitAttacher = loadingUnitAttacherProxy.findAvailableAttacherInstance(action.getAttachingUnitIdentification(), action.getAttachingVehicleReference(), action.getAttachingUnitIdentification());

        // the new switcher must be available

        if (unitAttacher == null || !unitAttacher.isAvailable()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_NOT_AVAILABLE, loadingUnit.getCode());
        }
        if (!unitAttacher.canAttachUnits()) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_NOT_ATTACHABLE, loadingUnit.getCode());
        }

        // the new vehicle cannot be the same of the previous one
        if (loadingUnit.isAttachedTo(unitAttacher.getAttachingVehicle().getVehicleReference())) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_ALREADY_HOOKED, loadingUnit.getCode());
        }
        if (loadingUnit.isAttachedToAVehicle()) {
            release(loadingUnit);
        }
        try {
            unitAttacher.attachLoadingUnit(loadingUnit);
        } catch (InvalidClassException e) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.VEHICLE_NOT_AVAILABLE, loadingUnit.getCode());
        }

        return loadingUnit;
    }

    //endregion HookTruckAction Management

    //region HookSwitcherAction Management


    //endregion HookSwitcherAction Management


    /**
     * The aim of this method is to create an activity when the user decide to send
     * the loading unit inside such Dock or Zone.
     *
     * @param loadingUnit Current Loading Unit
     * @param activityType
     * @param <T>
     * @return
     * @throws LoadingUnitActionException
     */
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T createActivity(final T loadingUnit, final LoadingUnitActivity.Type activityType) throws LoadingUnitActionException {
        List<LoadingUnitActivity> activities = ListUtils.emptyIfNull(LoadingUnitActivity.findByLoadingUnit(getEm(), loadingUnit));
        if (activities.stream().anyMatch(a -> LoadingUnitActivity.Status.isActive(a.getStatus()))) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.ACTIVE_ACTIVITIES, loadingUnit.getCode());
        }
        if (activities.stream().anyMatch(a -> LoadingUnitActivity.Status.isTodo(a.getStatus()) && a.getType().equals(activityType))) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.DUPLICATED_ACTIVITY, loadingUnit.getCode());
        }
        LoadingUnitActivity activity = new LoadingUnitActivity(loadingUnit, activityType);
        getEm().persist(activity);
        return loadingUnit;
    }

    //endregion AddHandlingRequestAction Management

    //region Send Management

    //region SendToDockAction Management
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T sendToDock(final T loadingUnit, final LocationReference locationReference, eu.reply.lea.services.yard.model.HandlingRequest.Type handlingRequestType) throws MasterdataServiceException, InvalidClassException {
        eu.reply.lea.services.yard.model.LoadingUnitActivity.Type activityType;
        switch (handlingRequestType) {
            case LOAD: {
                activityType = eu.reply.lea.services.yard.model.LoadingUnitActivity.Type.LOADING;
                break;
            }
            case UNLOAD: {
                activityType = eu.reply.lea.services.yard.model.LoadingUnitActivity.Type.UNLOADING;
                break;
            }
            default:
                throw new RuntimeException(
                    String.format("loadingUnitSendToDockAction.getHandlingRequestType():[{}] is not valid!",
                                  handlingRequestType));
        }

        List<eu.reply.lea.services.yard.model.LoadingUnitActivity> activities =
            new ArrayList<>(eu.reply.lea.services.yard.entities.LoadingUnitActivity.findByLoadingUnit(this.getEm(), loadingUnit));
        eu.reply.lea.services.yard.model.LoadingUnitActivity activeActivity = activities
            .stream()
            .filter(
                a -> a.getType().equals(activityType) && eu.reply.lea.services.yard.entities.LoadingUnitActivity.Status.isActive(
                    a.getStatus()))
            .findFirst()
            .orElse(null);
        if (activeActivity == null) {
            this.createActivity(loadingUnit, activityType);
        }

        Dock location = masterdataService.get(DockReference.from(locationReference));
        ListUtils.emptyIfNull(LoadingUnitActivity.findByLoadingUnit(getEm(), loadingUnit)).stream()
                .filter(a -> Status.isTodo(a.getStatus()))
                .forEach(a -> {
                    try {
                        loadingUnitActivityProcessor.confirm(a, new LoadingUnitActivityConfirmAction(new DockReference(location)));
                    } catch (LoadingUnitActivityActionException e) {
                        throw new RuntimeException(e);
                    }
                });

        return sendTo(loadingUnit, new LocationReference(location));
    }
    //endregion SendToDockAction Management

    //region SendToZoneAction Management

    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T sendToZone(final T loadingUnit, final LocationReference locationReference) throws MasterdataServiceException, InvalidClassException {
        Zone location = masterdataService.get(ZoneReference.from(locationReference));
        return sendTo(loadingUnit, new LocationReference(location));
    }

    //endregion SendToZoneAction Management

    //region SendToYardAction Management
    public <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T sendToYard(final T loadingUnit, final LocationReference locationReference) {
        //get location from client
        //return sendTo(loadingUnit, new LocationReference(location));
        return loadingUnit;
    }
    //endregion SendToYardAction Management


    /**
     * Create a request to generate a new mission of movement
     *
     * @param loadingUnit       Loading Unit to move.
     * @param locationReference next Location to reach.
     * @param <T>               Class that extends LoadingUnit
     * @return LoadingUnit
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> T sendTo(@NotNull final T loadingUnit,
                                                                                         @NotNull final LocationReference locationReference) {

        //TODO Check the status at least
        // CreateMissionRequest resourceAlreadyPresent = eu.reply.lea.services.yard.entities.CreateMissionRequest.findSendResourceRequest(this.em,
        // loadingUnit,
        // loadingUnit.getLastLocation(),
        // locationReference);

        //if (resourceAlreadyPresent == null) {
        CreateMissionRequest createMissionRequest = new eu.reply.lea.services.yard.entities.CreateMissionRequest(loadingUnit, loadingUnit.getLastLocation(), locationReference,loadingUnit.getInboundTransit()
            .getDestinationSite());
        getEm().persist(createMissionRequest);
        //}

        return loadingUnit;
    }

    //endregion Send Management

    //endregion Actions


    /**
     * If the attached vehicle is a Switcher, set Switcher Status to FREE when unhooked
     *
     * @param <T          extends LoadingUnit>
     * @param loadingUnit
     */
    private <T extends eu.reply.lea.services.yard.entities.LoadingUnitResource> void setSwitcherFree(final T loadingUnit) {
        if (Switcher.RESOURCE_NAME.equals(loadingUnit.getAttachedVehicle().getEntityName())) {
            Vehicle v = loadingUnit.getAttachedVehicle().getEntity(em, null);
            v.detachUnit();
        }
    }

}

---------- End of ./boundary/LoadingUnitResourceHandler.java ----------

---------- Start of ./boundary/trailer/TrailerResourceProcessor.java ----------
package eu.reply.lea.services.yard.boundary.trailer;

import java.io.InvalidClassException;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.yard.actions.loadingUnit.CreateActivityAction;
import eu.reply.lea.services.yard.actions.loadingUnit.DockingAction;
import eu.reply.lea.services.yard.actions.loadingUnit.HookSwitcherAction;
import eu.reply.lea.services.yard.actions.loadingUnit.HookTruckAction;
import eu.reply.lea.services.yard.actions.loadingUnit.InPlaceAction;
import eu.reply.lea.services.yard.actions.loadingUnit.MovingAction;
import eu.reply.lea.services.yard.actions.loadingUnit.ParkedAction;
import eu.reply.lea.services.yard.actions.loadingUnit.PickupAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundExpectedSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundExpectedWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundExpectedSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundExpectedWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToDockAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToYardAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToZoneAction;
import eu.reply.lea.services.yard.boundary.LoadingUnitResourceProcessor;
import eu.reply.lea.services.yard.entities.TrailerResource;
import eu.reply.lea.services.yard.events.TrailerResourceCreatedEvent;
import eu.reply.lea.services.yard.events.TrailerResourceDeletedEvent;
import eu.reply.lea.services.yard.events.TrailerResourceUpdatedEvent;
import eu.reply.lea.services.yard.events.trailer.TrailerResourceMoveStartedEvent;
import eu.reply.lea.services.yard.events.trailer.TrailerResourceParkedEvent;
import eu.reply.lea.services.yard.events.trailer.TrailerResourceWeightRegisteredEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.vehicles.SwitcherProviderProxy;
import eu.reply.lea.services.yard.vehicles.TruckProviderProxy;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = TrailerResource.class)
public class TrailerResourceProcessor extends
    LoadingUnitResourceProcessor<TrailerResource, TrailerResourceCreatedEvent, TrailerResourceDeletedEvent, TrailerResourceUpdatedEvent> {

    @Inject
    private Producer<TrailerResourceMoveStartedEvent> trailerResourceMoveStartedEventProducer;

    //region CRUD Operation
    public void persisting(final TrailerResource trailer) {
        if (StringUtils.isBlank(trailer.getCode())) {
            trailer.setCode(trailer.getLoadingUnitRegistryReference().getBusinessKey());
        }
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit,final RegisterInboundWeightAction registerInboundWeightAction) {
        return super.action(loadingUnit, registerInboundWeightAction);
    }
    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterOutboundWeightAction registerOutboundWeightAction) {
        return super.action(loadingUnit, registerOutboundWeightAction);
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterInboundExpectedWeightAction registerInboundExpectedWeightAction) {
        return super.action(loadingUnit, registerInboundExpectedWeightAction);
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterOutboundExpectedWeightAction registerOutboundExpectedWeightAction) {
        return super.action(loadingUnit, registerOutboundExpectedWeightAction);
    }
    ///
    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterInboundSealAction registerInboundSealAction) {
        return super.action(loadingUnit, registerInboundSealAction);
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterOutboundSealAction registerOutboundSealAction) {
        return super.action(loadingUnit, registerOutboundSealAction);
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit, final RegisterInboundExpectedSealAction registerInboundExpectedSealAction) {
        return super.action(loadingUnit, registerInboundExpectedSealAction);
    }

    @Override
    public TrailerResource action(final TrailerResource loadingUnit,final RegisterOutboundExpectedSealAction registerOutboundExpectedSealAction) {
        return super.action(loadingUnit, registerOutboundExpectedSealAction);
    }

    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"MOVING", "IN_PLACE"}),
        @Condition.Attribute(name = "inboundTransit.status", values = {"IN"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "outboundTransit.status", values = {"IN"}),
        @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    @Override
    public <D extends DockingAction> TrailerResource action(final TrailerResource loadingUnit,
                                                            final D dockingAction)
        throws LoadingUnitActionException {

        return super.action(loadingUnit,dockingAction);
    }
    //endregion Docking Action Management

    //region out Management

    /**
     * Change the status to OUT
     *
     * @param
     * @throws LoadingUnitActionException
     */
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"MOVING"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    @Override
    public TrailerResource out(final TrailerResource loadingUnit)
        throws LoadingUnitActionException {
        return super.out(loadingUnit);
    }
    //endregion out Management

    //region moving Management
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"IN_PLACE", "PARKED", "MOVING"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"<> null"})})
    //@formatter:on
    @Override
    public <A extends MovingAction> TrailerResource action(TrailerResource loadingUnit, A loadingUnitMovingAction)
        throws LoadingUnitActionException {

        //TODO:  @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})
        //we need to remove this because otherwise dropoff task can be managed
        //How we can manage it?


        TrailerResource loadingUnitAfterMoving = super.action(loadingUnit, loadingUnitMovingAction);

        this.trailerResourceMoveStartedEventProducer.fire(new TrailerResourceMoveStartedEvent(loadingUnitAfterMoving));
        return loadingUnitAfterMoving;
    }
    //endregion moving Management

    @Override
    public TrailerResource action(final TrailerResource trailerResource, final PickupAction pickupAction) throws LoadingUnitActionException,
        EntityNotFoundException, MasterdataServiceException {
        return super.action(trailerResource,pickupAction);
    }

    @Override
    public TrailerResource performDropOff(final TrailerResource trailerResource) throws LoadingUnitActionException,
        MasterdataServiceException {
        return super.performDropOff(trailerResource);
    }
    //region parked Management

    /**
     * Change the status to PARKED
     *
     * @throws LoadingUnitActionException
     */
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"MOVING"})
    })
    //@formatter:on
    @Override
    public <A extends ParkedAction> TrailerResource action(TrailerResource loadingUnit, A loadingUnitParkedAction)
        throws LoadingUnitActionException {

        //TODO:  @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})
        //we need to remove this because otherwise dropoff task can be managed
        //How we can manage it?
        TrailerResource loadingUnitAfterParking = super.action(loadingUnit, loadingUnitParkedAction);

        this.getParkedEventProducer().fire(new TrailerResourceParkedEvent(loadingUnitAfterParking));
        return loadingUnitAfterParking;
    }
    //endregion parked Management

    //region inPlace Management

    /**
     * Change the status to IN_PLACE
     *
     * @throws LoadingUnitActionException
     */
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"MOVING", "IN_PLACE"}),
    })
    //@formatter:on
    @Override
    public <A extends InPlaceAction> TrailerResource action(TrailerResource loadingUnit, A loadingUnitInPlaceAction)
        throws LoadingUnitActionException {


        //TODO:  @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})
        //we need to remove this because otherwise dropoff task can be managed
        //How we can manage it?
        TrailerResource loadingUnitAfterInPlace =super.action(loadingUnit, loadingUnitInPlaceAction);

        return loadingUnitAfterInPlace;
    }

    //endregion inPlace Management

    //region release Management

    /**
     * Release the container
     *
     * @param
     * @throws LoadingUnitActionException
     * @throws MasterdataServiceException
     */
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"IN_PLACE", "PARKED"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"<> null"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    @Override
    public TrailerResource release(TrailerResource loadingUnit) throws LoadingUnitActionException, MasterdataServiceException {
        return super.release(loadingUnit);
    }
    //endregion release Management

    //region undocking Management
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"IN_PLACE"}),
        @Condition.Attribute(name = "lastLocation", values = {"<> null"}),
        @Condition.Attribute(name = "inboundTransit.status", values = {"IN", "COMPLETED"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "outboundTransit.status", values = {"IN", "COMPLETED"}),
        @Condition.Attribute(name = "outboundTransit.locked", values = {"false"})})
    //@formatter:on
    @Override
    public TrailerResource undocking(TrailerResource loadingUnit)
        throws LoadingUnitActionException {

        return super.undocking(loadingUnit);
    }
    //endregion undocking Management

    //endregion Movements Actions

    //region HookTruckAction Management

    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "outboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    @Override
    public <D extends HookTruckAction> TrailerResource action(TrailerResource loadingUnit,
                                                              D loadingUnitHookTruckAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException {

        return super.action(loadingUnit, loadingUnitHookTruckAction);
    }
    //endregion HookTruckAction Management

    //region HookSwitcherAction Management

    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "inboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "outboundTransit.locked", values = {"false"}),
        @Condition.Attribute(name = "droppable", values = {"true"})})
    //@formatter:on
    @Override
    public <D extends HookSwitcherAction> TrailerResource action(TrailerResource loadingUnit,
                                                                 D loadingUnitHookSwitcherAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException {

        return super.action(loadingUnit, loadingUnitHookSwitcherAction);
    }

    //endregion HookSwitcherAction Management

    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "lastLocation", values = {"<> null"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"null"})
        //@formatter:on
    })
    @Override
    public <D extends CreateActivityAction> TrailerResource action(final TrailerResource loadingUnit,
                                                                   final D createActivityAction)
        throws LoadingUnitActionException {

        return super.action(loadingUnit,createActivityAction);
    }


    //region Send Management

    //region SendToDockAction Management

    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "lastLocation", values = {"<> null"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"null"})
        //@formatter:on
    })
    @Override
    public <D extends SendToDockAction> TrailerResource action(final TrailerResource loadingUnit,
                                                               final D loadingUnitSendToDockAction)
        throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException {

        return super.action(loadingUnit, loadingUnitSendToDockAction);
    }

    //endregion SendToDockAction Management

    //region SendToZoneAction Management
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "lastLocation", values = {"<> null"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"null"})
        //@formatter:on
    })
    @Override
    public <D extends SendToZoneAction> TrailerResource action(final TrailerResource loadingUnit,
                                                               final D sendToZoneAction)
        throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException {
        return super.action(loadingUnit, sendToZoneAction);
    }

    //endregion SendToZoneAction Management

    //region SendToYardAction Management
    @Condition({
        //@formatter:off
        @Condition.Attribute(name = "status", values = {"PARKED", "IN_PLACE"}),
        @Condition.Attribute(name = "lastLocation", values = {"<> null"}),
        @Condition.Attribute(name = "attachedVehicle", values = {"null"})
        //@formatter:on
    })
    @Override
    public <D extends SendToYardAction> TrailerResource action(final TrailerResource loadingUnit,
                                                               final D sendToYardAction) {
        return super.action(loadingUnit, sendToYardAction);
    }

    //endregion SendToYardAction Management


    //endregion Send Management

    //endregion Actions

}

---------- End of ./boundary/trailer/TrailerResourceProcessor.java ----------

---------- Start of ./boundary/CreateMissionRequestProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import eu.reply.lea.services.yard.actions.loadingUnit.sending.CreateMissionRequestSetErrorAction;
import eu.reply.lea.services.yard.entities.CreateMissionRequest;
import eu.reply.lea.services.yard.events.loadingUnit.sending.CreateMissionRequestCreatedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.sending.CreateMissionRequestDeletedEvent;
import eu.reply.lea.services.yard.events.loadingUnit.sending.CreateMissionRequestRetryEvent;
import eu.reply.lea.services.yard.events.loadingUnit.sending.CreateMissionRequestUpdatedEvent;
import eu.reply.lea.services.yard.model.CreateMissionRequestStatus;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import java.util.Calendar;


/**
 * The aim of this class is to manage SendResourceRequest
 * operation.
 */
@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = CreateMissionRequest.class)
public class CreateMissionRequestProcessor extends AbstractProcessor<CreateMissionRequestCreatedEvent, CreateMissionRequestDeletedEvent, CreateMissionRequestUpdatedEvent> {

    //region Inject Members

    @Inject
    private ConfigurableEventProducer<CreateMissionRequestRetryEvent> retryInErrorSendResourceRequestEventProducer;

    @Inject
    private LoadingUnitResourceHandler loadingUnitResourceHandler;

    //endregion

    //region CRUD Operation

    //region INSERT Operation

    /**
     * Before persist SendResourceRequest
     * @param sendResourceRequest SendResourceRequest instance
     */
    public void persisting(final CreateMissionRequest sendResourceRequest) {
        if(!sendResourceRequest.getCreateMissionRequestStatus().equals(CreateMissionRequestStatus.NEW))
            throw new RuntimeException("Cannot create SendResourceRequest if not in NEW status!");
    }

    /**
     * After persist SendResourceRequest
     * @param sendResourceRequest SendResourceRequest instance
     */
    public void persisted(final CreateMissionRequest sendResourceRequest) {
        super.fireCreated(new CreateMissionRequestCreatedEvent(sendResourceRequest));
    }

    //endregion

    //endregion

    //region External Actions

    //region retryMissionCreation action
    /**
     * Publish an Event to retry a Mission Creation.
     * @param sendResourceRequest SendResourceRequest
     * @return SendResourceRequest
     */
    @Condition({
            //@formatter:off
            @Condition.Attribute(name = "createMissionRequestStatus", values = {"IN_ERROR", "IN_PROGRESS"})
            //@formatter:on
    })
    public CreateMissionRequest retryMissionCreation(final CreateMissionRequest sendResourceRequest) {

        this.retryInErrorSendResourceRequestEventProducer.fire(new CreateMissionRequestRetryEvent(sendResourceRequest));
        return sendResourceRequest;
    }
    //endregion

    //region setError action
    /**
     * Setting error inside SendResourceRequest instance
     * @param sendResourceRequest SendResourceRequest
     * @param createMissionRequestSetErrorAction Action
     * @return SendResourceRequest
     */
    public CreateMissionRequest action(final CreateMissionRequest sendResourceRequest,
                                       final CreateMissionRequestSetErrorAction createMissionRequestSetErrorAction) {

        sendResourceRequest.setError(createMissionRequestSetErrorAction.getErrorMessage());
        sendResourceRequest.setCreateMissionRequestStatus(CreateMissionRequestStatus.IN_ERROR);

        return sendResourceRequest;
    }
    //endregion

    //region completed action
    /**
     * Setting request with Closed status and create new
     * @param sendResourceRequest SendResourceRequest
     * @return SendResourceRequest
     */
    public CreateMissionRequest completed(final CreateMissionRequest sendResourceRequest) {
        sendResourceRequest.setCreateMissionRequestStatus(CreateMissionRequestStatus.CLOSED);
        sendResourceRequest.setCompletedDate(Calendar.getInstance());
        return sendResourceRequest;
    }
    //endregion

    //endregion
}

---------- End of ./boundary/CreateMissionRequestProcessor.java ----------

---------- Start of ./boundary/HandlingRequestProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import java.io.InvalidClassException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;

import eu.reply.lea.services.masterdata.model.map.Zone;
import eu.reply.lea.services.masterdata.pojo.map.ZonePojo;
import eu.reply.lea.services.masterdata.reference.ZoneReference;
import eu.reply.lea.services.yard.actions.request.*;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.events.request.*;
import eu.reply.lea.services.yard.exceptions.DockActionException;
import eu.reply.sce.backend.core.jee.event.Producer;
import org.apache.commons.lang3.ObjectUtils;

import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.pojo.map.DockPojo;
import eu.reply.lea.services.masterdata.reference.DockReference;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.YardUtils;
import eu.reply.lea.services.yard.entities.ExpectedContainer;
import eu.reply.lea.services.yard.entities.ExpectedLoadingUnit;
import eu.reply.lea.services.yard.entities.ExpectedTrailer;
import eu.reply.lea.services.yard.entities.HandlingRequest;
import eu.reply.lea.services.yard.entities.HandlingRequestActivity;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException.Codes;
import eu.reply.lea.services.yard.exceptions.TransitActionException;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.configuration.Condition.Attribute;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityReferenceHandler;
import eu.reply.sce.backend.core.jee.log.Logged;
import lombok.NonNull;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = HandlingRequest.class)
public class HandlingRequestProcessor extends AbstractProcessor<HandlingRequestCreatedEvent, HandlingRequestDeletedEvent, HandlingRequestUpdatedEvent> {

    // Lifecycle methods

    @Inject
    private EntityReferenceHandler entityReferenceHandler;

    @Inject
    private HandlingRequestActivityProcessor activityProcessor;

    @Inject
    private DefaultMasterdataService defaultMasterdataService;

    public void persisting(final HandlingRequest entity) throws HandlingRequestActionException, TransitActionException {
        verifyTransit(entity.getTransit());
        handlingRequestsInitialization(entity.getTransit());
    }

    public void persisted(final HandlingRequest entity) {
        super.fireCreated(new HandlingRequestCreatedEvent(entity));
    }

    public void merging(final HandlingRequest entity) throws HandlingRequestActionException {

        if (entity.getTransit() == null) {
            throw new HandlingRequestActionException(Codes.NO_TRANSIT, entity.toString());
        }

        if (!Transit.Status.WAITING.equals(entity.getTransit().getStatus())) {

            HandlingRequest old = getEm().find(HandlingRequest.class, entity.getId());

            boolean sameExpectedTrailers = old.getExpectedUnits().equals(entity.getExpectedUnits());
            boolean sameScheduledStart = Objects.equals(old.getScheduledStart(), entity.getScheduledStart());
            boolean sameScheduledEnd = Objects.equals(old.getScheduledEnd(), entity.getScheduledEnd());

            boolean sameTrailers = entity.getHandlingRequestActivities().stream().map(a -> a.getLoadingUnit()).collect(Collectors.toList())
                    .equals(old.getHandlingRequestActivities().stream().map(a -> a.getLoadingUnit()).collect(Collectors.toList()));

            if (!sameExpectedTrailers || !sameScheduledStart || !sameScheduledEnd || !sameTrailers) {
                throw new HandlingRequestActionException(Codes.TRANSIT_STATUS_NOT_VALID, entity.toString());
            }
        }
    }

    public void merged(final HandlingRequest entity) {
        super.fireUpdated(new HandlingRequestUpdatedEvent(entity));
    }

    public void removing(final HandlingRequest entity) throws HandlingRequestActionException {
        verifyTransit(entity.getTransit());

        entity.getTransit().removeHandlingRequest(entity);

        if (!entity.getTransit().getHandlingRequests().stream().anyMatch(h -> !h.getId().equals(entity.getId()))) {
            throw new HandlingRequestActionException(Codes.TRANSIT_WITHOUT_HANDLING_REQUEST, entity.toString());
        }
    }

    public void removed(final HandlingRequest entity) {
        super.fireDeleted(new HandlingRequestDeletedEvent(entity));
    }

    // Actions methods
    @Condition({@Attribute(name = "transit.status", values = {"WAITING"})})
    public HandlingRequest action(final HandlingRequest handlingRequest,
                                  final HandlingRequestAssociateExpectedTrailerAction action) throws EntityNotFoundException, HandlingRequestActionException {
        associateExpectedLoadingUnit(handlingRequest, action.getExpectedTrailer(), ExpectedTrailer.class);
        return handlingRequest;
    }

    /**
     * The aim of this action is to rollback the HR to a TODO status
     * and to set the status of the Activities to CANCELLED.
     * A new HR activity is created for each loading unit putting
     * the transit in a status in which is ready to be addressed again.
     * @param handlingRequest
     * @return handlingRequest
     */
    @Condition({@Attribute(name ="status" , values = {"ADDRESSED"})})
    public HandlingRequest rollbackToTODOStatusAndCancelActivities(final HandlingRequest handlingRequest)  {
        handlingRequest.setStatus(eu.reply.lea.services.yard.model.HandlingRequest.Status.TODO);
        //Set HR activities status to CANCELLED
        handlingRequest.getHandlingRequestActivities().forEach(item->  item.setStatus(eu.reply.lea.services.yard.model.HandlingRequest.Status.CANCELLED));
        //Create a new HR Activity for each loading unit of the HR.
        for (LoadingUnitResource loadingUnit : handlingRequest.getUnits()){
            HandlingRequestActivity handlingRequestActivity = new HandlingRequestActivity();
            handlingRequestActivity.setLoadingUnit(loadingUnit);

            getEm().persist(handlingRequestActivity);
            handlingRequest.addHandlingRequestActivity(handlingRequestActivity);
        }
        return handlingRequest;
    }


    @Condition({@Attribute(name = "transit.status", values = {"WAITING"})})
    public HandlingRequest action(final HandlingRequest handlingRequest,
                                  final HandlingRequestDisassociateExpectedTrailerAction action) throws EntityNotFoundException, HandlingRequestActionException {
        disassociateExpectedLoadingUnit(handlingRequest, action.getExpectedTrailer(), ExpectedTrailer.class);
        return handlingRequest;
    }

    @Condition({@Attribute(name = "transit.status", values = {"WAITING"})})
    public HandlingRequest action(final HandlingRequest handlingRequest,
                                  final HandlingRequestAssociateExpectedContainerAction action) throws EntityNotFoundException, HandlingRequestActionException {
        associateExpectedLoadingUnit(handlingRequest, action.getExpectedContainer(), ExpectedContainer.class);
        return handlingRequest;
    }


    @Condition({@Attribute(name = "transit.status", values = {"WAITING"})})
    public HandlingRequest action(final HandlingRequest handlingRequest,
                                  final HandlingRequestDisassociateExpectedContainerAction action) throws EntityNotFoundException, HandlingRequestActionException {

        @NonNull EntityReference expectedUnitReference = action.getExpectedContainer();
        Class<? extends ExpectedLoadingUnit> loadingUnitRefClass = ExpectedLoadingUnit.class;
        disassociateExpectedLoadingUnit(handlingRequest, expectedUnitReference, loadingUnitRefClass);

        return handlingRequest;
    }

    @Condition({@Attribute(name = "transit.status", values = {"ARRIVED"}),
            @Attribute(name = "status", values = {"TODO"})})
    public HandlingRequest action(final HandlingRequest handlingRequest, final HandlingRequestAssociateDockAction action) throws HandlingRequestActionException, MasterdataServiceException {

        LoadingUnitResource
            loadingUnit = entityReferenceHandler.getEntity(action.getLoadingUnitReference(), LoadingUnitResource.class, getEm());
        if (loadingUnit == null || !handlingRequest.getUnits().contains(loadingUnit)) {
            throw new HandlingRequestActionException(Codes.MISSING_SPECIFIC_TRAILER, handlingRequest.getId().toString());
        }

        Dock dock = defaultMasterdataService.get(Dock.RESOURCE_NAME, action.getDockReference().getEntityId(), DockPojo.class);
        DockReference dockReference = new DockReference(dock);

        if (isAlreadyAssociated(handlingRequest, loadingUnit, dockReference)) {
            throw new HandlingRequestActionException(Codes.ADDRESSING_ALREADY_PRESENT, handlingRequest.getId().toString());
        }
        HandlingRequestActivity refActivity = handlingRequest.getHandlingRequestActivities().stream().filter(act -> act.getLoadingUnit().equals(loadingUnit)).findFirst().get();
        if (refActivity.getTargetLocation() == null) {
            refActivity.setStatus(HandlingRequest.Status.ADDRESSED);
            refActivity.setTargetLocation(new LocationReference(dockReference));
            getEm().merge(refActivity);
        } else {
            HandlingRequestActivity activity = new HandlingRequestActivity();
            handlingRequest.addHandlingRequestActivity(activity);
            activity.setTargetLocation(new LocationReference(dockReference));
            activity.setLoadingUnit(loadingUnit);
            activity.setStatus(HandlingRequest.Status.ADDRESSED);
            //task the activity with same container and copy hrconfirmationStatus
            activity.setHrLoadingUnitsConfirmationStatus(refActivity.getHrLoadingUnitsConfirmationStatus());
            getEm().persist(activity);
        }


        return handlingRequest;
    }

    /**
     * The aim of this method is to get a list of locationReferences
     * and create N handlingRequestActivity for each locationReferences entered
     * @param handlingRequest
     * @param controlAction
     * @return HandlingRequest associated to N HandlingRequestActivity which in turn are associated
     * with specified locationReference.
     * @throws HandlingRequestActionException
     * @throws MasterdataServiceException
     * @throws InvalidClassException
     */
    @Condition({
            @Attribute(name = "status", values = {"TODO"})})
    public HandlingRequest action(final HandlingRequest handlingRequest, final HandlingRequestAddOrUpdateReferenceAction controlAction)
            throws HandlingRequestActionException, MasterdataServiceException, InvalidClassException, DockActionException {

        List<HandlingRequestActivity> handlingRequestActivityList = new ArrayList<>();


        //Add the handling request activities which are in status TODO and have the same Loading unit as the one
        //sent by parameter
        handlingRequestActivityList.addAll(handlingRequest.getHandlingRequestActivities().stream()
                .filter(item -> item.getStatus() == eu.reply.lea.services.yard.model.HandlingRequest.Status.TODO && item.getLoadingUnit().getId().toString().equals(controlAction.getLoadingUnitReference().getEntityId())).collect(Collectors.toList()));

        int handlingRequestActivityListSize = handlingRequestActivityList.size();
        //If we have more location than HR activities we allow to generate new HR activities.
        for(int index = 0; index < (controlAction.getLocationReferences().size() - handlingRequestActivityListSize); index++){
            handlingRequestActivityList.add(new HandlingRequestActivity());
        }

        LoadingUnitResource
            loadingUnit = handlingRequest.getUnits().stream().filter(item -> item.getId().toString().equals(controlAction.getLoadingUnitReference().getEntityId())).findFirst().orElse(null);


        //Check if loading unit is not present in the handing request loading units.
        if (loadingUnit==null) {
            throw new HandlingRequestActionException(Codes.MISSING_SPECIFIC_TRAILER, handlingRequest.getId().toString());
        }

        //check if length of handlingRequestActivityList is equals to the size of locationReferences
        if(handlingRequestActivityList.size()!= controlAction.getLocationReferences().size()){
            throw new InvalidClassException("Error, something went wrong. Try again...");
        }
        //foreach locationReference inside action, do this {
        for (int index = 0; index < handlingRequestActivityList.size(); index++) {
            //this is the entityId of a dock or a zone
            String entityId = controlAction.getLocationReferences().get(index).getEntityId();

            //initialize the handlingRequestActivity
            HandlingRequestActivity activity = handlingRequestActivityList.get(index);
            activity.setPositionIndex(index);

            LocationReference locationReference = null;
            HandlingRequestActivityAddressToDockAction actionAddressToDock = null;
            HandlingRequestActivityAddressToZoneAction actionAddressToZone = null;
            //check if it is an activity compatible with dock or zone
            if (handlingRequest.getType().toString().equals("LOAD") || handlingRequest.getType().toString().equals("UNLOAD")) {
                //initialize the dock
                //getting it
                Dock dock = defaultMasterdataService.get(Dock.RESOURCE_NAME, entityId, DockPojo.class);
                //set the dock reference of the dock
                DockReference dockReference = new DockReference(dock);
                locationReference = new LocationReference(dockReference);
                //set the dock to the target location of the activity
                actionAddressToDock = new HandlingRequestActivityAddressToDockAction();
                actionAddressToDock.setDockReference(locationReference);
            } else {
                //initialize the zone
                //getting it
                Zone zone = defaultMasterdataService.get(Zone.RESOURCE_NAME, entityId, ZonePojo.class);
                //set the reference of the zone
                ZoneReference zoneReference = new ZoneReference(zone);
                //set the zone to the target location of the activity
                locationReference = new LocationReference(zoneReference);
                actionAddressToZone = new HandlingRequestActivityAddressToZoneAction();
                actionAddressToZone.setZoneReference(locationReference);
            }

            //set the loadingUnitId of the handlingRequest
            // to the handlingRequestActivity
            activity.setLoadingUnit(loadingUnit);
            //task the activity with same container and copy hrconfirmationStatus
            activity.setHrLoadingUnitsConfirmationStatus(activity.getHrLoadingUnitsConfirmationStatus());
            //add the new child of this handling request
            //so, create the new handlingRequestActivity
            if(activity.getHandlingRequest()==null) {
                handlingRequest.addHandlingRequestActivity(activity);
            }
            //persist the activity
            getEm().persist(activity);

            //check if the action to be called will be addressed to a dock
            if(actionAddressToDock != null)
                //and then
                //call the action to associate the dock to this activity
                activityProcessor.action(activity, actionAddressToDock);
            else {
                //if isn't compatible with a dock, it will be addressed to a zone
                //call the action to associate this activity to a zone
                activityProcessor.action(activity, actionAddressToZone);
            }
        }
        //clear the list of locationReferences removing all data of this handlingRequest
        controlAction.getLocationReferences().removeAll(handlingRequestActivityList.stream().collect(Collectors.toList()));

        //if all the HRactivities are not in status TODO we set the HR in status addressed
        if (!handlingRequest.getHandlingRequestActivities().stream().anyMatch(item -> item.getStatus() == eu.reply.lea.services.yard.model.HandlingRequest.Status.TODO)){
            handlingRequest.setStatus(eu.reply.lea.services.yard.model.HandlingRequest.Status.ADDRESSED);
        }

        return handlingRequest;
    }

    private boolean isAlreadyAssociated(final HandlingRequest handlingRequest, final LoadingUnitResource loadingUnit, final DockReference dockReference) {
        return handlingRequest.getHandlingRequestActivities().stream().anyMatch(act1 -> YardUtils.sameReference(act1.getTargetLocation(), dockReference, true) && loadingUnit.equals(act1.getLoadingUnit()));
    }

    @Condition({@Attribute(name = "transit.status", values = {"ARRIVED"}),
            @Attribute(name = "status", values = {"TODO"}),
            @Attribute(name = "confirmationStatus", values = {"EXPECTED", "UNEXPECTED"})})
    public HandlingRequest confirm(final HandlingRequest request) throws HandlingRequestActionException {
        boolean allActivitiesAddressed = request.getHandlingRequestActivities().stream().allMatch(hr -> hr.getStatus().equals(HandlingRequest.Status.ADDRESSED));
        if (allActivitiesAddressed) {
            request.setStatus(HandlingRequest.Status.ADDRESSED);
        } else {
            throw new HandlingRequestActionException(Codes.NOT_ALL_ACTIVITIES_ADDRESSED, request.getId().toString());
        }
        getEm().merge(request);
        return request;

    }

    @Condition({@Attribute(name = "transit.status", values = {"ARRIVED", "IN"}),
            @Attribute(name = "status", values = {"TODO", "ADDRESSED"})})
    public HandlingRequest cancel(final HandlingRequest request) throws HandlingRequestActionException {
        for (HandlingRequestActivity activity : request.getHandlingRequestActivities()) {
            activityProcessor.cancel(activity);
        }
        return request;
    }

    // Private methods
    private void verifyTransit(final Transit transit) throws HandlingRequestActionException {
        if (transit == null) {
            throw new HandlingRequestActionException(Codes.NO_TRANSIT);
        }
    }


    private void associateExpectedLoadingUnit(final HandlingRequest handlingRequest, final EntityReference expectedUnitRefeference, final Class<? extends ExpectedLoadingUnit> loadingUnitRefClass) throws EntityNotFoundException, HandlingRequestActionException {
        ExpectedLoadingUnit expectedLoadingUnit = entityReferenceHandler.getEntity(expectedUnitRefeference, loadingUnitRefClass);
        if (expectedLoadingUnit == null) {
            throw new EntityNotFoundException(expectedUnitRefeference);
        }
        if (!expectedLoadingUnit.getTransit().equals(handlingRequest.getTransit())) {
            throw new HandlingRequestActionException(Codes.WRONG_EXPECTED_LOADING_UNIT, handlingRequest.toString());
        }

        handlingRequest.addExpectedContainer(expectedLoadingUnit);

        super.fireUpdated(new HandlingRequestUpdatedEvent(handlingRequest));
    }

    private void disassociateExpectedLoadingUnit(final HandlingRequest handlingRequest, @NonNull final EntityReference expectedUnitReference, final Class<? extends ExpectedLoadingUnit> loadingUnitRefClass) throws EntityNotFoundException, HandlingRequestActionException {
        ExpectedLoadingUnit expectedLoadingUnit = entityReferenceHandler.getEntity(expectedUnitReference, loadingUnitRefClass);
        if (expectedLoadingUnit == null) {
            throw new EntityNotFoundException(expectedUnitReference);
        }
        if (!expectedLoadingUnit.getHandlingRequests().contains(handlingRequest)) {
            throw new HandlingRequestActionException(Codes.EXPECTED_UNIT_NOT_ASSOCIATED);
        }

        handlingRequest.removeExpectedContainer(expectedLoadingUnit);

        super.fireUpdated(new HandlingRequestUpdatedEvent(handlingRequest));
    }

    /**
     * While creating/updating a transit, handling requests can be added.
     * Generate code for new handling requests and convert plate strings in
     * uppercase
     *
     * @param transit
     * @throws TransitActionException
     */
    public void handlingRequestsInitialization(final Transit transit) throws TransitActionException {
        Set<HandlingRequest> transitRequests = transit.getHandlingRequests();
        if (transitRequests != null) {
            if ((transitRequests.stream().filter(hr -> hr.getLocation() == null && hr.getType().equals(HandlingRequest.Type.LOAD)).count() > 1)
                    || (transitRequests.stream().filter(hr -> hr.getLocation() == null && hr.getType().equals(HandlingRequest.Type.UNLOAD)).count() > 1)) {
                throw new TransitActionException(TransitActionException.Codes.IDENTICAL_HANDLING_REQUESTS, transit.getCode());
            }
            for (final HandlingRequest h : transitRequests) {
                if (h.getScheduledEnd() != null ^ h.getScheduledStart() != null) {
                    throw new TransitActionException(TransitActionException.Codes.NOT_VALID_END_DATE, transit.getCode());
                }
                // check that the "end date" does not precede the "start date"
                if (h.getScheduledStart() != null && h.getScheduledEnd() != null
                        && ObjectUtils.compare(h.getScheduledEnd(), h.getScheduledStart()) <= 0) {
                    throw new TransitActionException(TransitActionException.Codes.NOT_VALID_END_DATE, transit.getCode());
                }
            }
        }
    }

}

---------- End of ./boundary/HandlingRequestProcessor.java ----------

---------- Start of ./boundary/HandlingRequestActivityProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import java.io.InvalidClassException;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;

import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.map.Dock;
import eu.reply.lea.services.masterdata.model.map.Zone;
import eu.reply.lea.services.masterdata.pojo.map.DockPojo;
import eu.reply.lea.services.masterdata.pojo.map.ZonePojo;
import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.actions.request.*;
import eu.reply.lea.services.yard.entities.HandlingRequest;
import eu.reply.lea.services.yard.entities.HandlingRequestActivity;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.events.request.HandlingRequestActivityStatusChangeEvent;
import eu.reply.lea.services.yard.events.request.HandlingRequestCancelledEvent;
import eu.reply.lea.services.yard.events.request.HandlingRequestCreatedEvent;
import eu.reply.lea.services.yard.events.request.HandlingRequestDeletedEvent;
import eu.reply.lea.services.yard.events.request.HandlingRequestUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.DockActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException;
import eu.reply.lea.services.yard.exceptions.HandlingRequestActionException.Codes;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.configuration.Condition.Attribute;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.event.Producer;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = HandlingRequestActivity.class)
public class HandlingRequestActivityProcessor extends AbstractProcessor<HandlingRequestCreatedEvent, HandlingRequestDeletedEvent, HandlingRequestUpdatedEvent> {

    @Inject
    private Producer<HandlingRequestCancelledEvent> handlingRequestCancelledEvent;

    @Inject
    private Producer<HandlingRequestActivityStatusChangeEvent> hraStatusChangeEventProducer;

    @Inject
    private DefaultMasterdataService masterdataService;


    public void persisting(final HandlingRequestActivity entity) {
    }

    public void merging(final HandlingRequestActivity activity) {
        if (HandlingRequest.Status.TODO.equals(activity.getStatus()) && activity.getTargetLocation() != null) {
            activity.setStatus(HandlingRequest.Status.ADDRESSED);
            hraStatusChangeEventProducer.fire(new HandlingRequestActivityStatusChangeEvent(activity));
        }
    }

    @Condition({@Attribute(name = "status", values = {"TODO"}),
            @Attribute(name = "handlingRequest.status", values = {"TODO"}),
            @Attribute(name = "handlingRequest.transit.locked", values = {"false"}),
            @Attribute(name = "handlingRequest.transit.status", values = {"WAITING", "ARRIVED"}),
            @Attribute(name = "handlingRequest.type", values = {"LOAD", "UNLOAD"})
    })
    public HandlingRequestActivity action(final HandlingRequestActivity activity, final HandlingRequestActivityAddressToDockAction action) throws HandlingRequestActionException, MasterdataServiceException, InvalidClassException, DockActionException {
        HandlingRequest handlingRequestReceived = activity.getHandlingRequest();
        HandlingRequest hr = this.getEm().find(HandlingRequest.class, handlingRequestReceived.getId());
        HandlingRequestActivity activity1 = this.getEm().find(HandlingRequestActivity.class, activity.getId());
        if (hr == null || hr.getStatus().equals(HandlingRequest.Status.ADDRESSED)) {
            throw new HandlingRequestActionException(Codes.ALREADY_ADDRESSED);
        }
        Dock dock = masterdataService.get(Dock.RESOURCE_NAME, action.getDockReference().getEntityId(), DockPojo.class);
        //we can't address the hr to a dock which is blocked. In this case we throw an exception
        if (dock.isBlocked()) {
            throw new DockActionException(DockActionException.Codes.DOCK_BLOCKED);
        }
        activity1.setTargetLocation(new LocationReference(dock));
        getEm().merge(activity1);
        getEm().flush();
        getEm().refresh(hr);
        return activity1;
    }

    @Condition({@Attribute(name = "status", values = {"TODO"}),
            @Attribute(name = "handlingRequest.status", values = {"TODO"}),
            @Attribute(name = "handlingRequest.transit.locked", values = {"false"}),
            @Attribute(name = "handlingRequest.transit.status", values = {"WAITING", "ARRIVED"}),
            @Attribute(name = "handlingRequest.type", values = {"PICKUP", "DROPOFF"})
    })
    public HandlingRequestActivity action(final HandlingRequestActivity activity, final HandlingRequestActivityAddressToZoneAction action) throws HandlingRequestActionException, MasterdataServiceException, InvalidClassException {
        HandlingRequest receivedHr = activity.getHandlingRequest();
        HandlingRequest hr = this.getEm().find(HandlingRequest.class, receivedHr.getId());
        HandlingRequestActivity handlingRequestActivity = this.getEm().find(HandlingRequestActivity.class, activity.getId());

        if (hr == null || hr.getStatus().equals(HandlingRequest.Status.ADDRESSED)) {
            throw new HandlingRequestActionException(Codes.ALREADY_ADDRESSED);
        }
        Zone zone = masterdataService.get(Zone.RESOURCE_NAME, action.getZoneReference().getEntityId(), ZonePojo.class);
        handlingRequestActivity.setTargetLocation(new LocationReference(zone));
        getEm().merge(handlingRequestActivity);
        getEm().flush();
        getEm().refresh(handlingRequestActivity.getHandlingRequest());
        return handlingRequestActivity;
    }


    @Condition({@Attribute(name = "handlingRequest.transit.status", values = {"ARRIVED", "IN"}),
            @Attribute(name = "handlingRequest.status", values = {"TODO", "ADDRESSED", "EXECUTING"}),
            @Attribute(name = "status", values = {"TODO", "ADDRESSED", "EXECUTING"})})
    public HandlingRequestActivity cancel(final HandlingRequestActivity activity) throws HandlingRequestActionException {
        checkActivityCanBeCancelled(activity);
        activity.setStatus(HandlingRequest.Status.CANCELLED);
        computeRequestStatus(activity.getHandlingRequest());
        getEm().merge(activity);
        getEm().refresh(activity.getHandlingRequest());
        hraStatusChangeEventProducer.fire(new HandlingRequestActivityStatusChangeEvent(activity));
        return activity;
    }


    /**
     * Compute handling request status and loading unit load status
     * <ol>
     * <li>if each activity of a request is COMPLETED except those CANCELLED, request is COMPLETED
     * <li>if each activity of a request is CANCELLED, request is CANCELLED
     * </ol>
     * Loading unit load status is computed by handling request type
     * <ol>
     * <li>if each LOAD/PICKUP/DROPOFF request is done, container load status is FULL
     * <li>if each UNLOAD request is done, container load status is EMPTY
     * <li>otherwise, container load status is PARTIAL
     * </ol>
     *
     * @param handlingRequest
     * @throws HandlingRequestActionException
     */
    private void computeRequestStatus(final HandlingRequest handlingRequest) {
        // Compute HandlingRequest Status
        if (allRequestActivitiesAreCancelled(handlingRequest)) {
            handlingRequest.cancelled();
            handlingRequestCancelledEvent.fire(new HandlingRequestCancelledEvent(handlingRequest));
        }
    }
    private boolean allRequestActivitiesAreCancelled(final HandlingRequest handlingRequest) {
        return handlingRequest.getHandlingRequestActivities().stream().allMatch(act -> act.getStatus().equals(HandlingRequest.Status.CANCELLED));
    }


    private void checkActivityCanBeCancelled(final HandlingRequestActivity activity) throws HandlingRequestActionException {
        if (!(Transit.Status.IN.equals(activity.getHandlingRequest().getTransit().getStatus()) ||
                Transit.Status.ARRIVED.equals(activity.getHandlingRequest().getTransit().getStatus()))) {
            throw new HandlingRequestActionException(HandlingRequestActionException.Codes.TRANSIT_STATUS_NOT_VALID, activity.getHandlingRequest().getId().toString());
        }
        if (!(HandlingRequest.Status.TODO.equals(activity.getStatus()) ||
                HandlingRequest.Status.ADDRESSED.equals(activity.getStatus()))) {
            throw new HandlingRequestActionException(HandlingRequestActionException.Codes.STATUS_NOT_VALID, activity.getHandlingRequest().getId().toString());
        }
    }


}

---------- End of ./boundary/HandlingRequestActivityProcessor.java ----------

---------- Start of ./boundary/LoadingUnitActivityProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import eu.reply.lea.services.yard.actions.loadingUnitActivity.LoadingUnitActivityCompleteAction;
import eu.reply.lea.services.yard.actions.loadingUnitActivity.LoadingUnitActivityConfirmAction;
import eu.reply.lea.services.yard.entities.LoadingUnitActivity;
import eu.reply.lea.services.yard.events.LoadingUnitActivityCreatedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitActivityDeletedEvent;
import eu.reply.lea.services.yard.events.LoadingUnitActivityUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActivityActionException;
import eu.reply.lea.services.yard.model.LoadingUnitResource.LoadStatus;
import eu.reply.lea.services.yard.model.LoadingUnitActivity.Status;
import eu.reply.lea.services.yard.model.LoadingUnitActivity.Type;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = LoadingUnitActivity.class)
public class LoadingUnitActivityProcessor extends AbstractProcessor<LoadingUnitActivityCreatedEvent, LoadingUnitActivityDeletedEvent, LoadingUnitActivityUpdatedEvent> {

	// Lifecycle methods

	public void persisting(final LoadingUnitActivity entity) {
	}

	public void persisted(final LoadingUnitActivity entity) {
		super.fireCreated(new LoadingUnitActivityCreatedEvent(entity));
	}

	public void merging(final LoadingUnitActivity entity) {
	}

	public void merged(final LoadingUnitActivity entity) {
		super.fireUpdated(new LoadingUnitActivityUpdatedEvent(entity));
	}

	public void removed(final LoadingUnitActivity entity) {
		super.fireDeleted(new LoadingUnitActivityDeletedEvent(entity));
	}
	
	public LoadingUnitActivity confirm(final LoadingUnitActivity entity, final LoadingUnitActivityConfirmAction action) throws LoadingUnitActivityActionException {
		if(action.getDock() == null) {
			throw new LoadingUnitActivityActionException(LoadingUnitActivityActionException.Codes.MISSING_DOCK, entity.getLoadingUnit().getCode());
		}
		checkActivityCanBeConfirmed(entity);
		entity.confirmed(action.getDock());
		return entity;
	}

	public LoadingUnitActivity start(final LoadingUnitActivity entity) throws LoadingUnitActivityActionException {
		checkActivityCanBeExecute(entity);
		entity.inProgress();
		return entity;
	}

	public LoadingUnitActivity action(final LoadingUnitActivity entity, final LoadingUnitActivityCompleteAction action) throws LoadingUnitActivityActionException {
		checkActivityCanBeCompleted(entity);
		if(action.getMovedWeight() != null) {
            entity.setMovedWeight(action.getConvertedWeight());
        }
		if(Type.isLoading(entity.getType())) {
			entity.getLoadingUnit().setLoadStatus(LoadStatus.FULL);
		} else {
			entity.getLoadingUnit().setLoadStatus(LoadStatus.EMPTY);
		}
		entity.completed();
		return entity;
	}

	//Methods
	
	private void checkActivityCanBeConfirmed(final LoadingUnitActivity entity) throws LoadingUnitActivityActionException {
		if(!Status.isTodo(entity.getStatus())) {
			throw new LoadingUnitActivityActionException(LoadingUnitActivityActionException.Codes.STATUS_NOT_VALID, entity.getLoadingUnit().getCode());
		}
	}

	private void checkActivityCanBeExecute(final LoadingUnitActivity entity) throws LoadingUnitActivityActionException {
		if(!Status.isConfirmed(entity.getStatus())) {
			throw new LoadingUnitActivityActionException(LoadingUnitActivityActionException.Codes.STATUS_NOT_VALID, entity.getLoadingUnit().getCode());
		}
	}

	private void checkActivityCanBeCompleted(final LoadingUnitActivity entity) throws LoadingUnitActivityActionException {
		if(!Status.isInProgress(entity.getStatus())) {
			throw new LoadingUnitActivityActionException(LoadingUnitActivityActionException.Codes.STATUS_NOT_VALID, entity.getLoadingUnit().getCode());
		}
	}

	
}

---------- End of ./boundary/LoadingUnitActivityProcessor.java ----------

---------- Start of ./boundary/SwitcherProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.map.Site;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.yard.entities.Switcher;
import eu.reply.lea.services.yard.events.SwitcherCreatedEvent;
import eu.reply.lea.services.yard.events.SwitcherDeletedEvent;
import eu.reply.lea.services.yard.events.SwitcherUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.SwitcherActionException;
import eu.reply.lea.services.yard.model.vehicle.Switcher.Status;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = Switcher.class)
public class SwitcherProcessor extends AbstractProcessor<SwitcherCreatedEvent, SwitcherDeletedEvent, SwitcherUpdatedEvent> {

    @Inject
    private DefaultMasterdataService masterdataService;
    
    public void persisting(final Switcher entity) throws MasterdataServiceException {
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(this.generateCode(Switcher.class, null));
        }
        if (entity.getSite()!=null) {
            Site site = masterdataService.get(entity.getSite());
            entity.setSite(new SiteReference(site));
        }
    }

    public void persisted(final Switcher entity) {
        super.fireCreated(new SwitcherCreatedEvent(entity));
    }

    public void merged(final Switcher entity) {
        super.fireUpdated(new SwitcherUpdatedEvent(entity));
    }

    public void removed(final Switcher entity) {
        super.fireDeleted(new SwitcherDeletedEvent(entity));
    }

    public Switcher busy(final Switcher entity) {
    	entity.setStatus(Status.BUSY);
    	getEm().merge(entity);
        return entity;
    }

    public Switcher free(final Switcher entity) throws SwitcherActionException {
    	if(entity.getAttachedUnit() != null) {
    		throw new SwitcherActionException(SwitcherActionException.Codes.ATTACHED_TO_LOADING_UNIT, entity.getCode());
    	}
    	entity.setStatus(Status.FREE);
        return entity;
    }

}

---------- End of ./boundary/SwitcherProcessor.java ----------

---------- Start of ./boundary/ContainerResourceProcessor.java ----------
package eu.reply.lea.services.yard.boundary;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;

import java.io.InvalidClassException;

import org.apache.commons.lang3.StringUtils;

import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.yard.actions.loadingUnit.CreateActivityAction;
import eu.reply.lea.services.yard.actions.loadingUnit.DockingAction;
import eu.reply.lea.services.yard.actions.loadingUnit.HookSwitcherAction;
import eu.reply.lea.services.yard.actions.loadingUnit.HookTruckAction;
import eu.reply.lea.services.yard.actions.loadingUnit.InPlaceAction;
import eu.reply.lea.services.yard.actions.loadingUnit.MovingAction;
import eu.reply.lea.services.yard.actions.loadingUnit.ParkedAction;
import eu.reply.lea.services.yard.actions.loadingUnit.PickupAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundExpectedSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundExpectedWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterInboundWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundExpectedSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundExpectedWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundSealAction;
import eu.reply.lea.services.yard.actions.loadingUnit.RegisterOutboundWeightAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToDockAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToYardAction;
import eu.reply.lea.services.yard.actions.loadingUnit.SendToZoneAction;
import eu.reply.lea.services.yard.entities.ContainerResource;
import eu.reply.lea.services.yard.events.ContainerResourceCreatedEvent;
import eu.reply.lea.services.yard.events.ContainerResourceDeletedEvent;
import eu.reply.lea.services.yard.events.ContainerResourceUpdatedEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@Default
@ApplicationScoped
@EntityProcessor(entityClass = ContainerResource.class)
public class ContainerResourceProcessor extends
    LoadingUnitResourceProcessor<ContainerResource, ContainerResourceCreatedEvent, ContainerResourceDeletedEvent, ContainerResourceUpdatedEvent> {


    public void persisting(final ContainerResource container) {
        if (StringUtils.isBlank(container.getCode())) {
            container.setCode(this.generateCode(ContainerResource.class, null));
        }
    }

    public void persisted(final ContainerResource container) {
        super.fireCreated(new ContainerResourceCreatedEvent(container));
    }

    public void merged(final ContainerResource container) {
        super.fireUpdated(new ContainerResourceUpdatedEvent(container));
    }

    public void removed(final ContainerResource container) {
        super.fireDeleted(new ContainerResourceDeletedEvent(container));
    }


    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterInboundWeightAction registerInboundWeightAction) {
        return super.action(loadingUnit, registerInboundWeightAction);
    }
    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterOutboundWeightAction registerOutboundWeightAction) {
        return super.action(loadingUnit, registerOutboundWeightAction);
    }

    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterInboundExpectedWeightAction registerInboundExpectedWeightAction) {
        return super.action(loadingUnit, registerInboundExpectedWeightAction);
    }

    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterOutboundExpectedWeightAction registerOutboundExpectedWeightAction) {
        return super.action(loadingUnit, registerOutboundExpectedWeightAction);
    }
    ///
    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterInboundSealAction registerInboundSealAction) {
        return super.action(loadingUnit, registerInboundSealAction);
    }

    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterOutboundSealAction registerOutboundSealAction) {
        return super.action(loadingUnit, registerOutboundSealAction);
    }

    @Override
    public ContainerResource action(final ContainerResource loadingUnit, final RegisterInboundExpectedSealAction registerInboundExpectedSealAction) {
        return super.action(loadingUnit, registerInboundExpectedSealAction);
    }

    @Override
    public ContainerResource action(final ContainerResource containerResource,final PickupAction pickupAction) throws LoadingUnitActionException,
        EntityNotFoundException, MasterdataServiceException {
        return super.action(containerResource, pickupAction);
    }

    @Override
    public ContainerResource performDropOff(final ContainerResource containerResource) throws LoadingUnitActionException,
        MasterdataServiceException {
        return super.performDropOff(containerResource);
    }

    @Override
    public ContainerResource action(final ContainerResource loadingUnit,final RegisterOutboundExpectedSealAction registerOutboundExpectedSealAction) {
        return super.action(loadingUnit, registerOutboundExpectedSealAction);
    }

    @Override
    public <D extends DockingAction> ContainerResource action(final ContainerResource loadingUnit, final D dockingAction)
        throws LoadingUnitActionException {
        return super.action(loadingUnit, dockingAction);
    }

    @Override
    public ContainerResource out(final ContainerResource loadingUnit) throws LoadingUnitActionException {
        return super.out(loadingUnit);
    }

    @Override
    public <D extends MovingAction> ContainerResource action(final ContainerResource loadingUnit, final D loadingUnitMovingAction)
        throws LoadingUnitActionException {
        return super.action(loadingUnit, loadingUnitMovingAction);
    }

    @Override
    public <A extends ParkedAction> ContainerResource action(final ContainerResource loadingUnit, final A loadingUnitParkedAction)
        throws LoadingUnitActionException {
        return super.action(loadingUnit, loadingUnitParkedAction);
    }

    @Override
    public <A extends InPlaceAction> ContainerResource action(final ContainerResource loadingUnit,
                                                              final A loadingUnitInPlaceAction)
        throws LoadingUnitActionException {
        return super.action(loadingUnit, loadingUnitInPlaceAction);
    }

    @Override
    public ContainerResource release(final ContainerResource loadingUnit)
        throws LoadingUnitActionException, MasterdataServiceException {
        return super.release(loadingUnit);
    }



    @Override
    public ContainerResource undocking(final ContainerResource loadingUnit) throws LoadingUnitActionException {
        return super.undocking(loadingUnit);
    }

    @Override
    public <D extends HookTruckAction> ContainerResource action(final ContainerResource loadingUnit,
                                                                final D loadingUnitHookTruckAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException {
        return super.action(loadingUnit, loadingUnitHookTruckAction);
    }

    @Override
    public <D extends HookSwitcherAction> ContainerResource action(final ContainerResource loadingUnit,
                                                                   final D loadingUnitHookSwitcherAction)
        throws LoadingUnitActionException, MasterdataServiceException, EntityNotFoundException {
        return super.action(loadingUnit, loadingUnitHookSwitcherAction);
    }

    @Override
    public <D extends CreateActivityAction> ContainerResource action(final ContainerResource loadingUnit,
                                                                     final D createActivityAction)
        throws LoadingUnitActionException {
        return super.action(loadingUnit, createActivityAction);
    }

    @Override
    public <D extends SendToDockAction> ContainerResource action(final ContainerResource loadingUnit,
                                                                 final D loadingUnitSendToDockAction)
        throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException {
        return super.action(loadingUnit, loadingUnitSendToDockAction);
    }

    @Override
    public <D extends SendToZoneAction> ContainerResource action(final ContainerResource loadingUnit, final D sendToZoneAction)
        throws LoadingUnitActionException, MasterdataServiceException, InvalidClassException {
        return super.action(loadingUnit, sendToZoneAction);
    }

    @Override
    public <D extends SendToYardAction> ContainerResource action(final ContainerResource loadingUnit, final D sendToYardAction) {
        return super.action(loadingUnit, sendToYardAction);
    }
}

---------- End of ./boundary/ContainerResourceProcessor.java ----------

---------- Start of ./boundary/transitdeletion/TransitDeletionCommandObserver.java ----------
package eu.reply.lea.services.yard.boundary.transitdeletion;

import static eu.reply.lea.services.yard.entities.Transit.Q_FIND_BY_APP_CODE_AND_STATUS;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;

import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;

import eu.reply.lea.services.yard.boundary.TransitProcessor;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.exceptions.TransitActionException;
import eu.reply.sce.backend.core.event.ModuleEvent;
import eu.reply.sce.backend.core.event.Observer;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;


@Observer
@Logged
@ApplicationScoped
public class TransitDeletionCommandObserver {

    @Inject
    private TransitProcessor transitProcessor;

    @Inject
    private Logger logger;

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    public void dispatcher(
        @Observes @ModuleEvent("transitDeletionCommand") final JsonNode transitDeletionCommandInfo)
        throws TransitActionException {

        if (transitDeletionCommandInfo.get("appointmentCode") != null) {
            String appointmentCode = transitDeletionCommandInfo.get("appointmentCode").asText();
            try {
                Transit transit = em.createNamedQuery(Q_FIND_BY_APP_CODE_AND_STATUS, Transit.class)
                    .setParameter(Transit.P_APP_CODE, appointmentCode)
                    .setParameter(Transit.P_STATUS, Transit.Status.getActiveStatusesList()).getSingleResult();
                transitProcessor.cancel(transit);
            } catch (NoResultException e) {
                this.logger.debug(String.format("There are no active transit for appointment with code %s", appointmentCode));
            }

        }

    }


}

---------- End of ./boundary/transitdeletion/TransitDeletionCommandObserver.java ----------

---------- Start of ./vehicles/UnitAttacherTruckAdapter.java ----------
package eu.reply.lea.services.yard.vehicles;

import eu.reply.lea.services.masterdata.model.vehicle.Truck;
import eu.reply.lea.services.masterdata.model.vehicle.Vehicle;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitAttachedToTransitEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitDetachedFromTransitEvent;
import eu.reply.lea.services.yard.model.LoadingUnitResource;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacher;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;

import java.util.ArrayList;
import java.util.Collection;

public class UnitAttacherTruckAdapter implements LoadingUnitAttacher {

    private Truck truck;
    private Transit transit;
    private final ConfigurableEventProducer<LoadingUnitAttachedToTransitEvent> loadingUnitAttachedToTransitProducer;
    private final ConfigurableEventProducer<LoadingUnitDetachedFromTransitEvent> loadingUnitDetachedFromTransitProducer;

    UnitAttacherTruckAdapter(Truck truck, Transit transit, ConfigurableEventProducer<LoadingUnitAttachedToTransitEvent> loadingUnitAttachedToTransitProducer,
                             ConfigurableEventProducer<LoadingUnitDetachedFromTransitEvent> loadingUnitDetachedFromTransitProducer){
        this.truck= truck;
        this.transit = transit;
        this.loadingUnitAttachedToTransitProducer = loadingUnitAttachedToTransitProducer;
        this.loadingUnitDetachedFromTransitProducer = loadingUnitDetachedFromTransitProducer;
    }

    @Override
    public void attachLoadingUnit(LoadingUnitResource loadingUnitResource) {
        loadingUnitResource.attachToVehicle(getAttachingVehicle().getVehicleReference());
        loadingUnitResource.attachTransit(new TransitReference(transit), loadingUnitAttachedToTransitProducer);
    }

    @Override
    public void detachLoadingUnit(LoadingUnitResource loadingUnitResource) {
        loadingUnitResource.releaseFromAttachedVehicle(loadingUnitDetachedFromTransitProducer);
    }

    @Override
    public Collection<LoadingUnitResource> getAttachedLoadingUnits() {
        return new ArrayList<>();
    }

    @Override
    public boolean canAttachUnits() {
        return this.isAvailable();
    }

    @Override
    public Vehicle getAttachingVehicle() {
        return truck;
    }

    @Override
    public boolean isAvailable() {
        return true;
    }
}

---------- End of ./vehicles/UnitAttacherTruckAdapter.java ----------

---------- Start of ./vehicles/SwitcherProviderProxy.java ----------
package eu.reply.lea.services.yard.vehicles;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import eu.reply.lea.services.yard.entities.Switcher;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacher;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacherProxy;
import eu.reply.sce.backend.core.entity.TypedEntityReference;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import lombok.Getter;

@Getter
@ApplicationScoped
public class SwitcherProviderProxy implements LoadingUnitAttacherProxy {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Override
    public LoadingUnitAttacher findAvailableAttacherInstance(final Object loadingUnitInstance, final TypedEntityReference<?> reference, final Object instanceIdentifier) throws EntityNotFoundException {
        Switcher switcher = null;
        if(reference!= null) {
            switcher = getEm().find(Switcher.class, Long.parseLong(reference.getEntityId()));
        } else {
            switcher = Switcher.findBy(getEm(), instanceIdentifier.toString());
        }
        return switcher;
    }
}

---------- End of ./vehicles/SwitcherProviderProxy.java ----------

---------- Start of ./vehicles/TruckProviderProxy.java ----------
package eu.reply.lea.services.yard.vehicles;

import java.util.List;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.apache.commons.collections.CollectionUtils;

import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.client.DefaultMasterdataService;
import eu.reply.lea.services.masterdata.client.MasterdataServiceException;
import eu.reply.lea.services.masterdata.model.vehicle.Truck;
import eu.reply.lea.services.masterdata.pojo.vehicle.TruckPojo;
import eu.reply.lea.services.masterdata.reference.TruckReference;
import eu.reply.lea.services.yard.ModuleConfiguration;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitAttachedToTransitEvent;
import eu.reply.lea.services.yard.events.loadingUnit.LoadingUnitDetachedFromTransitEvent;
import eu.reply.lea.services.yard.exceptions.LoadingUnitActionException;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacher;
import eu.reply.lea.services.yard.model.vehicle.LoadingUnitAttacherProxy;
import eu.reply.sce.backend.core.entity.TypedEntityReference;
import eu.reply.sce.backend.core.entity.exception.EntityNotFoundException;
import eu.reply.sce.backend.core.event.ConfigurableEventProducer;

import lombok.Getter;

@Getter
@ApplicationScoped
public class TruckProviderProxy implements LoadingUnitAttacherProxy {

    @Inject
    private DefaultMasterdataService masterdataService;

    @Inject
    private ConfigurableEventProducer<LoadingUnitAttachedToTransitEvent> loadingUnitAttachedToTransitProducer;

    @Inject
    private ConfigurableEventProducer<LoadingUnitDetachedFromTransitEvent> loadingUnitDetachedFromTransitProducer;

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Override
    public LoadingUnitAttacher findAvailableAttacherInstance(final Object loadingUnitIdentifier,final TypedEntityReference<?> reference, final Object instanceIdentifier) throws EntityNotFoundException, LoadingUnitActionException {
        Truck truck = null;
        if (reference != null) {
            try {
                truck = masterdataService.get((TruckReference)reference);
            } catch (MasterdataServiceException e) {
               throw new EntityNotFoundException(Truck.RESOURCE_NAME, reference.getEntityId());
            }
        } else {
            List<TruckPojo> truckList = null;
            try {
                truckList = this.masterdataService.getByLicencePlate(Truck.RESOURCE_NAME, (LicencePlate)instanceIdentifier, TruckPojo.class);
                if (CollectionUtils.isEmpty(truckList)) {
                    throw new EntityNotFoundException(Truck.RESOURCE_NAME, instanceIdentifier.toString());
                }
            } catch (MasterdataServiceException e) {
                throw new EntityNotFoundException(Truck.RESOURCE_NAME, instanceIdentifier.toString());
            }
            truck = truckList.get(0);
        }
        Transit relatedTransit = getRelatedTransit(truck, loadingUnitIdentifier);
        return new UnitAttacherTruckAdapter(truck, relatedTransit, loadingUnitAttachedToTransitProducer,loadingUnitDetachedFromTransitProducer);
    }
    private Transit getRelatedTransit(final Truck truck, final Object loadingUnitIdentifier){
        List<Transit> transitList = Transit.findByTruckPlate(getEm(), truck.getLicencePlate()).stream().filter(
            t -> (
                Transit.Status.IN.equals(t.getStatus()) ||
                Transit.Status.ARRIVED.equals(t.getStatus()) ||
                Transit.Status.COMPLETED.equals(t.getStatus()))).collect(Collectors.toList());
        if (transitList.size() != 1) {
            throw new LoadingUnitActionException(LoadingUnitActionException.Codes.TRUCK_NOT_IN_PLANT, loadingUnitIdentifier.toString());
        }

       return transitList.get(0);
    }
}

---------- End of ./vehicles/TruckProviderProxy.java ----------

---------- Start of ./util/ObjectMapperUtility.java ----------
package eu.reply.lea.services.yard.util;

import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperUtility {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static ObjectMapper getMapper() {
        return mapper;
    }
}


---------- End of ./util/ObjectMapperUtility.java ----------

---------- Start of ./Validator.java ----------
package eu.reply.lea.services.yard;

public abstract class Validator {

    private ValidationNotificationHandler notificationHandler;

    public Validator(ValidationNotificationHandler aHandler) {
        super();

        this.setNotificationHandler(aHandler);
    }

    public abstract void validate();

    protected ValidationNotificationHandler notificationHandler() {
        return this.notificationHandler;
    }

    private void setNotificationHandler(ValidationNotificationHandler aHandler) {
        this.notificationHandler = aHandler;
    }
}
---------- End of ./Validator.java ----------

---------- Start of ./application/TransitApplicationService.java ----------
package eu.reply.lea.services.yard.application;


import java.util.Calendar;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;

import eu.reply.lea.services.common.embedded.DrivingLicence;
import eu.reply.lea.services.common.embedded.LicencePlate;
import eu.reply.lea.services.masterdata.reference.CarrierReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.yard.entities.ScheduledActivityDTO;
import eu.reply.lea.services.yard.entities.Transit;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityReferenceHandler;
import eu.reply.sce.backend.core.jee.log.Logged;

@Transactional(Transactional.TxType.REQUIRES_NEW)
@ApplicationScoped
@Logged
public class TransitApplicationService {


    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;

    @Inject
    private EntityReferenceHandler entityReferenceHandler;

    public Transit createTransit(final String externalCode,
                                 final String appointmentCode,
                                 final LicencePlate expectedTruckPlate,
                                 final DrivingLicence expectedDrivingLicence,
                                 final SiteReference siteReference,
                                 final CarrierReference carrier,
                                 final Calendar expectedRegistrationDateFrom,
                                 final Calendar expectedRegistrationDateTo) {
        Transit transit = new Transit( externalCode,
                                                       appointmentCode,
                                                       expectedTruckPlate,
                                                       expectedDrivingLicence,
                                                       siteReference,
                                                       carrier,
                                                       expectedRegistrationDateFrom,
                                                       expectedRegistrationDateTo);
        em.persist(transit);
        return transit;
    }



    public void addExpectedTrailers(Long transitId, Set<LicencePlate> licencePlates) {
        Transit transit = em.find(Transit.class, transitId);
        for (LicencePlate licensePlate : licencePlates) {
            transit.addExpectedTrailer(licensePlate);
        }
        em.merge(transit);
    }

    public void addScheduledActivities(Long transitId, Set<ScheduledActivityDTO> scheduledActivitiesDTO) {
        Transit transit = em.find(Transit.class, transitId);
        for (ScheduledActivityDTO scheduledActivityDTO : scheduledActivitiesDTO) {
            transit.addScheduledActivity(scheduledActivityDTO.getHrType(), scheduledActivityDTO.getDockReference());
        }
        em.merge(transit);
    }

    public void completeTransit(final TransitReference transitReference){
        Transit transit = entityReferenceHandler.getEntity(transitReference, Transit.class);
        transit.complete();
    }
}

---------- End of ./application/TransitApplicationService.java ----------

---------- Start of ./application/LoadingUnitMovementApplicationService.java ----------
package eu.reply.lea.services.yard.application;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.util.List;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.domainservice.LoadingUnitMovementDomainService;
import eu.reply.lea.services.yard.entities.LoadingUnitMovement;
import eu.reply.lea.services.yard.entities.LoadingUnitResource;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.repository.LoadingUnitMovementRepository;
import eu.reply.sce.backend.core.jee.log.Logged;


@ApplicationScoped
@Logged
public class LoadingUnitMovementApplicationService {

    @Inject
    private LoadingUnitMovementRepository loadingUnitMovementRepository;
    @Inject
    private LoadingUnitMovementDomainService loadingUnitMovementDomainService;


    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createNewMovement(@NotNull final LoadingUnitReference loadingUnitRef, final LocationReference destinationLocation) {
        List<LoadingUnitMovement> loadingUnitMovements =
            loadingUnitMovementRepository.findByLoadingUnitRef(loadingUnitRef);
        loadingUnitMovementDomainService.createNewMovement(loadingUnitMovements, loadingUnitRef, destinationLocation);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createNewMovement(@NotNull final LoadingUnitMovement loadingUnitMovement) {
        loadingUnitMovementDomainService.createNewMovement(loadingUnitMovement);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void completeMovement(@NotNull final LoadingUnitMovement loadingUnitMovement) {
        loadingUnitMovementDomainService.completeMovement(loadingUnitMovement);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void completeMovement(@NotNull final LoadingUnitReference loadingUnitRef, final LocationReference parkLocation) {
        List<LoadingUnitMovement> loadingUnitMovements =
            loadingUnitMovementRepository.findByLoadingUnitRef(loadingUnitRef);
        loadingUnitMovementDomainService.completeMovement(loadingUnitMovements, loadingUnitRef, parkLocation);
    }

}

---------- End of ./application/LoadingUnitMovementApplicationService.java ----------

---------- Start of ./application/TransitMovementApplicationService.java ----------
package eu.reply.lea.services.yard.application;

import java.util.List;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yard.domainservice.TransitMovementDomainService;
import eu.reply.lea.services.yard.entities.TransitMovement;
import eu.reply.lea.services.yard.reference.TransitReference;
import eu.reply.lea.services.yard.repository.TransitMovementRepository;
import eu.reply.sce.backend.core.jee.log.Logged;


@ApplicationScoped
@Logged
public class TransitMovementApplicationService {

    @Inject
    private TransitMovementRepository transitMovementRepository;
    @Inject
    private TransitMovementDomainService transitMovementDomainService;


    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createNewMovement(@NotNull final TransitReference transitReference, final LocationReference destinationLocation) {
        List<TransitMovement> transitMovements =
            transitMovementRepository.findByTransitReference(transitReference);
        transitMovementDomainService.createNewMovement(transitMovements, transitReference, destinationLocation);

    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void completeMovement(@NotNull final TransitReference transitReference, final LocationReference destinationLocation) {
        List<TransitMovement> transitMovements =
            transitMovementRepository.findByTransitReference(transitReference);
        transitMovementDomainService.completeMovement(transitMovements, transitReference, destinationLocation);
    }

}

---------- End of ./application/TransitMovementApplicationService.java ----------

This below is another module:


---------- Start of ./MissionTaskDetail.java ----------
package eu.reply.lea.services.yms.task.mission;

import java.util.Objects;
import javax.annotation.Nonnull;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;

import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yms.task.LocationAwareTaskDetail;

@Entity
public class MissionTaskDetail extends LocationAwareTaskDetail<MissionTask> {

    private static final long serialVersionUID = 9054947047886305201L;

    @ManyToOne(optional=false)
    private MissionTask task;


    protected MissionTaskDetail() {
        super();
    }

    public MissionTaskDetail(@Nonnull final MissionTask task, @Nonnull final LoadingUnitReference loadingUnitReference) {
        this();
        this.task = Objects.requireNonNull(task, "task");
        this.setLoadingUnitReference(loadingUnitReference);
    }

    @Override
    public MissionTask getTask() {
        return task;
    }

    @Override
    protected void setTask(final MissionTask task) {
        this.task = task;
    }


}
---------- End of ./MissionTaskDetail.java ----------

---------- Start of ./MissionTaskConfiguration.java ----------
package eu.reply.lea.services.yms.task.mission;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NamedQuery;

import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.process.task.entities.exceptions.TaskConfigurationNotFoundException;
import eu.reply.lea.services.yms.task.TaskType;
import eu.reply.lea.services.yms.task.locationaware.LocationAwareTaskConfiguration;

import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@NamedQuery(name=MissionTaskConfiguration.Q_FIND_BY_NAME,query="select c from MissionTaskConfiguration c where c.enabled=true and c.name = :name")
public class MissionTaskConfiguration extends LocationAwareTaskConfiguration<MissionTaskHeader> {

    private static final long serialVersionUID = -3245924133352157462L;

    public static final String Q_FIND_BY_NAME = "MissionTaskConfiguration.Q_FIND_BY_NAME";
    
    @Embedded
    private MissionTaskHeader headers;
    
    public MissionTaskConfiguration() {
    	super(TaskType.MISSION);
    }

    public MissionTaskConfiguration(final String name, final SiteReference siteReference, final String description, final MissionTaskHeader header) {
    	super(name, siteReference,description, TaskType.MISSION, header);
    }
    
    public MissionTaskConfiguration(final String name, final String description,final SiteReference siteReference, final MissionTaskHeader header) {
    	super(name,siteReference, description, TaskType.MISSION, header);
    }
    
    public static MissionTaskConfiguration findBy(final EntityManager em, final SiteReference site) throws TaskConfigurationNotFoundException {
        return LocationAwareTaskConfiguration.findByNameOrNull(em, MissionTaskConfiguration.class, site, site.getBusinessKey());
    }
    

}

---------- End of ./MissionTaskConfiguration.java ----------

---------- Start of ./MissionTaskRepository.java ----------
package eu.reply.lea.services.yms.task.mission;


import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.sce.backend.core.jee.configuration.ModuleConfiguration;
import eu.reply.sce.backend.core.jee.log.Logged;

@ApplicationScoped
@Logged
public class MissionTaskRepository {

    @Inject
    @ModuleConfiguration.Module(ModuleConfiguration.Module.CURRENT)
    private EntityManager em;



    public List<MissionTask> findByLoadingUnit(final LoadingUnitReference loadingUnitReference) {
        return em.createNamedQuery(MissionTask.Q_FIND_BY_LOADING_UNIT_REFERENCE, MissionTask.class)
            .setParameter("module", loadingUnitReference.getModule())
            .setParameter("entityName", loadingUnitReference.getEntityName())
            .setParameter("entityId", loadingUnitReference.getEntityId())
                .getResultList();

    }


}

---------- End of ./MissionTaskRepository.java ----------

---------- Start of ./MissionTaskProcessor.java ----------
package eu.reply.lea.services.yms.task.mission;

import java.math.BigDecimal;
import java.util.List;
import javax.annotation.Nonnull;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;

import org.apache.commons.collections4.ListUtils;

import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.yard.client.DefaultYardService;
import eu.reply.lea.services.yard.client.YardServiceException;
import eu.reply.lea.services.yard.model.vehicle.Switcher;
import eu.reply.lea.services.yard.pojo.SwitcherPojo;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yard.reference.SwitcherReference;
import eu.reply.lea.services.yms.boundary.YardService;
import eu.reply.lea.services.yms.task.AbstractLocationAwareTaskProcessor;
import eu.reply.lea.services.yms.task.exception.LoadUnitTaskActionException;
import eu.reply.lea.services.yms.task.exception.LoadUnitTaskActionException.Codes;
import eu.reply.lea.services.yms.task.mission.MissionTask.ActionStatus;
import eu.reply.lea.services.yms.util.YMSUtils;
import eu.reply.sce.backend.core.entity.configuration.Condition;
import eu.reply.sce.backend.core.entity.configuration.Condition.Attribute;
import eu.reply.sce.backend.core.jee.configuration.entity.EntityProcessor;
import eu.reply.sce.backend.core.jee.log.Logged;

@ApplicationScoped
@Logged
@Default
@EntityProcessor(entityClass=MissionTask.class)
public class MissionTaskProcessor extends AbstractLocationAwareTaskProcessor<MissionTask> {

	@Inject
	private YardService yardService;

	@Inject
	private DefaultYardService defaultYardService;

	@Override
	@Condition({ @Attribute(name = "status", values = { "TODO", "IN_PROGRESS", "PENDING" }) })
	public MissionTask enter(final MissionTask task) {
		return super.enter(task);
	}

	@Override
	@Condition({ @Attribute(name = "status", values = { "IN_PROGRESS" }) })
	public MissionTask exit(final MissionTask task) {
		return super.exit(task);
	}

	@Override
	@Condition({ @Attribute(name = "status", values = { "TODO", "IN_PROGRESS", "PENDING" }) })
	public MissionTask close(final MissionTask task) {
		return super.close(task);
	}

	@Override
	@Condition({ @Attribute(name = "status", values = { "TODO" }) })
	public MissionTask cancel(final MissionTask task) {
		throw new UnsupportedOperationException();
	}

	@Condition({
		@Attribute(name = "status", values = { "IN_PROGRESS" }),
		@Attribute(name = "actionStatus", values = { "READY" }),
		@Attribute(name = "vehicle", values = { "null" })
	})
	public MissionTask action(@Nonnull final MissionTask task, @Nonnull final MissionTaskAssociateVehicleAction action) throws LoadUnitTaskActionException, YardServiceException {
		if(action.isHookingVehicleDataMissing()) {
			throw new LoadUnitTaskActionException(Codes.MISSING_VEHICLE, task);
		}
        yardService.callSwitcherBusyAction(action.getSwitcherReference());
		task.setVehicle(new VehicleReference(action.getSwitcherReference()));
		return task;
	}

	@Condition({
		@Attribute(name = "status", values = { "IN_PROGRESS" }),
		@Attribute(name = "actionStatus", values = { "READY" }),
		@Attribute(name = "vehicle", values = { "<> null" })
	})
	public MissionTask detachVehicle(@Nonnull final MissionTask task) throws YardServiceException, LoadUnitTaskActionException {
		freeSwitcher(task);
		task.setVehicle(null);
		return task;
	}

	@Condition({
		@Attribute(name = "status", values = { "IN_PROGRESS" }),
		@Attribute(name = "actionStatus", values = { "READY" }),
		@Attribute(name = "vehicle", values = { "<> null" })
	})
	public MissionTask hook(@Nonnull final MissionTask task) {
		yardService.callLoadingUnitMovementStartAction(task);
		return task;
	}

	@Condition({
		@Attribute(name = "status", values = { "IN_PROGRESS" }),
		@Attribute(name = "actionStatus", values = { "HOOKED" })
	})
	public MissionTask unhook(@Nonnull final MissionTask task) {
		yardService.callLoadingUnitMovementEndAction(task);
		return closeTask(task);
	}

	@Condition({
		@Attribute(name = "status", values = { "BLOCKED", "IN_PROGRESS" })
	})
	public MissionTask forceComplete(@Nonnull final MissionTask task) throws YardServiceException, LoadUnitTaskActionException {
		return closeTask(task);
	}

	private MissionTask closeTask(final MissionTask task) {
		task.setActionStatus(ActionStatus.UNHOOKED);
		task.getProgression().setMaxLimit(BigDecimal.ONE);
		task.getProgression().setCurrent(new BigDecimal(1));
		return checkCloseAuto(task);
	}



}

---------- End of ./MissionTaskProcessor.java ----------

---------- Start of ./MissionTaskHeader.java ----------
package eu.reply.lea.services.yms.task.mission;

import javax.persistence.Embeddable;

import eu.reply.lea.services.yms.task.locationaware.LocationAwareTaskHeader;

@Embeddable

public class MissionTaskHeader extends LocationAwareTaskHeader {

    private static final long serialVersionUID = -6574898603367322815L;

    public MissionTaskHeader() {
        super();
    }

    private MissionTaskHeader(final MissionTaskHeader other) {
        super(other);
    }

    @Override
    public MissionTaskHeader clone() {
        return new MissionTaskHeader(this);
    }

}

---------- End of ./MissionTaskHeader.java ----------

---------- Start of ./MissionTaskBuilder.java ----------
package eu.reply.lea.services.yms.task.mission;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.yms.task.TaskType;
import eu.reply.lea.services.yms.task.TaskTypeQualifier;
import eu.reply.lea.services.yms.task.locationaware.LocationAwareTaskBuilder;
import eu.reply.sce.backend.core.jee.log.Logged;

@Logged
@TaskTypeQualifier(value = TaskType.MISSION)
public class MissionTaskBuilder
    extends LocationAwareTaskBuilder<MissionTaskBuilder, MissionTaskHeader, MissionTaskConfiguration, MissionTask> {

    public MissionTaskBuilder() {
        super(MissionTaskConfiguration.class, MissionTask.class); // Pass the actual class type
    }

    @Override
    protected MissionTask createTask() {
        return new MissionTask(this.getCode(), this.getSiteReference(), this.getConfig(),
                               (LocationReference) this.getOptionalParameters().get("locationFrom"),
                               (LocationReference) this.getOptionalParameters().get("locationTo"));
    }

    @Override
    protected void createTaskDetails(final MissionTask task) {

    }


}

---------- End of ./MissionTaskBuilder.java ----------

---------- Start of ./MissionTask.java ----------
package eu.reply.lea.services.yms.task.mission;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import eu.reply.lea.services.masterdata.reference.LocationReference;
import eu.reply.lea.services.masterdata.reference.SiteReference;
import eu.reply.lea.services.masterdata.reference.VehicleReference;
import eu.reply.lea.services.process.task.entities.TaskStatus;
import eu.reply.lea.services.yard.reference.LoadingUnitMovementReference;
import eu.reply.lea.services.yard.reference.LoadingUnitReference;
import eu.reply.lea.services.yms.task.locationaware.LocationAwareTask;
import eu.reply.sce.backend.core.entity.EntityReference;
import eu.reply.sce.backend.core.sequence.businesskey.BusinessKeySequence;

@Entity
@Getter
@Setter
@BusinessKeySequence(prefix = "MISSION", length = 10)
@NamedQueries({
    @NamedQuery(name=MissionTask.Q_FIND_BY_VEHICLE_REF,query="select m from MissionTask m where m.vehicle = :vehicle"),
    @NamedQuery(name = MissionTask.Q_FIND_BY_LOADING_UNIT_REFERENCE,
        query = "select DISTINCT m from MissionTask m JOIN m.details md "
                + "where md.loadingUnitReference.entityId = :entityId "
                + "and md.loadingUnitReference.entityName = :entityName and md.loadingUnitReference.module = :module")
})
public class MissionTask extends LocationAwareTask<MissionTaskConfiguration, MissionTaskHeader, MissionTaskDetail>{

    private static final long serialVersionUID = 6266394206640176004L;

    public static final String Q_FIND_BY_VEHICLE_REF = "MissionTask.Q_FIND_BY_VEHICLE_REF";
    public static final String Q_FIND_BY_LOADING_UNIT_REFERENCE = "MissionTask.Q_FIND_BY_LOADING_UNIT_REFERENCE";

    public static final String P_VEHICLE = "vehicle";
    
    @Embedded
    private MissionTaskHeader headers;
    
    @JsonIgnore
    @ManyToOne(optional = true, fetch = FetchType.LAZY)
    private MissionTaskConfiguration configuration;

    @OneToMany(mappedBy = "task", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH }, orphanRemoval = true)
    private Set<MissionTaskDetail> details = new HashSet<>();

    @AttributeOverrides({
    	@AttributeOverride(name = "entityName", column = @Column(name = "lu_movement_entityName")),
    	@AttributeOverride(name = "businessKey", column = @Column(name = "lu_movement_businesskey")),
    	@AttributeOverride(name = "module", column = @Column(name = "lu_movement_module", length = 20)),
    	@AttributeOverride(name = "entityId", column = @Column(name = "lu_movement_entityId", length = 50)) })
    private LoadingUnitMovementReference loadingUnitMovementRef; //TODO maybe remove?
    
    @AttributeOverrides({
        @AttributeOverride(name = "entityName", column = @Column(name = "vehicle_entityName")),
        @AttributeOverride(name = "businessKey", column = @Column(name = "vehicle_businesskey")),
        @AttributeOverride(name = "module", column = @Column(name = "vehicle_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "vehicle_entityId", length = 50)) })
    private VehicleReference vehicle;

    @AttributeOverrides({ @AttributeOverride(name = "businessKey", column = @Column(name = "site_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "site_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "site_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "site_entityId", length = 50)) })
	private SiteReference site;

    @AttributeOverrides({ @AttributeOverride(name = "businessKey", column = @Column(name = "sLocation_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "sLocation_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "sLocation_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "sLocation_entityId", length = 50)) })
	private LocationReference hookLocation;

    @AttributeOverrides({ @AttributeOverride(name = "businessKey", column = @Column(name = "dLocation_businessKey")),
        @AttributeOverride(name = "entityName", column = @Column(name = "dLocation_entityName")),
        @AttributeOverride(name = "module", column = @Column(name = "dLocation_module", length = 20)),
        @AttributeOverride(name = "entityId", column = @Column(name = "dLocation_entityId", length = 50)) })
	private LocationReference unhookLocation;

    @Enumerated(EnumType.STRING)
    private ActionStatus actionStatus;
    
    protected MissionTask() {
       super();
    }
    
    public MissionTask(final String name, final SiteReference siteReference, final MissionTaskConfiguration config,
                       final LocationReference hookLocation, final LocationReference unhookLocation) {
        super(name, siteReference, config);
        this.site = siteReference;
        this.actionStatus = ActionStatus.READY;
        this.configuration = config;
        this.hookLocation = hookLocation;
        this.unhookLocation = unhookLocation;
        this.blockTask();
    }

    @Override
    public void setHeaders(@NonNull final MissionTaskHeader headers) {
        this.headers = headers;
    }

    @Override
    public Set<MissionTaskDetail> getDetails() {
        return Collections.unmodifiableSet(details);
    }

    @SuppressWarnings("unused")
    private void setDetails(final Set<MissionTaskDetail> details) {
        this.details = details;
    }

    @Override
    protected boolean addDetailToCollection(final MissionTaskDetail detail) {
        return addChild(detail, details);
    }

    @Override
    protected boolean removeDetailFromCollection(final MissionTaskDetail detail) {
        return removeChild(detail, details);
    }

    @Override
    protected void checkLockUnlock() {
        //do nothing
    }

    @Override
    public void initConfiguration() {
        if (configuration != null) {
            setHeaders(configuration.getHeaders().clone());
        }
    }
    
    @Override
    public boolean checkCanActivate() {
        return TaskStatus.BLOCKED.equals(getStatus());
    }

    @Override
    public boolean activate() {
       try {
           makeExecutable();
           return true;
       }catch(Exception e) {
           return false;
       }
    }
    
    protected List<LoadingUnitReference> getLoadingUnitReferences() {
        return this.getDetails().stream().map(MissionTaskDetail::getLoadingUnitReference).collect(Collectors.toList());
    }

    @Override
    protected void updateVehicleInfo() {
        return;
    }
    
    public static List<MissionTask> findBy(final EntityManager em, final EntityReference vehicle) {
        return em.createNamedQuery(MissionTask.Q_FIND_BY_VEHICLE_REF, MissionTask.class)
                .setParameter(P_VEHICLE, vehicle)
                .getResultList();
    }

    public enum ActionStatus {
        READY, HOOKED, UNHOOKED;

        public boolean isReady() {
            return this == READY;
        }

        public boolean isHooked() {
            return this == HOOKED;
        }
        
        public boolean isUnhooked() {
            return this == UNHOOKED;
        }
    }

}

---------- End of ./MissionTask.java ----------

---------- Start of ./MissionTaskAssociateVehicleAction.java ----------
package eu.reply.lea.services.yms.task.mission;


import java.io.Serializable;

import javax.annotation.Nonnull;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;

import eu.reply.lea.services.yard.reference.SwitcherReference;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class MissionTaskAssociateVehicleAction implements Serializable {

	private static final long serialVersionUID = 6179043539084815640L;

	private SwitcherReference switcherReference;
    private String switcherCode;

    protected MissionTaskAssociateVehicleAction() {
        super();
    }

    public MissionTaskAssociateVehicleAction(final String switcherCode) {
        this.switcherCode = switcherCode;
    }

    public MissionTaskAssociateVehicleAction(@Nonnull final SwitcherReference switcherReference) {
        this.switcherReference = switcherReference;
    }

    @JsonIgnore
    public boolean isHookingVehicleDataMissing() {
        return switcherReference==null && StringUtils.isBlank(switcherCode);
    }

}

---------- End of ./MissionTaskAssociateVehicleAction.java ----------

Can you please suggest how to refactor the missiontaskprocessor? I don't want to do api calls to the yard in the middle of the transaction