/* * Copyright 2011 Marc Grue. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * * See the License for the specific language governing permissions and * limitations under the License. */ package org.qi4j.sample.dcicargo.sample_a.context.shipping.handling; import java.util.Arrays; import java.util.Date; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.This; import org.qi4j.api.mixin.Mixins; import org.qi4j.api.unitofwork.NoSuchEntityException; import org.qi4j.api.unitofwork.UnitOfWork; import org.qi4j.api.value.ValueBuilder; import org.qi4j.sample.dcicargo.sample_a.context.support.ApplicationEvents; import org.qi4j.sample.dcicargo.sample_a.context.support.RegisterHandlingEventAttemptDTO; import org.qi4j.sample.dcicargo.sample_a.data.entity.HandlingEventsEntity; import org.qi4j.sample.dcicargo.sample_a.data.shipping.cargo.Cargo; import org.qi4j.sample.dcicargo.sample_a.data.shipping.cargo.TrackingId; import org.qi4j.sample.dcicargo.sample_a.data.shipping.handling.HandlingEvent; import org.qi4j.sample.dcicargo.sample_a.data.shipping.handling.HandlingEventType; import org.qi4j.sample.dcicargo.sample_a.data.shipping.handling.HandlingEvents; import org.qi4j.sample.dcicargo.sample_a.data.shipping.location.Location; import org.qi4j.sample.dcicargo.sample_a.data.shipping.voyage.Voyage; import org.qi4j.sample.dcicargo.sample_a.infrastructure.dci.Context; import org.qi4j.sample.dcicargo.sample_a.infrastructure.dci.RoleMixin; import static org.qi4j.sample.dcicargo.sample_a.data.entity.HandlingEventsEntity.HANDLING_EVENTS_ID; /** * Register new handling event use case. * * The Cargo is updated synchronously in this implementation. */ public class RegisterHandlingEvent extends Context { // ROLES --------------------------------------------------------------------- private HandlingEventFactoryRole handlingEventFactory; private Date registrationTime; private Date completionTime; private String trackingIdString; private String eventTypeString; private String unLocodeString; private String voyageNumberString; // CONTEXT CONSTRUCTORS ------------------------------------------------------ public RegisterHandlingEvent( Date registrationTime, Date completionTime, String trackingIdString, String eventTypeString, String unLocodeString, String voyageNumberString ) { handlingEventFactory = rolePlayer( HandlingEventFactoryRole.class, HandlingEventsEntity.class, HANDLING_EVENTS_ID ); this.registrationTime = registrationTime; this.completionTime = completionTime; this.trackingIdString = trackingIdString; this.eventTypeString = eventTypeString; this.unLocodeString = unLocodeString; this.voyageNumberString = voyageNumberString; } // INTERACTIONS -------------------------------------------------------------- public void register() { handlingEventFactory.registerHandlingEvent(); } // METHODFUL ROLE IMPLEMENTATIONS -------------------------------------------- @Mixins( HandlingEventFactoryRole.Mixin.class ) public interface HandlingEventFactoryRole { void setContext( RegisterHandlingEvent context ); void registerHandlingEvent(); class Mixin extends RoleMixin<RegisterHandlingEvent> implements HandlingEventFactoryRole { @Service ApplicationEvents applicationEvents; @This HandlingEvents handlingEvents; // Handling event properties TrackingId trackingId; HandlingEventType handlingEventType; Location location; Voyage voyage; public void registerHandlingEvent() { RegisterHandlingEventAttemptDTO registrationAttempt = buildRegistrationAttempt(); // Step 1: Publish event stating that registration attempt has been received. applicationEvents.receivedHandlingEventRegistrationAttempt( registrationAttempt ); HandlingEvent handlingEvent = null; try { // Step 2: Verify existing data verifyExistingData(); // Step 3: Verify that received data can represent a valid handling event verifyValidData(); // Step 4: Create and save handling event handlingEvent = handlingEvents.createHandlingEvent( context.registrationTime, context.completionTime, trackingId, handlingEventType, location, voyage ); } catch( IllegalArgumentException e ) { // Deviation 2-5a: Publish event if registration is unsuccessful applicationEvents.unsuccessfulHandlingEventRegistration( registrationAttempt ); throw e; } // Step 5: Inspect cargo new InspectCargo( handlingEvent ).inspect(); // Step 6: Publish notification that cargo was successfully handled applicationEvents.cargoWasHandled( handlingEvent ); } private RegisterHandlingEventAttemptDTO buildRegistrationAttempt() { ValueBuilder<RegisterHandlingEventAttemptDTO> builder = vbf.newValueBuilder( RegisterHandlingEventAttemptDTO.class ); builder.prototype().registrationTime().set( context.registrationTime ); builder.prototype().completionTime().set( context.completionTime ); builder.prototype().trackingIdString().set( context.trackingIdString ); builder.prototype().eventTypeString().set( context.eventTypeString ); builder.prototype().unLocodeString().set( context.unLocodeString ); builder.prototype().voyageNumberString().set( context.voyageNumberString ); return builder.newInstance(); } private void verifyExistingData() { if( context.registrationTime == null ) { throw new IllegalArgumentException( "Registration time was null. All parameters have to be passed." ); } if( context.completionTime == null ) { throw new IllegalArgumentException( "Completion time was null. All parameters have to be passed." ); } context.trackingIdString = getClean( "Tracking id", context.trackingIdString ); context.eventTypeString = getClean( "Event type", context.eventTypeString ); context.unLocodeString = getClean( "UnLocode", context.unLocodeString ); // Voyage is optional } private String getClean( String parameter, String value ) { if( value == null ) { throw new IllegalArgumentException( parameter + " was null. All parameters have to be passed." ); } if( value.trim().length() == 0 ) { throw new IllegalArgumentException( parameter + " cannot be empty." ); } return value.trim(); } private void verifyValidData() { // Deviation 3a try { handlingEventType = HandlingEventType.valueOf( context.eventTypeString ); } catch( Exception e ) { throw new IllegalArgumentException( "'" + context.eventTypeString + "' is not a valid handling event type. Valid types are: " + Arrays.toString( HandlingEventType.values() ) ); } // Verifications against data store UnitOfWork uow = uowf.currentUnitOfWork(); // Deviation 3b try { // Will throw NoSuchEntityException if not found in store Cargo cargo = uow.get( Cargo.class, context.trackingIdString ); trackingId = cargo.trackingId().get(); // Deviation 3c if( cargo.itinerary().get() == null ) { throw new IllegalArgumentException( "Can't create handling event for non-routed cargo '" + context.trackingIdString + "'." ); } } catch( NoSuchEntityException e ) { throw new IllegalArgumentException( "Found no cargo with tracking id '" + context.trackingIdString + "'." ); } // Deviation 3d try { location = uow.get( Location.class, context.unLocodeString ); } catch( NoSuchEntityException e ) { throw new IllegalArgumentException( "Unknown location: " + context.unLocodeString ); } // Deviation 3e if( handlingEventType.requiresVoyage() ) { // Deviation 3e1a if( context.voyageNumberString == null ) { throw new IllegalArgumentException( "Handling event " + handlingEventType.toString() + " requires a voyage. No voyage number submitted." ); } // Deviation 3e1b try { voyage = uow.get( Voyage.class, context.voyageNumberString ); } catch( NoSuchEntityException e ) { throw new IllegalArgumentException( "Found no voyage with voyage number '" + context.voyageNumberString + "'." ); } } else { // Deviation 3f voyage = null; } } } } }