r361 - in trunk: sammoa-application/src/main/java/fr/ulr/sammoa/application sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/campaign sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/layer sammoa-ui-swing/src/main/java/fr/ulr/sammo
Author: fdesbois Date: 2012-08-07 17:49:18 +0200 (Tue, 07 Aug 2012) New Revision: 361 Url: http://forge.codelutin.com/repositories/revision/sammoa/361 Log: refs #1193 : move FlightController in proper package Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerUpdateListener.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightState.java Removed: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightController.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerDefault.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerUpdateListener.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightState.java Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/BaseHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/AddAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/BeginAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/EndAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/NextAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/ObservationAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/SammoaAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StartAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/campaign/CampaignUI.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/layer/TransectLayer.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/io/exportMap/ExportMapUI.jaxx trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java Deleted: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightController.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightController.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightController.java 2012-08-07 15:49:18 UTC (rev 361) @@ -1,285 +0,0 @@ -package fr.ulr.sammoa.application; -/* - * #%L - * SAMMOA :: Application - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2012 UMS 3462, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import fr.ulr.sammoa.application.device.DeviceTechnicalException; -import fr.ulr.sammoa.application.device.audio.AudioRecorder; -import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; -import fr.ulr.sammoa.application.device.gps.GpsConfig; -import fr.ulr.sammoa.application.device.gps.GpsHandler; -import fr.ulr.sammoa.persistence.GeoPoint; -import fr.ulr.sammoa.persistence.Observation; -import fr.ulr.sammoa.persistence.ObservationStatus; -import fr.ulr.sammoa.persistence.Position; -import fr.ulr.sammoa.persistence.Route; -import fr.ulr.sammoa.persistence.RouteType; -import fr.ulr.sammoa.persistence.TransectFlight; - -/** - * The FlightController is the main service used to do all actions during a - * flight. It is synchronized with the audio and GPS devices. It can be - * initialized with a flight that already started, the actions allowed depends on - * flight state. - * <p/> - * Created: 12/07/12 - * - * @author fdesbois <desbois@codelutin.com> - * @see FlightState - */ -public interface FlightController { - - /** - * @return the {@link FlightState} - */ - FlightState getState(); - - /** - * @return the {@link AudioRecorderDefault} used to save audio files - */ - AudioRecorder getAudioRecorder(); - - /** - * @return the {@link GpsHandler} used to retrieve GPS {@link GeoPoint} and - * save them. - */ - GpsHandler getGpsHandler(); - - /** - * @param config GpsConfig to initialize the Gps - * @exception fr.ulr.sammoa.application.device.DeviceTechnicalException if the gps device can't be opened properly - */ - void openGpsDevice(GpsConfig config) throws DeviceTechnicalException; - - /** - * @exception DeviceTechnicalException if the audio device can't be opened properly - */ - void openAudioDevice() throws DeviceTechnicalException; - - /** - * @return The current {@link Route} - */ - Route getCurrentRoute(); - - /** - * @return The next {@link TransectFlight} - */ - TransectFlight getNextTransect(); - - /** - * Initialize all data of FlightController depends on the current flight state. - * If the flight is running ({@link #isRunning()}), the devices will be started and - * recording if necessary. - * <p/> - * You must call init method to ensure the {@link FlightState}. - */ - void init(); - - /** - * Start operation. This will set the {@code beginDate} of the flight, then - * a new {@link RouteType#TRANSIT} route is created. The state is now - * {@link FlightState#OFF_EFFORT}. - * <p/> - * This operation is called when the plane take off, for the moment no - * observation is done and the audio is not recording. The GPS is enabled - * and will send data to display the plane tracking. - * <p/> - * After a start(), you can call : - * <ul> - * <li>{@link #begin()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #stop()}</li> - * </ul> - */ - void start(); - - /** - * Select a {@code nextTransect} to use for the next {@link RouteType#LEG} - * when {@link #begin()} method is called. - * - * @param nextTransect the TransectFlight to use as next one - */ - void setNextTransect(TransectFlight nextTransect); - - /** - * Begin operation. A new {@link RouteType#LEG} is created based on GPS - * current date and next transect that becomes the current one. The state - * is now {@link FlightState#ON_EFFORT}. - * <p/> - * This operation is called when the plane arrives on a transect and observation - * need to begin. Conditions could be set on the currentRoute (TRANSIT) and - * will be copied on the new LEG. This operation is also called when a - * CIRCLE_BACK is finished to resume effort on the current transect. - * <p/> - * After a begin(), you can call : - * <ul> - * <li>{@link #add()}</li> - * <li>{@link #circleBack(Observation)}</li> - * <li>{@link #next()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #end()}</li> - * <li>{@link #stop()}</li> - * </ul> - */ - void begin(); - - /** - * Circle Back operation. A new {@link RouteType#CIRCLE_BACK} is created - * based on GPS current date and attached to the {@code observation}. The - * next transect will be the current one to allow begin() to not change the - * transect. The state is now {@link FlightState#OFF_EFFORT}. - * <p/> - * This operation is called when an observation need to be checked again, - * the plane will do a circle back. In this case, we are not on effort - * anymore, but we can continue creating observations with the appropriate - * status. The {@code observation} is marked as {@link ObservationStatus#CIRCLE_BACK}. - * After the circle back, we use {@link #begin()} operation to continue effort - * with a new LEG. - * <p/> - * After a circleBack(), you can call : - * <ul> - * <li>circleBack(Observation)</li> - * <li>{@link #begin()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #stop()}</li> - * </ul> - * - * @param observation The observation cause of the circle back - * @see ObservationStatus - */ - void circleBack(Observation observation); - - /** - * Add operation. A new {@link RouteType#LEG} is created based on GPS current - * date and current transect. The next transect and state doesn't change. - * <p/> - * This operation is called when the observation conditions has changed, - * to mark this, a LEG is created with a GPS point and a new audio file. * - * <p/> - * After a add(), you can call : - * <ul> - * <li>add()</li> - * <li>{@link #circleBack(Observation)}</li> - * <li>{@link #next()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #end()}</li> - * <li>{@link #stop()}</li> - * </ul> - */ - void add(); - - /** - * Next operation. It's a shortcut to end the previous effort and begin the - * next one on the next transect. This will call {@link #end()} if necessary - * and then {@link #begin()}. - * <p/> - * After a next(), you can call : - * <ul> - * <li>add()</li> - * <li>{@link #circleBack(Observation)}</li> - * <li>{@link #next()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #end()}</li> - * <li>{@link #stop()}</li> - * </ul> - */ - void next(); - - /** - * Observation operation. It's the creation of an observation for the - * given {@code position}. The observer will be retrieved from the - * current route and the time is synchronized with the GPS or with the - * system if not responding. - * - * @param position Position of the observer that make the observation - */ - void observation(Position position); - - /** - * End operation. This will create a new {@link RouteType#TRANSIT} route and - * put the next transect depends on the plane list. The audio is still - * recording for a few minutes and the state becomes {@link FlightState#OFF_EFFORT} - * <p/> - * This operation is called when an effort/transect is finished. - * <p/> - * After a end(), you can call : - * <ul> - * <li>{@link #begin()}</li> - * <li>{@link #observation(Position)}</li> - * <li>{@link #stop()}</li> - * </ul> - */ - void end(); - - /** - * Stop operation. This will stop the flight (by creating the end date) and - * stop all devices (GPS and Audio). Current route and next transect are - * reset (set to null). The state becomes {@link FlightState#ENDED} - * <p/> - * This operation is called when the plane is landing. - * <p/> - * You can't do anything after a stop. - */ - void stop(); - - /** - * Close operation. This is used to close properly the controller even if - * the flight is not finished. - */ - void close(); - - /** - * @return true if {@link FlightState#WAITING} - */ - boolean isWaiting(); - - /** - * @return true if {@link FlightState#ENDED} - */ - boolean isEnded(); - - /** - * @return true if {@link FlightState#ON_EFFORT} - */ - boolean isOnEffort(); - - /** - * @return true if {@link FlightState#OFF_EFFORT} - */ - boolean isOffEffort(); - - /** - * @return true if {@link FlightState#OFF_EFFORT} or {@link FlightState#ON_EFFORT} - */ - boolean isRunning(); - - /** - * @param listener FlightControllerUpdateListener to add - */ - void addListener(FlightControllerUpdateListener listener); - - /** - * @param listener FlightControllerUpdateListener to remove - */ - void removeListener(FlightControllerUpdateListener listener); -} Deleted: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerDefault.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerDefault.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerDefault.java 2012-08-07 15:49:18 UTC (rev 361) @@ -1,879 +0,0 @@ -/* - * #%L - * SAMMOA :: Application - * * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2012 UMS 3462, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ -package fr.ulr.sammoa.application; - -import com.google.common.base.Preconditions; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; -import fr.ulr.sammoa.application.device.DeviceManager; -import fr.ulr.sammoa.application.device.DeviceStateListener; -import fr.ulr.sammoa.application.device.DeviceTechnicalException; -import fr.ulr.sammoa.application.device.audio.AudioRecorder; -import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; -import fr.ulr.sammoa.application.device.gps.GpsConfig; -import fr.ulr.sammoa.application.device.gps.GpsHandler; -import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; -import fr.ulr.sammoa.application.device.gps.GpsLocationListener; -import fr.ulr.sammoa.persistence.Flight; -import fr.ulr.sammoa.persistence.FlightDAO; -import fr.ulr.sammoa.persistence.GeoPoint; -import fr.ulr.sammoa.persistence.GeoPointDAO; -import fr.ulr.sammoa.persistence.Observation; -import fr.ulr.sammoa.persistence.ObservationDAO; -import fr.ulr.sammoa.persistence.ObservationStatus; -import fr.ulr.sammoa.persistence.ObserverPosition; -import fr.ulr.sammoa.persistence.Position; -import fr.ulr.sammoa.persistence.Route; -import fr.ulr.sammoa.persistence.RouteType; -import fr.ulr.sammoa.persistence.SammoaDAOHelper; -import fr.ulr.sammoa.persistence.SammoaPersistence; -import fr.ulr.sammoa.persistence.TransectFlight; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.TopiaRuntimeException; -import org.nuiton.util.TimeLog; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Date; -import java.util.Set; - -/** - * Created: 11/06/12 - * - * @author fdesbois <desbois@codelutin.com> - */ -public class FlightControllerDefault implements GpsLocationListener, FlightController { - - private static final Logger logger = LoggerFactory.getLogger(FlightControllerDefault.class); - - private static final TimeLog timeLog = new TimeLog(FlightControllerDefault.class, 500, 1000); - - protected SammoaContext context; - - protected SammoaPersistence persistence; - - protected FlightService service; - - protected AudioRecorder audioRecorder; - - protected GpsHandler gpsHandler; - - protected boolean initialized; - - protected FlightState state; - - protected Flight flight; - - protected Route currentRoute; - - protected TransectFlight nextTransect; - - protected TransectFlight lastTransect; - - protected Set<FlightControllerUpdateListener> listeners; - - public FlightControllerDefault(SammoaContext context, - Flight flight) { - - this.context = context; - this.flight = flight; - - this.persistence = context.getPersistence(); - this.service = context.getFlightService(); - - this.currentRoute = service.getLastRoute(flight); - this.lastTransect = service.getLastTransectDone(flight); - this.listeners = Sets.newHashSet(); - } - - @Override - public void addListener(FlightControllerUpdateListener listener) { - listeners.add(listener); - } - - @Override - public void removeListener(FlightControllerUpdateListener listener) { - listeners.remove(listener); - } - - @Override - public FlightState getState() { - return state; - } - - @Override - public AudioRecorder getAudioRecorder() { - return audioRecorder; - } - - @Override - public Route getCurrentRoute() { - return currentRoute; - } - - @Override - public TransectFlight getNextTransect() { - return nextTransect; - } - - @Override - public GpsHandler getGpsHandler() { - return gpsHandler; - } - - @Override - public void openGpsDevice(final GpsConfig config) throws DeviceTechnicalException { - - Set<GpsLocationListener> locationListeners; - if (gpsHandler != null) { - - // Remove all existing listeners and keep them for the new instance - locationListeners = Sets.newHashSet(gpsHandler.getGpsLocationListeners()); - for (GpsLocationListener listener : locationListeners) { - gpsHandler.removeGpsLocationListener(listener); - } - - } else { - locationListeners = Sets.newHashSet(); - } - - gpsHandler = newDeviceManager(gpsHandler, new Supplier<GpsHandler>() { - - @Override - public GpsHandler get() { - - // Instanciate the GpsHandler - Class<? extends GpsHandler> gpsHandlerClass = config.getGpsHandlerClass(); - try { - - Constructor<? extends GpsHandler> constructor = - gpsHandlerClass.getConstructor(GpsConfig.class); - - GpsHandler result = constructor.newInstance(config); - result.addGpsLocationListener(FlightControllerDefault.this); - return result; - - } catch (InstantiationException e) { - throw Throwables.propagate(e); - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } catch (NoSuchMethodException e) { - throw Throwables.propagate(e); - } catch (InvocationTargetException e) { - throw Throwables.propagate(e); - } - } - }); - - for (GpsLocationListener listener : locationListeners) { - gpsHandler.addGpsLocationListener(listener); - } - - if (initialized && isRunning()) { - gpsHandler.start(); - } else { - gpsHandler.open(); - } - } - - @Override - public void openAudioDevice() throws DeviceTechnicalException { - - audioRecorder = newDeviceManager(audioRecorder, new Supplier<AudioRecorder>() { - - @Override - public AudioRecorder get() { - return new AudioRecorderDefault(); - } - }); - - if (initialized && isRunning()) { - audioRecorder.start(); - } else { - audioRecorder.open(); - } - } - - @Override - public boolean isWaiting() { - return state == FlightState.WAITING; - } - - @Override - public boolean isEnded() { - return state == FlightState.ENDED; - } - - @Override - public boolean isOnEffort() { - return state == FlightState.ON_EFFORT; - } - - @Override - public boolean isOffEffort() { - return state == FlightState.OFF_EFFORT; - } - - @Override - public boolean isRunning() { - return isOnEffort() || isOffEffort(); - } - - @Override - public void init() { - - Preconditions.checkState(gpsHandler != null, - "The GpsHandler must be created using #openGpsDevice"); - - Preconditions.checkState(audioRecorder != null, - "The AudioRecorder must be created using #openAudioDevice"); - - if (initialized) { - if (logger.isWarnEnabled()) { - logger.warn("The FlightController is already initialized"); - } - return; - } - - if (logger.isInfoEnabled()) { - logger.info("Initialize the FlightController for flight " + flight.getFlightNumber()); - } - - initialized = true; - - // Note that a flight can't finished by a leg, so effort not null - // implies that the flight is started and not ended - if (currentRoute != null - && currentRoute.getRouteType() == RouteType.LEG) { - - state = FlightState.ON_EFFORT; - - } else if (currentRoute != null - && flight.getBeginDate() != null - && flight.getEndDate() == null) { - - state = FlightState.OFF_EFFORT; - - } else if (flight.getEndDate() != null) { - - state = FlightState.ENDED; - - } else { - state = FlightState.WAITING; - } - - if (isRunning()) { - - gpsHandler.start(); - - audioRecorder.start(); - - // Selection of the nextTransect, keep the last one for circleBack - if (currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { - nextTransect = lastTransect; - - } else { - nextTransect = flight.getNextTransectFlightFrom(lastTransect); - } - - // Restart recording audio if onEffort or circleBack - if (state == FlightState.ON_EFFORT - || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { - - saveAudio(0); - } - } - } - - @Override - public void start() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isWaiting(), "You can call start() only if flight is waiting (not started, not ended)"); - - gpsHandler.start(); - - audioRecorder.start(); - - TopiaContext transaction = persistence.beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - setFlightBeginDate(transaction, flight, currentDate); - - if (logger.isInfoEnabled()) { - logger.info("Start Flight {} at {}", flight.getFlightNumber(), flight.getBeginDate()); - } - - // Start with TRANSIT route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create TRANSIT [START] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); - - // Auto selection of the next transect starting from the begining - nextTransect = flight.getNextTransectFlightFrom(null); - - state = FlightState.OFF_EFFORT; - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "start()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "start()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void setNextTransect(TransectFlight nextTransect) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - nextTransect == null || !nextTransect.isDeleted(), "You can't use a deleted transect as next value"); - - this.nextTransect = nextTransect; - - // Fire transect changed - fireNextTransectChanged(nextTransect); - - timeLog.log(startTime, "setNextTransect()", "Fired"); - } - - @Override - public void begin() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOffEffort(), "You can call begin() only if flight is running (started, not ended, not on effort)"); - - Preconditions.checkState( - nextTransect != null, "You can't call begin() if no transect is selected. " + - "Call setNextTransect() method first"); - - TopiaContext transaction = persistence.beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // The next transect becomes the last one (or current in this case) - lastTransect = nextTransect; - - // Create new LEG route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create LEG [BEGIN] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); - - // automatic selection of the next transect - nextTransect = flight.getNextTransectFlightFrom(lastTransect); - - state = FlightState.ON_EFFORT; - - // Record the audio for the current LEG - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "begin()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "begin()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void circleBack(Observation observation) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - currentRoute != null - && currentRoute.getRouteType() != RouteType.TRANSIT, - "You can't call circleBack() during TRANSIT"); - - - TopiaContext transaction = persistence.beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - setObservationStatus(transaction, observation, ObservationStatus.CIRCLE_BACK); - - // Create CIRCLE_BACK - if (logger.isInfoEnabled()) { - logger.info(String.format("Create CIRCLE_BACK at %1$tH:%1$tM:%1$tS", currentDate)); - } - - currentRoute = service.createCircleBack(transaction, flight, currentDate, currentRoute, observation); - - nextTransect = lastTransect; - - state = FlightState.OFF_EFFORT; - - // Record the audio of the LEG in an other file - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "circleBack()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "circleBack()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void add() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOnEffort(), "You can call add() only if flight is on effort (started, not ended, on effort)"); - - TopiaContext transaction = persistence.beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // Create new LEG route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create LEG [ADD] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); - - // Record the audio of the LEG in an other file - saveAudio(3); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "add()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - - timeLog.log(startTime, "add()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void next() { - - long startTime = TimeLog.getTime(); - - if (isOnEffort()) { - doEndWithAudioDelay(3); - } - - begin(); - - timeLog.log(startTime, "next()"); - } - - @Override - public void observation(Position position) { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isRunning(), "You can call observation() only if flight is running (started, not ended)"); - - TopiaContext transaction = persistence.beginTransaction(); - try { - - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - ObserverPosition observer; - if (currentRoute == null) { - - // problem we don't have any observerPosition - observer = null; - - } else { - observer = currentRoute.getObserverPositionByPosition(position); - } - - if (logger.isInfoEnabled()) { - logger.info(String.format("Create Observation %2$s at %1$tH:%1$tM:%1$tS (observer = %3$s)", - currentDate, - position, - observer != null && observer.getObserver() != null - ? observer.getObserver().getInitials() : "") - ); - } - Observation observation = service.createObservation(transaction, flight, currentDate, observer); - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "observation()", "Commited"); - - for (FlightControllerUpdateListener listener : listeners) { - listener.onObservationAdded(observation); - } - - timeLog.log(startTime, "observation()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void end() { - - long startTime = TimeLog.getTime(); - - // Stop recording after 2 minutes (120 seconds) - doEndWithAudioDelay(120); - - timeLog.log(startTime, "end()"); - } - - @Override - public void stop() { - - long startTime = TimeLog.getTime(); - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOffEffort(), "You can call stop() only if flight is running (started, not ended, not on effort)"); - - TopiaContext transaction = persistence.beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - if (logger.isInfoEnabled()) { - logger.info(String.format("Stop flight %2$d at %1$tH:%1$tM:%1$tS", - currentDate, - flight.getFlightNumber()) - ); - } - setFlightEndDate(transaction, flight, currentDate); - - // Stop audio - getAudioRecorder().stop(); - - // Stop gps - getGpsHandler().stop(); - - currentRoute = null; - - nextTransect = null; - - state = FlightState.ENDED; - - transaction.commitTransaction(); - - startTime = timeLog.log(startTime, "stop()", "Commited"); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - timeLog.log(startTime, "stop()", "Fired"); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - - @Override - public void close() { - - audioRecorder.close(); - audioRecorder = null; - - gpsHandler.close(); - gpsHandler = null; - - persistence.stopAutoSaveListener(); - } - - protected void doEndWithAudioDelay(long audioDelay) { - - Preconditions.checkState(initialized, - "The controller must be initialized before calling any action"); - - Preconditions.checkState( - isOnEffort(), "You can call end() only if flight is on effort (started, not ended, on effort)"); - - TopiaContext transaction = persistence.beginTransaction(); - try { - Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); - - // Create new TRANSIT route - if (logger.isInfoEnabled()) { - logger.info(String.format("Create TRANSIT [END] at %1$tH:%1$tM:%1$tS", currentDate)); - } - currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); - - audioRecorder.stopRecord(audioDelay); - - state = FlightState.OFF_EFFORT; - - transaction.commitTransaction(); - - // Fire events after commit - fireRouteAdded(currentRoute); - fireNextTransectChanged(nextTransect); - fireStateChanged(state); - - } catch (TopiaException e) { - throw new TopiaRuntimeException(e); - - } finally { - persistence.endTransaction(transaction); - } - } - -// protected void setNextTransect(TransectFlight nextTransect, boolean fireEvents) { -// -// this.nextTransect = nextTransect; -// -// if (fireEvents) { -// // Fire transect changed -// for (FlightControllerUpdateListener listener : listeners) { -// listener.onNextTransectChanged(nextTransect); -// } -// } -// } -// -// protected void setNextTransectFrom(TransectFlight transect, boolean fireEvents) { -// -// TransectFlight nextTransect = -// flight.getNextTransectFlightFrom(transect); -// -// setNextTransect(nextTransect, fireEvents); -// } - - protected void setFlightBeginDate(TopiaContext transaction, - Flight flight, - Date beginDate) - throws TopiaException { - - FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); - flight.setBeginDate(beginDate); - flightDAO.update(flight); - } - - protected void setFlightEndDate(TopiaContext transaction, - Flight flight, - Date endDate) - throws TopiaException { - - FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); - flight.setEndDate(endDate); - flightDAO.update(flight); - } - - protected void setObservationStatus(TopiaContext transaction, - Observation observation, - ObservationStatus status) - throws TopiaException { - - ObservationDAO observationDAO = - SammoaDAOHelper.getObservationDAO(transaction); - observation.setObservationStatus(status); - observationDAO.update(observation); - } - - protected void saveAudio(long delay) { - - String fileName = String.format( - "%1$tF-%1$tH-%1$tM-%1$tS.%2$s.%3$s", - currentRoute.getBeginTime(), - currentRoute.getTopiaId(), - getAudioRecorder().getOutputType().getExtension() - ); - - File audioDir = context.getConfig().getAudioDirectory(); - - File audioFile = new File(audioDir, fileName); - - try { - getAudioRecorder().record(audioFile, delay); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } - - protected Date saveGPS(TopiaContext transaction, - GeoPoint geoPoint, - Flight flight) - throws TopiaException { - - Date result; - if (geoPoint == null) { - result = new Date(); - if (logger.isWarnEnabled()) { - logger.warn("No GPS point at {}", result); - } - - } else { - - if (logger.isTraceEnabled()) { - logger.trace("Create GPS Point : {}", geoPoint); - } - - result = geoPoint.getRecordTime(); - - GeoPointDAO dao = SammoaDAOHelper.getGeoPointDAO(transaction); - - geoPoint.setFlight(flight); - - dao.create(geoPoint); - } - return result; - } - - protected void fireStateChanged(FlightState state) { - for (FlightControllerUpdateListener listener : listeners) { - listener.onStateChanged(state); - } - } - - protected void fireRouteAdded(Route route) { - for (FlightControllerUpdateListener listener : listeners) { - listener.onRouteAdded(route); - } - } - - protected void fireNextTransectChanged(TransectFlight nextTransect) { - for (FlightControllerUpdateListener listener : listeners) { - listener.onNextTransectChanged(nextTransect); - } - } - - protected <T extends DeviceManager> T newDeviceManager(T oldInstance, Supplier<T> supplier) - throws DeviceTechnicalException { - - Set<DeviceStateListener> stateListeners; - if (oldInstance != null) { - - // Remove all existing listeners and keep them for the new instance - stateListeners = Sets.newHashSet(oldInstance.getDeviceStateListeners()); - for (DeviceStateListener listener : stateListeners) { - oldInstance.removeDeviceStateListener(listener); - } - - oldInstance.close(); - - } else { - stateListeners = Sets.newHashSet(); - } - - T result = supplier.get(); - - // Attach all updateListener - for (DeviceStateListener listener : stateListeners) { - result.addDeviceStateListener(listener); - } - - return result; - } - - @Override - public void locationChanged(GpsLocationEvent event) { - GeoPoint newLocation = event.getNewValue(); - if (newLocation != null/* && newLocation.getTopiaId() == null*/) { - newLocation.setFlight(flight); - persistence.delayEntityCreation(newLocation); - } - } - -} Deleted: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerUpdateListener.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerUpdateListener.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerUpdateListener.java 2012-08-07 15:49:18 UTC (rev 361) @@ -1,69 +0,0 @@ -package fr.ulr.sammoa.application; -/* - * #%L - * SAMMOA :: Application - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2012 UMS 3462, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import fr.ulr.sammoa.persistence.Observation; -import fr.ulr.sammoa.persistence.Route; -import fr.ulr.sammoa.persistence.TransectFlight; - -/** - * Listener for all change of data in the {@link FlightController} - * - * Created: 12/07/12 - * - * @author fdesbois <desbois@codelutin.com> - * @see FlightController - */ -public interface FlightControllerUpdateListener { - - /** - * Fired when a new {@code route} has been created and added to the flight - * - * @param route The new route added - */ - void onRouteAdded(Route route); - - /** - * Fired when the next transect has been updated. - * - * @param nextTransect The next transect that will be used on - * {@link FlightController#begin()} action - */ - void onNextTransectChanged(TransectFlight nextTransect); - - /** - * Fired when controller change the {@code state} of the flight after - * each action. - * - * @param state The new state - */ - void onStateChanged(FlightState state); - - /** - * Fired when controller add a new observation - * - * @param observation The new observation - */ - void onObservationAdded(Observation observation); -} Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-07 15:49:18 UTC (rev 361) @@ -506,10 +506,10 @@ return result; } - protected Observation createObservation(TopiaContext transaction, - Flight flight, - Date beginTime, - ObserverPosition observer) + public Observation createObservation(TopiaContext transaction, + Flight flight, + Date beginTime, + ObserverPosition observer) throws TopiaException { Observation result; @@ -525,22 +525,22 @@ return result; } - - protected Route createTransit(TopiaContext transaction, - Flight flight, - Date beginTime, - Route previousRoute) + + public Route createTransit(TopiaContext transaction, + Flight flight, + Date beginTime, + Route previousRoute) throws TopiaException { Route result = createRoute(transaction, flight, beginTime, RouteType.TRANSIT, previousRoute, null); return result; } - protected Route createLeg(TopiaContext transaction, - Flight flight, - Date beginTime, - Route previousRoute, - TransectFlight transectFlight) + public Route createLeg(TopiaContext transaction, + Flight flight, + Date beginTime, + Route previousRoute, + TransectFlight transectFlight) throws TopiaException { Preconditions.checkArgument(transectFlight != null, "You can't create a leg without any transect"); @@ -557,11 +557,11 @@ return result; } - protected Route createCircleBack(TopiaContext transaction, - Flight flight, - Date beginTime, - Route previousRoute, - Observation circleBackCause) + public Route createCircleBack(TopiaContext transaction, + Flight flight, + Date beginTime, + Route previousRoute, + Observation circleBackCause) throws TopiaException { Preconditions.checkArgument(circleBackCause != null, "You can't create a route without any observation cause"); Deleted: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightState.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightState.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightState.java 2012-08-07 15:49:18 UTC (rev 361) @@ -1,57 +0,0 @@ -/* - * #%L - * SAMMOA :: Application - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2012 UMS 3462, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ -package fr.ulr.sammoa.application; - -/** - * Created: 20/06/12 - * - * @author fdesbois <desbois@codelutin.com> - */ -public enum FlightState { - /** - * The WAITING state is when the flight is not started and not ended. - * It appends when the flight is not really in used. - */ - WAITING, - - /** - * The OFF_EFFORT state is when the flight is started but not ended, - * and also if the current route is not an effort. - * It appends generally when the flight is in TRANSIT or CIRCLE_BACK. - */ - OFF_EFFORT, - - /** - * The ON_EFFORT state is when the flight is started, not ended but in - * current effort. It appends when a LEG is currently in progress. - */ - ON_EFFORT, - - /** - * The ENDED state is when the flight is ended. - * It appends when the current effort is finished and when no more route - * need to be registered. - */ - ENDED -} Copied: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java (from rev 360, trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightController.java) =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java 2012-08-07 15:49:18 UTC (rev 361) @@ -0,0 +1,285 @@ +package fr.ulr.sammoa.application.flightController; +/* + * #%L + * SAMMOA :: Application + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import fr.ulr.sammoa.application.device.DeviceTechnicalException; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; +import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; +import fr.ulr.sammoa.application.device.gps.GpsConfig; +import fr.ulr.sammoa.application.device.gps.GpsHandler; +import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.Observation; +import fr.ulr.sammoa.persistence.ObservationStatus; +import fr.ulr.sammoa.persistence.Position; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.RouteType; +import fr.ulr.sammoa.persistence.TransectFlight; + +/** + * The FlightController is the main service used to do all actions during a + * flight. It is synchronized with the audio and GPS devices. It can be + * initialized with a flight that already started, the actions allowed depends on + * flight state. + * <p/> + * Created: 12/07/12 + * + * @author fdesbois <desbois@codelutin.com> + * @see FlightState + */ +public interface FlightController { + + /** + * @return the {@link FlightState} + */ + FlightState getState(); + + /** + * @return the {@link AudioRecorderDefault} used to save audio files + */ + AudioRecorder getAudioRecorder(); + + /** + * @return the {@link GpsHandler} used to retrieve GPS {@link GeoPoint} and + * save them. + */ + GpsHandler getGpsHandler(); + + /** + * @param config GpsConfig to initialize the Gps + * @exception fr.ulr.sammoa.application.device.DeviceTechnicalException if the gps device can't be opened properly + */ + void openGpsDevice(GpsConfig config) throws DeviceTechnicalException; + + /** + * @exception DeviceTechnicalException if the audio device can't be opened properly + */ + void openAudioDevice() throws DeviceTechnicalException; + + /** + * @return The current {@link Route} + */ + Route getCurrentRoute(); + + /** + * @return The next {@link TransectFlight} + */ + TransectFlight getNextTransect(); + + /** + * Initialize all data of FlightController depends on the current flight state. + * If the flight is running ({@link #isRunning()}), the devices will be started and + * recording if necessary. + * <p/> + * You must call init method to ensure the {@link FlightState}. + */ + void init(); + + /** + * Start operation. This will set the {@code beginDate} of the flight, then + * a new {@link RouteType#TRANSIT} route is created. The state is now + * {@link FlightState#OFF_EFFORT}. + * <p/> + * This operation is called when the plane take off, for the moment no + * observation is done and the audio is not recording. The GPS is enabled + * and will send data to display the plane tracking. + * <p/> + * After a start(), you can call : + * <ul> + * <li>{@link #begin()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #stop()}</li> + * </ul> + */ + void start(); + + /** + * Select a {@code nextTransect} to use for the next {@link RouteType#LEG} + * when {@link #begin()} method is called. + * + * @param nextTransect the TransectFlight to use as next one + */ + void setNextTransect(TransectFlight nextTransect); + + /** + * Begin operation. A new {@link RouteType#LEG} is created based on GPS + * current date and next transect that becomes the current one. The state + * is now {@link FlightState#ON_EFFORT}. + * <p/> + * This operation is called when the plane arrives on a transect and observation + * need to begin. Conditions could be set on the currentRoute (TRANSIT) and + * will be copied on the new LEG. This operation is also called when a + * CIRCLE_BACK is finished to resume effort on the current transect. + * <p/> + * After a begin(), you can call : + * <ul> + * <li>{@link #add()}</li> + * <li>{@link #circleBack(Observation)}</li> + * <li>{@link #next()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #end()}</li> + * <li>{@link #stop()}</li> + * </ul> + */ + void begin(); + + /** + * Circle Back operation. A new {@link RouteType#CIRCLE_BACK} is created + * based on GPS current date and attached to the {@code observation}. The + * next transect will be the current one to allow begin() to not change the + * transect. The state is now {@link FlightState#OFF_EFFORT}. + * <p/> + * This operation is called when an observation need to be checked again, + * the plane will do a circle back. In this case, we are not on effort + * anymore, but we can continue creating observations with the appropriate + * status. The {@code observation} is marked as {@link ObservationStatus#CIRCLE_BACK}. + * After the circle back, we use {@link #begin()} operation to continue effort + * with a new LEG. + * <p/> + * After a circleBack(), you can call : + * <ul> + * <li>circleBack(Observation)</li> + * <li>{@link #begin()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #stop()}</li> + * </ul> + * + * @param observation The observation cause of the circle back + * @see ObservationStatus + */ + void circleBack(Observation observation); + + /** + * Add operation. A new {@link RouteType#LEG} is created based on GPS current + * date and current transect. The next transect and state doesn't change. + * <p/> + * This operation is called when the observation conditions has changed, + * to mark this, a LEG is created with a GPS point and a new audio file. * + * <p/> + * After a add(), you can call : + * <ul> + * <li>add()</li> + * <li>{@link #circleBack(Observation)}</li> + * <li>{@link #next()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #end()}</li> + * <li>{@link #stop()}</li> + * </ul> + */ + void add(); + + /** + * Next operation. It's a shortcut to end the previous effort and begin the + * next one on the next transect. This will call {@link #end()} if necessary + * and then {@link #begin()}. + * <p/> + * After a next(), you can call : + * <ul> + * <li>add()</li> + * <li>{@link #circleBack(Observation)}</li> + * <li>{@link #next()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #end()}</li> + * <li>{@link #stop()}</li> + * </ul> + */ + void next(); + + /** + * Observation operation. It's the creation of an observation for the + * given {@code position}. The observer will be retrieved from the + * current route and the time is synchronized with the GPS or with the + * system if not responding. + * + * @param position Position of the observer that make the observation + */ + void observation(Position position); + + /** + * End operation. This will create a new {@link RouteType#TRANSIT} route and + * put the next transect depends on the plane list. The audio is still + * recording for a few minutes and the state becomes {@link FlightState#OFF_EFFORT} + * <p/> + * This operation is called when an effort/transect is finished. + * <p/> + * After a end(), you can call : + * <ul> + * <li>{@link #begin()}</li> + * <li>{@link #observation(Position)}</li> + * <li>{@link #stop()}</li> + * </ul> + */ + void end(); + + /** + * Stop operation. This will stop the flight (by creating the end date) and + * stop all devices (GPS and Audio). Current route and next transect are + * reset (set to null). The state becomes {@link FlightState#ENDED} + * <p/> + * This operation is called when the plane is landing. + * <p/> + * You can't do anything after a stop. + */ + void stop(); + + /** + * Close operation. This is used to close properly the controller even if + * the flight is not finished. + */ + void close(); + + /** + * @return true if {@link FlightState#WAITING} + */ + boolean isWaiting(); + + /** + * @return true if {@link FlightState#ENDED} + */ + boolean isEnded(); + + /** + * @return true if {@link FlightState#ON_EFFORT} + */ + boolean isOnEffort(); + + /** + * @return true if {@link FlightState#OFF_EFFORT} + */ + boolean isOffEffort(); + + /** + * @return true if {@link FlightState#OFF_EFFORT} or {@link FlightState#ON_EFFORT} + */ + boolean isRunning(); + + /** + * @param listener FlightControllerUpdateListener to add + */ + void addListener(FlightControllerUpdateListener listener); + + /** + * @param listener FlightControllerUpdateListener to remove + */ + void removeListener(FlightControllerUpdateListener listener); +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightController.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Copied: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java (from rev 360, trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerDefault.java) =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java 2012-08-07 15:49:18 UTC (rev 361) @@ -0,0 +1,881 @@ +/* + * #%L + * SAMMOA :: Application + * * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ +package fr.ulr.sammoa.application.flightController; + +import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.collect.Sets; +import fr.ulr.sammoa.application.FlightService; +import fr.ulr.sammoa.application.SammoaContext; +import fr.ulr.sammoa.application.device.DeviceManager; +import fr.ulr.sammoa.application.device.DeviceStateListener; +import fr.ulr.sammoa.application.device.DeviceTechnicalException; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; +import fr.ulr.sammoa.application.device.audio.AudioRecorderDefault; +import fr.ulr.sammoa.application.device.gps.GpsConfig; +import fr.ulr.sammoa.application.device.gps.GpsHandler; +import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; +import fr.ulr.sammoa.application.device.gps.GpsLocationListener; +import fr.ulr.sammoa.persistence.Flight; +import fr.ulr.sammoa.persistence.FlightDAO; +import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.GeoPointDAO; +import fr.ulr.sammoa.persistence.Observation; +import fr.ulr.sammoa.persistence.ObservationDAO; +import fr.ulr.sammoa.persistence.ObservationStatus; +import fr.ulr.sammoa.persistence.ObserverPosition; +import fr.ulr.sammoa.persistence.Position; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.RouteType; +import fr.ulr.sammoa.persistence.SammoaDAOHelper; +import fr.ulr.sammoa.persistence.SammoaPersistence; +import fr.ulr.sammoa.persistence.TransectFlight; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.TopiaRuntimeException; +import org.nuiton.util.TimeLog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Date; +import java.util.Set; + +/** + * Created: 11/06/12 + * + * @author fdesbois <desbois@codelutin.com> + */ +public class FlightControllerDefault implements GpsLocationListener, FlightController { + + private static final Logger logger = LoggerFactory.getLogger(FlightControllerDefault.class); + + private static final TimeLog timeLog = new TimeLog(FlightControllerDefault.class, 500, 1000); + + protected SammoaContext context; + + protected SammoaPersistence persistence; + + protected FlightService service; + + protected AudioRecorder audioRecorder; + + protected GpsHandler gpsHandler; + + protected boolean initialized; + + protected FlightState state; + + protected Flight flight; + + protected Route currentRoute; + + protected TransectFlight nextTransect; + + protected TransectFlight lastTransect; + + protected Set<FlightControllerUpdateListener> listeners; + + public FlightControllerDefault(SammoaContext context, + Flight flight) { + + this.context = context; + this.flight = flight; + + this.persistence = context.getPersistence(); + this.service = context.getFlightService(); + + this.currentRoute = service.getLastRoute(flight); + this.lastTransect = service.getLastTransectDone(flight); + this.listeners = Sets.newHashSet(); + } + + @Override + public void addListener(FlightControllerUpdateListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(FlightControllerUpdateListener listener) { + listeners.remove(listener); + } + + @Override + public FlightState getState() { + return state; + } + + @Override + public AudioRecorder getAudioRecorder() { + return audioRecorder; + } + + @Override + public Route getCurrentRoute() { + return currentRoute; + } + + @Override + public TransectFlight getNextTransect() { + return nextTransect; + } + + @Override + public GpsHandler getGpsHandler() { + return gpsHandler; + } + + @Override + public void openGpsDevice(final GpsConfig config) throws DeviceTechnicalException { + + Set<GpsLocationListener> locationListeners; + if (gpsHandler != null) { + + // Remove all existing listeners and keep them for the new instance + locationListeners = Sets.newHashSet(gpsHandler.getGpsLocationListeners()); + for (GpsLocationListener listener : locationListeners) { + gpsHandler.removeGpsLocationListener(listener); + } + + } else { + locationListeners = Sets.newHashSet(); + } + + gpsHandler = newDeviceManager(gpsHandler, new Supplier<GpsHandler>() { + + @Override + public GpsHandler get() { + + // Instanciate the GpsHandler + Class<? extends GpsHandler> gpsHandlerClass = config.getGpsHandlerClass(); + try { + + Constructor<? extends GpsHandler> constructor = + gpsHandlerClass.getConstructor(GpsConfig.class); + + GpsHandler result = constructor.newInstance(config); + result.addGpsLocationListener(FlightControllerDefault.this); + return result; + + } catch (InstantiationException e) { + throw Throwables.propagate(e); + } catch (IllegalAccessException e) { + throw Throwables.propagate(e); + } catch (NoSuchMethodException e) { + throw Throwables.propagate(e); + } catch (InvocationTargetException e) { + throw Throwables.propagate(e); + } + } + }); + + for (GpsLocationListener listener : locationListeners) { + gpsHandler.addGpsLocationListener(listener); + } + + if (initialized && isRunning()) { + gpsHandler.start(); + } else { + gpsHandler.open(); + } + } + + @Override + public void openAudioDevice() throws DeviceTechnicalException { + + audioRecorder = newDeviceManager(audioRecorder, new Supplier<AudioRecorder>() { + + @Override + public AudioRecorder get() { + return new AudioRecorderDefault(); + } + }); + + if (initialized && isRunning()) { + audioRecorder.start(); + } else { + audioRecorder.open(); + } + } + + @Override + public boolean isWaiting() { + return state == FlightState.WAITING; + } + + @Override + public boolean isEnded() { + return state == FlightState.ENDED; + } + + @Override + public boolean isOnEffort() { + return state == FlightState.ON_EFFORT; + } + + @Override + public boolean isOffEffort() { + return state == FlightState.OFF_EFFORT; + } + + @Override + public boolean isRunning() { + return isOnEffort() || isOffEffort(); + } + + @Override + public void init() { + + Preconditions.checkState(gpsHandler != null, + "The GpsHandler must be created using #openGpsDevice"); + + Preconditions.checkState(audioRecorder != null, + "The AudioRecorder must be created using #openAudioDevice"); + + if (initialized) { + if (logger.isWarnEnabled()) { + logger.warn("The FlightController is already initialized"); + } + return; + } + + if (logger.isInfoEnabled()) { + logger.info("Initialize the FlightController for flight " + flight.getFlightNumber()); + } + + initialized = true; + + // Note that a flight can't finished by a leg, so effort not null + // implies that the flight is started and not ended + if (currentRoute != null + && currentRoute.getRouteType() == RouteType.LEG) { + + state = FlightState.ON_EFFORT; + + } else if (currentRoute != null + && flight.getBeginDate() != null + && flight.getEndDate() == null) { + + state = FlightState.OFF_EFFORT; + + } else if (flight.getEndDate() != null) { + + state = FlightState.ENDED; + + } else { + state = FlightState.WAITING; + } + + if (isRunning()) { + + gpsHandler.start(); + + audioRecorder.start(); + + // Selection of the nextTransect, keep the last one for circleBack + if (currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { + nextTransect = lastTransect; + + } else { + nextTransect = flight.getNextTransectFlightFrom(lastTransect); + } + + // Restart recording audio if onEffort or circleBack + if (state == FlightState.ON_EFFORT + || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { + + saveAudio(0); + } + } + } + + @Override + public void start() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isWaiting(), "You can call start() only if flight is waiting (not started, not ended)"); + + gpsHandler.start(); + + audioRecorder.start(); + + TopiaContext transaction = persistence.beginTransaction(); + try { + + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + setFlightBeginDate(transaction, flight, currentDate); + + if (logger.isInfoEnabled()) { + logger.info("Start Flight {} at {}", flight.getFlightNumber(), flight.getBeginDate()); + } + + // Start with TRANSIT route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create TRANSIT [START] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); + + // Auto selection of the next transect starting from the begining + nextTransect = flight.getNextTransectFlightFrom(null); + + state = FlightState.OFF_EFFORT; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "start()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "start()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void setNextTransect(TransectFlight nextTransect) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + nextTransect == null || !nextTransect.isDeleted(), "You can't use a deleted transect as next value"); + + this.nextTransect = nextTransect; + + // Fire transect changed + fireNextTransectChanged(nextTransect); + + timeLog.log(startTime, "setNextTransect()", "Fired"); + } + + @Override + public void begin() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOffEffort(), "You can call begin() only if flight is running (started, not ended, not on effort)"); + + Preconditions.checkState( + nextTransect != null, "You can't call begin() if no transect is selected. " + + "Call setNextTransect() method first"); + + TopiaContext transaction = persistence.beginTransaction(); + try { + + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + // The next transect becomes the last one (or current in this case) + lastTransect = nextTransect; + + // Create new LEG route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create LEG [BEGIN] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); + + // automatic selection of the next transect + nextTransect = flight.getNextTransectFlightFrom(lastTransect); + + state = FlightState.ON_EFFORT; + + // Record the audio for the current LEG + saveAudio(3); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "begin()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "begin()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void circleBack(Observation observation) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + currentRoute != null + && currentRoute.getRouteType() != RouteType.TRANSIT, + "You can't call circleBack() during TRANSIT"); + + + TopiaContext transaction = persistence.beginTransaction(); + try { + + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + setObservationStatus(transaction, observation, ObservationStatus.CIRCLE_BACK); + + // Create CIRCLE_BACK + if (logger.isInfoEnabled()) { + logger.info(String.format("Create CIRCLE_BACK at %1$tH:%1$tM:%1$tS", currentDate)); + } + + currentRoute = service.createCircleBack(transaction, flight, currentDate, currentRoute, observation); + + nextTransect = lastTransect; + + state = FlightState.OFF_EFFORT; + + // Record the audio of the LEG in an other file + saveAudio(3); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "circleBack()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "circleBack()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void add() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOnEffort(), "You can call add() only if flight is on effort (started, not ended, on effort)"); + + TopiaContext transaction = persistence.beginTransaction(); + try { + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + // Create new LEG route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create LEG [ADD] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createLeg(transaction, flight, currentDate, currentRoute, lastTransect); + + // Record the audio of the LEG in an other file + saveAudio(3); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "add()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + + timeLog.log(startTime, "add()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void next() { + + long startTime = TimeLog.getTime(); + + if (isOnEffort()) { + doEndWithAudioDelay(3); + } + + begin(); + + timeLog.log(startTime, "next()"); + } + + @Override + public void observation(Position position) { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isRunning(), "You can call observation() only if flight is running (started, not ended)"); + + TopiaContext transaction = persistence.beginTransaction(); + try { + + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + ObserverPosition observer; + if (currentRoute == null) { + + // problem we don't have any observerPosition + observer = null; + + } else { + observer = currentRoute.getObserverPositionByPosition(position); + } + + if (logger.isInfoEnabled()) { + logger.info(String.format("Create Observation %2$s at %1$tH:%1$tM:%1$tS (observer = %3$s)", + currentDate, + position, + observer != null && observer.getObserver() != null + ? observer.getObserver().getInitials() : "") + ); + } + Observation observation = service.createObservation(transaction, flight, currentDate, observer); + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "observation()", "Commited"); + + for (FlightControllerUpdateListener listener : listeners) { + listener.onObservationAdded(observation); + } + + timeLog.log(startTime, "observation()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void end() { + + long startTime = TimeLog.getTime(); + + // Stop recording after 2 minutes (120 seconds) + doEndWithAudioDelay(120); + + timeLog.log(startTime, "end()"); + } + + @Override + public void stop() { + + long startTime = TimeLog.getTime(); + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOffEffort(), "You can call stop() only if flight is running (started, not ended, not on effort)"); + + TopiaContext transaction = persistence.beginTransaction(); + try { + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + if (logger.isInfoEnabled()) { + logger.info(String.format("Stop flight %2$d at %1$tH:%1$tM:%1$tS", + currentDate, + flight.getFlightNumber()) + ); + } + setFlightEndDate(transaction, flight, currentDate); + + // Stop audio + getAudioRecorder().stop(); + + // Stop gps + getGpsHandler().stop(); + + currentRoute = null; + + nextTransect = null; + + state = FlightState.ENDED; + + transaction.commitTransaction(); + + startTime = timeLog.log(startTime, "stop()", "Commited"); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + timeLog.log(startTime, "stop()", "Fired"); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + + @Override + public void close() { + + audioRecorder.close(); + audioRecorder = null; + + gpsHandler.close(); + gpsHandler = null; + + persistence.stopAutoSaveListener(); + } + + protected void doEndWithAudioDelay(long audioDelay) { + + Preconditions.checkState(initialized, + "The controller must be initialized before calling any action"); + + Preconditions.checkState( + isOnEffort(), "You can call end() only if flight is on effort (started, not ended, on effort)"); + + TopiaContext transaction = persistence.beginTransaction(); + try { + Date currentDate = saveGPS(transaction, gpsHandler.getCurrentLocation(), flight); + + // Create new TRANSIT route + if (logger.isInfoEnabled()) { + logger.info(String.format("Create TRANSIT [END] at %1$tH:%1$tM:%1$tS", currentDate)); + } + currentRoute = service.createTransit(transaction, flight, currentDate, currentRoute); + + audioRecorder.stopRecord(audioDelay); + + state = FlightState.OFF_EFFORT; + + transaction.commitTransaction(); + + // Fire events after commit + fireRouteAdded(currentRoute); + fireNextTransectChanged(nextTransect); + fireStateChanged(state); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } finally { + persistence.endTransaction(transaction); + } + } + +// protected void setNextTransect(TransectFlight nextTransect, boolean fireEvents) { +// +// this.nextTransect = nextTransect; +// +// if (fireEvents) { +// // Fire transect changed +// for (FlightControllerUpdateListener listener : listeners) { +// listener.onNextTransectChanged(nextTransect); +// } +// } +// } +// +// protected void setNextTransectFrom(TransectFlight transect, boolean fireEvents) { +// +// TransectFlight nextTransect = +// flight.getNextTransectFlightFrom(transect); +// +// setNextTransect(nextTransect, fireEvents); +// } + + protected void setFlightBeginDate(TopiaContext transaction, + Flight flight, + Date beginDate) + throws TopiaException { + + FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); + flight.setBeginDate(beginDate); + flightDAO.update(flight); + } + + protected void setFlightEndDate(TopiaContext transaction, + Flight flight, + Date endDate) + throws TopiaException { + + FlightDAO flightDAO = SammoaDAOHelper.getFlightDAO(transaction); + flight.setEndDate(endDate); + flightDAO.update(flight); + } + + protected void setObservationStatus(TopiaContext transaction, + Observation observation, + ObservationStatus status) + throws TopiaException { + + ObservationDAO observationDAO = + SammoaDAOHelper.getObservationDAO(transaction); + observation.setObservationStatus(status); + observationDAO.update(observation); + } + + protected void saveAudio(long delay) { + + String fileName = String.format( + "%1$tF-%1$tH-%1$tM-%1$tS.%2$s.%3$s", + currentRoute.getBeginTime(), + currentRoute.getTopiaId(), + getAudioRecorder().getOutputType().getExtension() + ); + + File audioDir = context.getConfig().getAudioDirectory(); + + File audioFile = new File(audioDir, fileName); + + try { + getAudioRecorder().record(audioFile, delay); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + protected Date saveGPS(TopiaContext transaction, + GeoPoint geoPoint, + Flight flight) + throws TopiaException { + + Date result; + if (geoPoint == null) { + result = new Date(); + if (logger.isWarnEnabled()) { + logger.warn("No GPS point at {}", result); + } + + } else { + + if (logger.isTraceEnabled()) { + logger.trace("Create GPS Point : {}", geoPoint); + } + + result = geoPoint.getRecordTime(); + + GeoPointDAO dao = SammoaDAOHelper.getGeoPointDAO(transaction); + + geoPoint.setFlight(flight); + + dao.create(geoPoint); + } + return result; + } + + protected void fireStateChanged(FlightState state) { + for (FlightControllerUpdateListener listener : listeners) { + listener.onStateChanged(state); + } + } + + protected void fireRouteAdded(Route route) { + for (FlightControllerUpdateListener listener : listeners) { + listener.onRouteAdded(route); + } + } + + protected void fireNextTransectChanged(TransectFlight nextTransect) { + for (FlightControllerUpdateListener listener : listeners) { + listener.onNextTransectChanged(nextTransect); + } + } + + protected <T extends DeviceManager> T newDeviceManager(T oldInstance, Supplier<T> supplier) + throws DeviceTechnicalException { + + Set<DeviceStateListener> stateListeners; + if (oldInstance != null) { + + // Remove all existing listeners and keep them for the new instance + stateListeners = Sets.newHashSet(oldInstance.getDeviceStateListeners()); + for (DeviceStateListener listener : stateListeners) { + oldInstance.removeDeviceStateListener(listener); + } + + oldInstance.close(); + + } else { + stateListeners = Sets.newHashSet(); + } + + T result = supplier.get(); + + // Attach all updateListener + for (DeviceStateListener listener : stateListeners) { + result.addDeviceStateListener(listener); + } + + return result; + } + + @Override + public void locationChanged(GpsLocationEvent event) { + GeoPoint newLocation = event.getNewValue(); + if (newLocation != null/* && newLocation.getTopiaId() == null*/) { + newLocation.setFlight(flight); + persistence.delayEntityCreation(newLocation); + } + } + +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerDefault.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Copied: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerUpdateListener.java (from rev 360, trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightControllerUpdateListener.java) =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerUpdateListener.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerUpdateListener.java 2012-08-07 15:49:18 UTC (rev 361) @@ -0,0 +1,69 @@ +package fr.ulr.sammoa.application.flightController; +/* + * #%L + * SAMMOA :: Application + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import fr.ulr.sammoa.persistence.Observation; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.TransectFlight; + +/** + * Listener for all change of data in the {@link FlightController} + * + * Created: 12/07/12 + * + * @author fdesbois <desbois@codelutin.com> + * @see FlightController + */ +public interface FlightControllerUpdateListener { + + /** + * Fired when a new {@code route} has been created and added to the flight + * + * @param route The new route added + */ + void onRouteAdded(Route route); + + /** + * Fired when the next transect has been updated. + * + * @param nextTransect The next transect that will be used on + * {@link FlightController#begin()} action + */ + void onNextTransectChanged(TransectFlight nextTransect); + + /** + * Fired when controller change the {@code state} of the flight after + * each action. + * + * @param state The new state + */ + void onStateChanged(FlightState state); + + /** + * Fired when controller add a new observation + * + * @param observation The new observation + */ + void onObservationAdded(Observation observation); +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerUpdateListener.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Copied: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightState.java (from rev 360, trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightState.java) =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightState.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightState.java 2012-08-07 15:49:18 UTC (rev 361) @@ -0,0 +1,57 @@ +/* + * #%L + * SAMMOA :: Application + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ +package fr.ulr.sammoa.application.flightController; + +/** + * Created: 20/06/12 + * + * @author fdesbois <desbois@codelutin.com> + */ +public enum FlightState { + /** + * The WAITING state is when the flight is not started and not ended. + * It appends when the flight is not really in used. + */ + WAITING, + + /** + * The OFF_EFFORT state is when the flight is started but not ended, + * and also if the current route is not an effort. + * It appends generally when the flight is in TRANSIT or CIRCLE_BACK. + */ + OFF_EFFORT, + + /** + * The ON_EFFORT state is when the flight is started, not ended but in + * current effort. It appends when a LEG is currently in progress. + */ + ON_EFFORT, + + /** + * The ENDED state is when the flight is ended. + * It appends when the current effort is finished and when no more route + * need to be registered. + */ + ENDED +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightState.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/BaseHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/BaseHandler.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/BaseHandler.java 2012-08-07 15:49:18 UTC (rev 361) @@ -24,8 +24,8 @@ */ package fr.ulr.sammoa.ui.swing; -import fr.ulr.sammoa.application.FlightController; import fr.ulr.sammoa.application.SammoaContext; +import fr.ulr.sammoa.application.flightController.FlightController; import fr.ulr.sammoa.ui.swing.flight.FlightUIModel; /** Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-08-07 15:49:18 UTC (rev 361) @@ -24,11 +24,11 @@ */ package fr.ulr.sammoa.ui.swing; -import fr.ulr.sammoa.application.FlightState; import fr.ulr.sammoa.application.SammoaConfig; import fr.ulr.sammoa.application.SammoaContext; import fr.ulr.sammoa.application.device.DeviceTechnicalException; import fr.ulr.sammoa.application.device.gps.GpsConfig; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.ui.swing.campaign.CampaignUI; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/SammoaUIContext.java 2012-08-07 15:49:18 UTC (rev 361) @@ -25,9 +25,9 @@ package fr.ulr.sammoa.ui.swing; import com.google.common.base.Preconditions; -import fr.ulr.sammoa.application.FlightController; import fr.ulr.sammoa.application.SammoaConfig; import fr.ulr.sammoa.application.SammoaContext; +import fr.ulr.sammoa.application.flightController.FlightController; import fr.ulr.sammoa.ui.swing.flight.FlightUIHandler; import fr.ulr.sammoa.ui.swing.flight.FlightUIModel; import org.nuiton.widget.SwingSession; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/AddAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/AddAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/AddAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/BeginAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/BeginAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/BeginAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.RouteType; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/EndAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/EndAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/EndAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/NextAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/NextAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/NextAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/ObservationAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/ObservationAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/ObservationAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Position; import fr.ulr.sammoa.ui.swing.SammoaUIContext; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/SammoaAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/SammoaAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/SammoaAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,8 +23,8 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightController; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightController; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.persistence.TransectFlight; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StartAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StartAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StartAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/action/StopAction.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,7 +23,7 @@ */ package fr.ulr.sammoa.ui.swing.action; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.ui.swing.SammoaUIContext; import org.nuiton.util.Resource; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/campaign/CampaignUI.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/campaign/CampaignUI.jaxx 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/campaign/CampaignUI.jaxx 2012-08-07 15:49:18 UTC (rev 361) @@ -26,7 +26,7 @@ implements='fr.ulr.sammoa.ui.swing.SammoaUI<CampaignUIHandler>'> <import> - fr.ulr.sammoa.application.FlightState + fr.ulr.sammoa.application.flightController.FlightState fr.ulr.sammoa.persistence.Region fr.ulr.sammoa.persistence.Campaign fr.ulr.sammoa.ui.swing.SammoaUIContext Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBar.jaxx 2012-08-07 15:49:18 UTC (rev 361) @@ -28,7 +28,7 @@ javax.swing.BoxLayout javax.swing.SwingConstants jaxx.runtime.swing.ClockWidget - fr.ulr.sammoa.application.FlightState + fr.ulr.sammoa.application.flightController.FlightState </import> <script><![CDATA[ Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightBarHandler.java 2012-08-07 15:49:18 UTC (rev 361) @@ -24,7 +24,7 @@ */ package fr.ulr.sammoa.ui.swing.flight; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.ui.swing.BaseHandler; import fr.ulr.sammoa.ui.swing.SammoaColors; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUI.jaxx 2012-08-07 15:49:18 UTC (rev 361) @@ -40,7 +40,7 @@ fr.ulr.sammoa.persistence.Flight fr.ulr.sammoa.persistence.Observer fr.ulr.sammoa.persistence.Strate - fr.ulr.sammoa.application.FlightState + fr.ulr.sammoa.application.flightController.FlightState fr.ulr.sammoa.ui.swing.SammoaUIContext fr.ulr.sammoa.ui.swing.ValidationTable fr.ulr.sammoa.ui.swing.observations.EffortPanel Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-08-07 15:49:18 UTC (rev 361) @@ -46,17 +46,17 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; -import fr.ulr.sammoa.application.FlightController; -import fr.ulr.sammoa.application.FlightControllerDefault; -import fr.ulr.sammoa.application.FlightControllerUpdateListener; import fr.ulr.sammoa.application.FlightService; -import fr.ulr.sammoa.application.FlightState; import fr.ulr.sammoa.application.ReferentialService; import fr.ulr.sammoa.application.SammoaConfig; import fr.ulr.sammoa.application.SammoaContext; import fr.ulr.sammoa.application.device.DeviceTechnicalException; import fr.ulr.sammoa.application.device.gps.GpsLocationEvent; import fr.ulr.sammoa.application.device.gps.GpsLocationListener; +import fr.ulr.sammoa.application.flightController.FlightController; +import fr.ulr.sammoa.application.flightController.FlightControllerDefault; +import fr.ulr.sammoa.application.flightController.FlightControllerUpdateListener; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.GeoPoint; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIModel.java 2012-08-07 15:49:18 UTC (rev 361) @@ -26,7 +26,7 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.Observation; import fr.ulr.sammoa.persistence.Observations; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/layer/TransectLayer.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/layer/TransectLayer.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/layer/TransectLayer.java 2012-08-07 15:49:18 UTC (rev 361) @@ -26,7 +26,7 @@ import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.plugin.esri.EsriPlugIn; -import fr.ulr.sammoa.application.FlightState; +import fr.ulr.sammoa.application.flightController.FlightState; import fr.ulr.sammoa.persistence.Route; import fr.ulr.sammoa.persistence.Transect; import fr.ulr.sammoa.persistence.TransectFlight; Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/io/exportMap/ExportMapUI.jaxx =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/io/exportMap/ExportMapUI.jaxx 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/io/exportMap/ExportMapUI.jaxx 2012-08-07 15:49:18 UTC (rev 361) @@ -25,7 +25,7 @@ implements='fr.ulr.sammoa.ui.swing.SammoaUI<ExportMapUIHandler>'> <import> - fr.ulr.sammoa.application.FlightState + fr.ulr.sammoa.application.flightController.FlightState fr.ulr.sammoa.persistence.Campaign fr.ulr.sammoa.persistence.RouteType fr.ulr.sammoa.persistence.Strate Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java 2012-08-07 15:48:54 UTC (rev 360) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/observations/EffortPanelHandler.java 2012-08-07 15:49:18 UTC (rev 361) @@ -23,11 +23,11 @@ * #L% */ -import fr.ulr.sammoa.application.FlightController; import fr.ulr.sammoa.application.FlightService; import fr.ulr.sammoa.application.device.DeviceState; import fr.ulr.sammoa.application.device.DeviceStateEvent; import fr.ulr.sammoa.application.device.DeviceStateListener; +import fr.ulr.sammoa.application.flightController.FlightController; import fr.ulr.sammoa.persistence.Observation; import fr.ulr.sammoa.persistence.ObservationStatus; import fr.ulr.sammoa.persistence.Observations;
participants (1)
-
fdesbois@users.forge.codelutin.com