View Javadoc
1   package fr.ifremer.tutti.ui.swing;
2   
3   /*
4    * #%L
5    * Tutti :: UI
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.base.Preconditions;
26  import com.google.common.collect.Maps;
27  import com.google.common.collect.Sets;
28  import fr.ifremer.tutti.TuttiConfiguration;
29  import fr.ifremer.tutti.caliper.feed.CaliperFeedReader;
30  import fr.ifremer.tutti.ichtyometer.feed.IchtyometerFeedReader;
31  import fr.ifremer.tutti.persistence.ProgressionModel;
32  import fr.ifremer.tutti.service.ClosedPersistenceService;
33  import fr.ifremer.tutti.service.DecoratorService;
34  import fr.ifremer.tutti.service.PersistenceService;
35  import fr.ifremer.tutti.service.TuttiDataContext;
36  import fr.ifremer.tutti.service.TuttiServiceContext;
37  import fr.ifremer.tutti.service.ValidationService;
38  import fr.ifremer.tutti.service.bigfin.BigfinImportService;
39  import fr.ifremer.tutti.service.catches.ValidateCruiseOperationsService;
40  import fr.ifremer.tutti.service.catches.WeightCleaningService;
41  import fr.ifremer.tutti.service.catches.WeightComputingService;
42  import fr.ifremer.tutti.service.catches.multipost.MultiPostExportService;
43  import fr.ifremer.tutti.service.catches.multipost.MultiPostImportService;
44  import fr.ifremer.tutti.service.export.cps.CalcifiedPiecesSamplingExportService;
45  import fr.ifremer.tutti.service.export.pdf.CatchesPdfExportService;
46  import fr.ifremer.tutti.service.export.sumatra.CatchesSumatraExportService;
47  import fr.ifremer.tutti.service.export.toconfirmreport.ToConfirmReportService;
48  import fr.ifremer.tutti.service.genericformat.GenericFormatExportService;
49  import fr.ifremer.tutti.service.genericformat.GenericFormatImportService;
50  import fr.ifremer.tutti.service.operationimport.FishingOperationImportService;
51  import fr.ifremer.tutti.service.protocol.ProtocolCaracteristicsImportExportService;
52  import fr.ifremer.tutti.service.protocol.ProtocolImportExportService;
53  import fr.ifremer.tutti.service.psionimport.PsionImportService;
54  import fr.ifremer.tutti.service.pupitri.PupitriExportService;
55  import fr.ifremer.tutti.service.pupitri.PupitriImportService;
56  import fr.ifremer.tutti.service.referential.ReferentialTemporaryGearService;
57  import fr.ifremer.tutti.service.referential.ReferentialTemporaryPersonService;
58  import fr.ifremer.tutti.service.referential.ReferentialTemporarySpeciesService;
59  import fr.ifremer.tutti.service.referential.ReferentialTemporaryVesselService;
60  import fr.ifremer.tutti.service.referential.TuttiReferentialSynchronizeService;
61  import fr.ifremer.tutti.service.report.ReportGenerationService;
62  import fr.ifremer.tutti.service.cruise.CruiseCacheLoader;
63  import fr.ifremer.tutti.ui.swing.content.MainUI;
64  import fr.ifremer.tutti.ui.swing.updater.DeleteHelper;
65  import fr.ifremer.tutti.ui.swing.util.SoundEngine;
66  import fr.ifremer.tutti.ui.swing.util.TuttiUIUtil;
67  import fr.ifremer.tutti.ui.swing.util.UIMessageNotifier;
68  import fr.ifremer.tutti.ui.swing.util.auth.AuthenticationInfo;
69  import fr.ifremer.tutti.ui.swing.util.auth.LoginUI;
70  import jaxx.runtime.JAXXContext;
71  import jaxx.runtime.swing.editor.bean.BeanDoubleList;
72  import jaxx.runtime.swing.editor.bean.BeanFilterableComboBox;
73  import jaxx.runtime.swing.help.JAXXHelpBroker;
74  import jaxx.runtime.swing.help.JAXXHelpUIHandler;
75  import jaxx.runtime.swing.session.BeanDoubleListState;
76  import jaxx.runtime.swing.session.BeanFilterableComboBoxState;
77  import jaxx.runtime.swing.session.State;
78  import jaxx.runtime.swing.session.SwingSession;
79  import org.apache.commons.io.IOUtils;
80  import org.apache.commons.lang3.StringUtils;
81  import org.apache.commons.logging.Log;
82  import org.apache.commons.logging.LogFactory;
83  import org.jdesktop.beans.AbstractBean;
84  import org.nuiton.converter.ConverterUtil;
85  import org.nuiton.i18n.I18n;
86  import org.nuiton.i18n.init.DefaultI18nInitializer;
87  import org.nuiton.i18n.init.UserI18nInitializer;
88  import org.nuiton.jaxx.application.ApplicationBusinessException;
89  import org.nuiton.jaxx.application.ApplicationIOUtil;
90  import org.nuiton.jaxx.application.ApplicationTechnicalException;
91  import org.nuiton.jaxx.application.listener.PropagatePropertyChangeListener;
92  import org.nuiton.jaxx.application.swing.ApplicationUIContext;
93  import org.nuiton.jaxx.application.swing.action.ApplicationActionEngine;
94  import org.nuiton.jaxx.application.swing.action.ApplicationActionUI;
95  import org.nuiton.jaxx.application.swing.action.ApplicationUIAction;
96  import org.nuiton.jaxx.application.swing.util.ApplicationErrorHelper;
97  
98  import javax.swing.JOptionPane;
99  import java.awt.Color;
100 import java.awt.Component;
101 import java.beans.PropertyChangeListener;
102 import java.io.Closeable;
103 import java.io.File;
104 import java.io.IOException;
105 import java.io.InputStream;
106 import java.net.URI;
107 import java.net.URISyntaxException;
108 import java.util.Date;
109 import java.util.Locale;
110 import java.util.Map;
111 import java.util.Properties;
112 import java.util.Set;
113 import java.util.Timer;
114 
115 import static org.nuiton.i18n.I18n.n;
116 import static org.nuiton.i18n.I18n.t;
117 
118 /**
119  * UI application context.
120  *
121  * @author Tony Chemit - chemit@codelutin.com
122  * @since 0.1
123  */
124 public class TuttiUIContext extends AbstractBean implements Closeable, UIMessageNotifier, JAXXHelpUIHandler, PropagatePropertyChangeListener.PropagatePropertyChange, ApplicationUIContext {
125 
126     /** Logger. */
127     private static final Log log = LogFactory.getLog(TuttiUIContext.class);
128 
129     public static final String PROPERTY_PROGRAM_ID = "programId";
130 
131     public static final String PROPERTY_CRUISE_ID = "cruiseId";
132 
133     public static final String PROPERTY_PROTOCOL_ID = "protocolId";
134 
135     public static final String PROPERTY_SCREEN = "screen";
136 
137 //    public static final String PROPERTY_PROGRAM_FILLED = "programFilled";
138 //
139 //    public static final String PROPERTY_CRUISE__FILLED = "cruiseFilled";
140 //
141 //    public static final String PROPERTY_PROTOCOL_FILLED = "protocolFilled";
142 
143     public static final String PROPERTY_VALIDATION_CONTEXT = "validationContext";
144 
145     public static final String PROPERTY_ICHTYOMETER_CONNECTED = "ichtyometerConnected";
146 
147     public static final String PROPERTY_CALIPER_CONNECTED = "caliperConnected";
148 
149     public static final String PROPERTY_BUSY = "busy";
150 
151     public static final String PROPERTY_HIDE_BODY = "hideBody";
152 
153     public static final String PROPERTY_LOCALE = "locale";
154 
155     public static final Set<String> PROPERTIES_TO_SAVE = Sets.newHashSet(
156             PROPERTY_PROGRAM_ID,
157             PROPERTY_CRUISE_ID,
158             PROPERTY_PROTOCOL_ID,
159             PROPERTY_LOCALE);
160 
161     public static final String PROPERTY_DB_EXIST = "dbExist";
162 
163     public static final String PROPERTY_DB_LOADED = "dbLoaded";
164 
165     /**
166      * Application context (only one for all the application).
167      *
168      * @since 0.1
169      */
170     private static TuttiUIContext applicationContext;
171 
172     /**
173      * Application global configuration.
174      *
175      * @since 0.1
176      */
177     protected final TuttiConfiguration config;
178 
179     /**
180      * Service context used by any service.
181      *
182      * @since 0.1
183      */
184     protected final TuttiServiceContext serviceContext;
185 
186     /**
187      * Swing session used to save ui states.
188      *
189      * @since 0.1
190      */
191     protected final SwingSession swingSession;
192 
193     /**
194      * Erro helper.
195      *
196      * @since 1.0
197      */
198     protected final ApplicationErrorHelper errorHelper;
199 
200     /**
201      * Shared data context.
202      *
203      * @since 1.0.2
204      */
205     protected TuttiDataContext dataContext;
206 
207     /**
208      * Tutti help broker.
209      *
210      * @since 1.1
211      */
212     protected TuttiHelpBroker helpBroker;
213 
214     /**
215      * Current screen displayed in ui.
216      *
217      * @since 0.1
218      */
219     protected TuttiScreen screen;
220 
221     /**
222      * Current locale used in application.
223      *
224      * @since 1.0.3
225      */
226     protected Locale locale;
227 
228     /**
229      * Busy state ({@code true} when a blocking action is running).
230      *
231      * @since 1.0.3
232      */
233     protected boolean busy;
234 
235     /**
236      * Flag to hide (or not) the body of application.
237      *
238      * @since 1.1
239      */
240     protected boolean hideBody;
241 
242     /**
243      * Message notifiers.
244      *
245      * @since 0.3
246      */
247     protected final Set<UIMessageNotifier> messageNotifiers;
248 
249     /**
250      * Validation context (used by fishingOperation screens).
251      *
252      * @since 0.3
253      */
254     private String validationContext;
255 
256     private MainUI mainUI;
257 
258     private ApplicationActionUI actionUI;
259 
260     /**
261      * Flag to know if there is an exsiting db.
262      *
263      * @since 1.0
264      */
265     private boolean dbExist;
266 
267     /**
268      * Flag to know if there is a loaded db.
269      *
270      * @since 1.0
271      */
272     private boolean dbLoaded;
273 
274     private Properties helpMapping;
275 
276     private final TuttiActionFactory tuttiActionFactory;
277 
278     private final ApplicationActionEngine tuttiActionEngine;
279 
280     /**
281      * To keep authentication credential in memory.
282      *
283      * @since 3.1
284      */
285     private final Map<String, AuthenticationInfo> updateAuthenticationStore;
286 
287     /**
288      * Ichtyometer Reader.
289      *
290      * @since 3.1
291      */
292     private IchtyometerFeedReader ichtyometerReader;
293 
294     /**
295      * Caliper Reader.
296      *
297      * @since 4.5
298      */
299     private CaliperFeedReader caliperFeedReader;
300 
301     /**
302      * A file lock to prevent multiple instance. the lock is create in the {@link #init()} method and remove in the
303      * {@link #close()} method.
304      *
305      * @since 3.2
306      */
307     private File lock;
308 
309     /**
310      * Flag to know if context was already closed. Can happen when you close nicely the application, the shutdown hook
311      * must then not close a second time this context.
312      *
313      * @since 3.2
314      */
315     private boolean closed;
316 
317     private final SoundEngine soundEngine;
318 
319     public static TuttiUIContext newContext(TuttiConfiguration config) {
320         Preconditions.checkNotNull(config);
321         Preconditions.checkState(applicationContext == null,
322                                  "Application context was already opened!");
323         applicationContext = new TuttiUIContext(config);
324         return applicationContext;
325     }
326 
327     public static TuttiUIContext getApplicationContext() {
328         return applicationContext;
329     }
330 
331     public ApplicationErrorHelper getErrorHelper() {
332         return applicationContext.errorHelper;
333     }
334 
335     @Override
336     public String getI18nPrefix() {
337         return "tutti.property.";
338     }
339 
340     @Override
341     public String getDateFormat() {
342         return getConfig().getDateFormat();
343     }
344 
345     @Override
346     public boolean isActionInProgress(ApplicationUIAction action) {
347         // TODO do something
348         return false;
349     }
350 
351     @Override
352     public void setActionInProgress(ApplicationUIAction action, boolean actionInProgress) {
353         // TODO do something
354     }
355 
356     protected TuttiUIContext(TuttiConfiguration config) {
357         this.config = config;
358         this.serviceContext = new TuttiServiceContext(config);
359 
360         Map<Class, State> additionalStates = Maps.newHashMap();
361         additionalStates.put(BeanFilterableComboBox.class, new BeanFilterableComboBoxState());
362         additionalStates.put(BeanDoubleList.class, new BeanDoubleListState());
363         this.swingSession = SwingSession.newSession(getConfig().getUIConfigFile(), false, additionalStates);
364 
365         //FIXME Push this to ifremer-shared
366         this.errorHelper = new ApplicationErrorHelper(this) {
367 
368             @Override
369             public void showWarningDialog(String message) {
370 
371                 JOptionPane.showMessageDialog(context.getActionUI(), "<html><body>" + message + "</body></html>",
372                                               t("application.error.ui.business.warning"),
373                                               JOptionPane.WARNING_MESSAGE);
374             }
375 
376             @Override
377             public void showErrorDialog(String message, Throwable cause) {
378                 super.showErrorDialog(message, cause);
379             }
380         };
381         this.dataContext = serviceContext.getDataContext();
382         PropagatePropertyChangeListener.listenAndPropagateAll(dataContext, this);
383         UIMessageNotifier logMessageNotifier = new UIMessageNotifier() {
384 
385             @Override
386             public void showInformationMessage(String message) {
387                 if (StringUtils.isNotBlank(message)) {
388                     message = message.replaceAll("\\<strong\\>", "");
389                     message = message.replaceAll("\\<.strong\\>", "");
390                     message = message.replaceAll("\\<li\\>", "");
391                     message = message.replaceAll("\\<.li\\>", "");
392                     message = message.replaceAll("\\<ul\\>", "");
393                     message = message.replaceAll("\\<.ul\\>", "");
394                     if (log.isInfoEnabled()) {
395                         log.info(message);
396                     }
397                 }
398             }
399         };
400         this.messageNotifiers = Sets.newHashSet();
401         addMessageNotifier(logMessageNotifier);
402         tuttiActionFactory = new TuttiActionFactory();
403         tuttiActionEngine = new ApplicationActionEngine(tuttiActionFactory);
404         this.updateAuthenticationStore = Maps.newTreeMap();
405         this.soundEngine = new SoundEngine(config);
406     }
407 
408     @Override
409     public TuttiConfiguration getConfiguration() {
410         return config;
411     }
412 
413     @Override
414     public Component getBodyUI() {
415         MainUI mainUI = getMainUI();
416         return mainUI == null ? null : mainUI.getBody();
417     }
418 
419     @Override
420     public Component getStatusUI() {
421         MainUI mainUI = getMainUI();
422         return mainUI == null ? null : mainUI.getStatus();
423     }
424 
425     //------------------------------------------------------------------------//
426     //-- Open / close methods                                               --//
427     //------------------------------------------------------------------------//
428 
429     public void init() {
430 
431         config.prepareDirectories();
432 
433         // converters are stored in current classloader, we need then to rescan them
434         // each time we change current classloader
435         ConverterUtil.deregister();
436         ConverterUtil.initConverters();
437 
438         // Use shutdownHook to close context on System.exit
439         Runtime.getRuntime().addShutdownHook(new Thread(() -> {
440             if (!closed) {
441                 close();
442             }
443         }));
444 
445         //--------------------------------------------------------------------//
446         // init db configuration
447         //--------------------------------------------------------------------//
448 
449         config.initConfig();
450 
451 //        // clean db cache (avoid a lots of headache :(
452 //        File cacheDirectory = config.getServiceConfig().getPersistenceConfig().getCacheDirectory();
453 //        if (cacheDirectory.exists()) {
454 //            // clean cache directory (fix soem headaches...)
455 //            TuttiIOUtil.cleanDirectory(
456 //                    cacheDirectory,
457 //                    t("tutti.db.deleteCache.error", cacheDirectory));
458 //        }
459 
460         //--------------------------------------------------------------------//
461         // init i18n
462         //--------------------------------------------------------------------//
463         File i18nDirectory = config.getI18nDirectory();
464         if (!config.isFullLaunchMode()) {
465 
466             i18nDirectory = new File(config.getDataDirectory(), "i18n");
467 
468             if (i18nDirectory.exists()) {
469                 // clean i18n cache
470                 ApplicationIOUtil.cleanDirectory(
471                         i18nDirectory,
472                         t("tutti.i18n.deleteCache.error", i18nDirectory));
473             }
474         }
475 
476         ApplicationIOUtil.forceMkdir(i18nDirectory,
477                                      t("tutti.i18n.mkDir.error", i18nDirectory));
478 
479         if (log.isDebugEnabled()) {
480             log.debug("I18N directory: " + i18nDirectory);
481         }
482 
483         Locale i18nLocale = config.getI18nLocale();
484 
485         if (log.isInfoEnabled()) {
486             log.info(String.format("Starts i18n with locale [%s] at [%s]",
487                                    i18nLocale, i18nDirectory));
488         }
489         I18n.init(new UserI18nInitializer(
490                           i18nDirectory, new DefaultI18nInitializer("tutti-i18n")),
491                   i18nLocale);
492 
493 
494         //--------------------------------------------------------------------//
495         // init lock
496         //--------------------------------------------------------------------//
497 
498         lock = new File(config.getBasedir(), "tutti.lock");
499 
500         if (lock.exists()) {
501             lock = null;
502             throw new ApplicationBusinessException(t("tutti.error.application.already.started"));
503         }
504 
505         ApplicationIOUtil.writeContent(lock, new Date().toString(), "Could not create lock file");
506         if (log.isInfoEnabled()) {
507             log.info("Create lock file: " + lock);
508         }
509 
510 
511         //--------------------------------------------------------------------//
512         // init help
513         //--------------------------------------------------------------------//
514 
515         File helpDirectory = config.getHelpDirectory();
516 
517         if (!config.isFullLaunchMode()) {
518 
519             if (!helpDirectory.exists()) {
520                 helpDirectory = new File(config.getDataDirectory(), "help");
521             }
522         }
523 
524         if (log.isDebugEnabled()) {
525             log.debug("Help directory: " + helpDirectory);
526         }
527         ApplicationIOUtil.forceMkdir(
528                 helpDirectory,
529                 t("tutti.help.mkDir.error", helpDirectory));
530 
531         // load help mapping
532         String mappingProperties = "/tutti-help-fr.properties";
533         try {
534 
535             InputStream resourceAsStream =
536                     getClass().getResourceAsStream(mappingProperties);
537             helpMapping = new Properties();
538             helpMapping.load(resourceAsStream);
539 
540         } catch (Exception eee) {
541             log.error("Failed to load help mapping file at '" +
542                               mappingProperties + "'", eee);
543         }
544         if (log.isInfoEnabled()) {
545             log.info(String.format("Starts help with locale at [%s]",
546                                    helpDirectory));
547         }
548 
549         //--------------------------------------------------------------------//
550         // init action UI
551         //--------------------------------------------------------------------//
552         setActionUI(new ApplicationActionUI(null, this));
553     }
554 
555     public void open() {
556 
557         setLocale(config.getI18nLocale());
558 
559         if (getProgramId() == null) {
560 
561             // load it from config
562             setProgramId(config.getProgramId());
563         }
564 
565         if (getCruiseId() == null) {
566 
567             // load it from config
568             setCruiseId(config.getCruiseId());
569         }
570 
571         if (getProtocolId() == null) {
572 
573             // load it from config
574             setProtocolId(config.getProtocolId());
575         }
576 
577         boolean dbExists = config.isDbExists();
578 
579         setDbExist(dbExists);
580 
581         if (!dbExists) {
582 
583             setProtocolId(null);
584             setProgramId(null);
585             setCruiseId(null);
586             setDbLoaded(false);
587         }
588 
589         // save back to config
590         saveContextToConfig();
591 
592         // list when programId or campaingId change to save the configuration
593         addPropertyChangeListener(evt -> {
594 
595             if (PROPERTIES_TO_SAVE.contains(evt.getPropertyName())) {
596                 saveContextToConfig();
597             }
598         });
599 
600         soundEngine.open();
601 
602     }
603 
604     @Override
605     public void close() {
606 
607         if (log.isInfoEnabled()) {
608             log.info("Closing application context...");
609         }
610         Preconditions.checkState(!closed, "Application was already closed.");
611 
612         try {
613             // Clear data references
614             messageNotifiers.clear();
615             validationContext = null;
616             IOUtils.closeQuietly(dataContext);
617 
618             if (timer != null) {
619                 timer.purge();
620                 timer.cancel();
621             }
622 
623             setScreen(null);
624 
625             IOUtils.closeQuietly(serviceContext);
626             IOUtils.closeQuietly(ichtyometerReader);
627             IOUtils.closeQuietly(caliperFeedReader);
628             IOUtils.closeQuietly(soundEngine);
629 
630             // remove listeners
631             PropertyChangeListener[] listeners = getPropertyChangeListeners();
632             for (PropertyChangeListener listener : listeners) {
633                 if (log.isDebugEnabled()) {
634                     log.debug("Remove listener: " + listener);
635                 }
636                 removePropertyChangeListener(listener);
637             }
638             setMainUI(null);
639             if (actionUI != null) {
640 
641                 // close action ui
642                 actionUI.getModel().clear();
643             }
644             setActionUI(null);
645 
646         } finally {
647             closed = true;
648             if (lock != null) {
649 
650                 // destroy lock
651                 ApplicationIOUtil.deleteFile(lock, "Could not delete lock file");
652                 if (log.isInfoEnabled()) {
653                     log.info("Delete lock file: " + lock);
654                 }
655             }
656         }
657     }
658 
659     //------------------------------------------------------------------------//
660     //-- Service methods                                                    --//
661     //------------------------------------------------------------------------//
662 
663     public PersistenceService getPersistenceService() {
664 
665         PersistenceService service;
666 
667         if (useRealPersistenceService()) {
668             service = dataContext.getService();
669             if (service == null) {
670 
671                 // use real service
672                 service = serviceContext.getService(PersistenceService.class);
673                 dataContext.setPersistenceService(service);
674 //                dataContext.open(config, service);
675             }
676         } else {
677             service = serviceContext.getService(ClosedPersistenceService.class);
678         }
679         return service;
680     }
681 
682     public DecoratorService getDecoratorService() {
683         return serviceContext.getService(DecoratorService.class);
684     }
685 
686     public TuttiReferentialSynchronizeService getTuttiReferentialSynchronizeService() {
687         return serviceContext.getService(TuttiReferentialSynchronizeService.class);
688     }
689 
690     public ProtocolImportExportService getTuttiProtocolImportExportService() {
691         return serviceContext.getService(ProtocolImportExportService.class);
692     }
693 
694     public ProtocolCaracteristicsImportExportService getProtocolCaracteristicsImportExportService() {
695         return serviceContext.getService(ProtocolCaracteristicsImportExportService.class);
696     }
697 
698     public PupitriImportService getPupitriImportService() {
699         return serviceContext.getService(PupitriImportService.class);
700     }
701 
702     public PupitriExportService getPupitriExportService() {
703         return serviceContext.getService(PupitriExportService.class);
704     }
705 
706     public PsionImportService getTuttiPsionImportService() {
707         return serviceContext.getService(PsionImportService.class);
708     }
709 
710     public BigfinImportService getTuttiBigfinImportService() {
711         return serviceContext.getService(BigfinImportService.class);
712     }
713 
714     public ReferentialTemporaryGearService getReferentialTemporaryGearService() {
715         return serviceContext.getService(ReferentialTemporaryGearService.class);
716     }
717 
718     public ReferentialTemporaryPersonService getReferentialTemporaryPersonService() {
719         return serviceContext.getService(ReferentialTemporaryPersonService.class);
720     }
721 
722     public ReferentialTemporarySpeciesService getReferentialTemporarySpeciesService() {
723         return serviceContext.getService(ReferentialTemporarySpeciesService.class);
724     }
725 
726     public ReferentialTemporaryVesselService getReferentialTemporaryVesselService() {
727         return serviceContext.getService(ReferentialTemporaryVesselService.class);
728     }
729 
730     public WeightComputingService getWeightComputingService() {
731         return serviceContext.getService(WeightComputingService.class);
732     }
733 
734     public WeightCleaningService getWeightCleaningService() {
735         return serviceContext.getService(WeightCleaningService.class);
736     }
737 
738     public ValidateCruiseOperationsService getValidateCruiseOperationsService() {
739         return serviceContext.getService(ValidateCruiseOperationsService.class);
740     }
741 
742     public ValidationService getValidationService() {
743         return serviceContext.getService(ValidationService.class);
744     }
745 
746     public CatchesPdfExportService getGeneratePDFService() {
747         return serviceContext.getService(CatchesPdfExportService.class);
748     }
749 
750     public ToConfirmReportService getToConfirmReportService() {
751         return serviceContext.getService(ToConfirmReportService.class);
752     }
753 
754     public GenericFormatExportService getGenericFormatExportService() {
755         return serviceContext.getService(GenericFormatExportService.class);
756     }
757 
758     public GenericFormatImportService getGenericFormatImportService() {
759         return serviceContext.getService(GenericFormatImportService.class);
760     }
761 
762     public CatchesSumatraExportService getCatchesSumatraExportService() {
763         return serviceContext.getService(CatchesSumatraExportService.class);
764     }
765 
766     public CalcifiedPiecesSamplingExportService getCalcifiedPiecesSamplingExportService() {
767         return serviceContext.getService(CalcifiedPiecesSamplingExportService.class);
768     }
769 
770     public MultiPostImportService getMultiPostImportService() {
771         return serviceContext.getService(MultiPostImportService.class);
772     }
773 
774     public MultiPostExportService getMultiPostExportService() {
775         return serviceContext.getService(MultiPostExportService.class);
776     }
777 
778     public FishingOperationImportService getFishingOperationImportService() {
779         return serviceContext.getService(FishingOperationImportService.class);
780     }
781 
782     public ReportGenerationService getReportGenerationService() {
783         return serviceContext.getService(ReportGenerationService.class);
784     }
785 
786     public SoundEngine getSoundEngine() {
787         return soundEngine;
788     }
789 
790     public boolean useRealPersistenceService() {
791         return isDbExist() && isDbLoaded();
792     }
793 
794     private PersistenceService reloadPersistenceService() {
795 
796         try {
797             serviceContext.close();
798         } catch (IOException e) {
799             throw new ApplicationTechnicalException(t("tutti.context.service.close.error"), e);
800         }
801         dataContext.close();
802 
803         return getPersistenceService();
804     }
805 
806     public void reloadDecoratorService() {
807         serviceContext.reloadService(DecoratorService.class);
808     }
809 
810     //------------------------------------------------------------------------//
811     //-- DataContext methods                                                --//
812     //------------------------------------------------------------------------//
813 
814     public TuttiDataContext getDataContext() {
815         return dataContext;
816     }
817 
818     public boolean isCruiseFilled() {
819         return dataContext.isCruiseFilled();
820     }
821 
822     public String getProgramId() {
823         return dataContext.getProgramId();
824     }
825 
826     public boolean isProtocolFilled() {
827         return dataContext.isProtocolFilled();
828     }
829 
830     public String getProtocolId() {
831         return dataContext.getProtocolId();
832     }
833 
834     public Integer getCruiseId() {
835         return dataContext.getCruiseId();
836     }
837 
838     public boolean isProgramFilled() {
839         return dataContext.isProgramFilled();
840     }
841 
842     public void setProgramId(String programId) {
843         dataContext.setProgramId(programId);
844     }
845 
846     public void setCruiseId(Integer cruiseId) {
847         dataContext.setCruiseId(cruiseId);
848     }
849 
850     public void setProtocolId(String protocolId) {
851         dataContext.setProtocolId(protocolId);
852     }
853 
854     public void clearDbContext() {
855         dataContext.clearContext();
856     }
857 
858     public void checkDbContext() {
859 
860         // open data context
861         dataContext.open(config);
862 
863         // ask data context to check his ids
864         dataContext.checkDbContext();
865 
866         // save config
867         saveContextToConfig();
868 
869     }
870 
871     public CruiseCacheLoader createCruiseCacheLoader(ProgressionModel progressionModel) {
872 
873         return CruiseCacheLoader.newCacheLoader(getPersistenceService(),
874                                                 getDecoratorService(),
875                                                 progressionModel,
876                                                 getDataContext().getProtocol(),
877                                                 getCruiseId());
878 
879     }
880 
881     //------------------------------------------------------------------------//
882     //-- Db methods                                                         --//
883     //------------------------------------------------------------------------//
884 
885     public boolean isDbExist() {
886         return dbExist;
887     }
888 
889     public void setDbExist(boolean dbExist) {
890         this.dbExist = dbExist;
891         firePropertyChange(PROPERTY_DB_EXIST, null, dbExist);
892     }
893 
894     public boolean isDbLoaded() {
895         return dbLoaded;
896     }
897 
898     private void setDbLoaded(boolean dbLoaded) {
899         this.dbLoaded = dbLoaded;
900         firePropertyChange(PROPERTY_DB_LOADED, null, dbLoaded);
901     }
902 
903     //------------------------------------------------------------------------//
904     //-- Config methods                                                     --//
905     //------------------------------------------------------------------------//
906 
907     public TuttiConfiguration getConfig() {
908         return config;
909     }
910 
911     protected void saveContextToConfig() {
912         if (log.isInfoEnabled()) {
913             log.info("Save config (programId: " + getProgramId() + ", cruiseId: " +
914                              getCruiseId() + ", protocolId: " + getProtocolId() + ", locale: " +
915                              getLocale() + ")");
916         }
917         config.setProgramId(getProgramId());
918         config.setCruiseId(getCruiseId());
919         config.setProtocolId(getProtocolId());
920         config.setI18nLocale(getLocale());
921         config.save();
922     }
923 
924 
925     //------------------------------------------------------------------------//
926     //-- UI methods                                                         --//
927     //------------------------------------------------------------------------//
928 
929     @Override
930     public MainUI getMainUI() {
931         return mainUI;
932     }
933 
934     public void setMainUI(MainUI mainUI) {
935         this.mainUI = mainUI;
936     }
937 
938     @Override
939     public ApplicationActionUI getActionUI() {
940         return actionUI;
941     }
942 
943     @Override
944     public ApplicationActionUI getExistingActionUI() {
945         while (actionUI == null || !actionUI.isShowing()) {
946 
947             try {
948                 Thread.sleep(50);
949             } catch (InterruptedException e) {
950                 // ignore this one
951             }
952         }
953         return actionUI;
954     }
955 
956     public void setActionUI(ApplicationActionUI actionUI) {
957         this.actionUI = actionUI;
958     }
959 
960     public void addInSwingSession(Component c, boolean replace) {
961 
962         try {
963 
964             swingSession.add(c, replace);
965 
966             saveSwingSession();
967 
968         } catch (Exception e) {
969             if (log.isWarnEnabled()) {
970                 log.warn("Could not add component " + c + "in swingSession file: " + swingSession.getFile(), e);
971             }
972         }
973 
974     }
975 
976     public void saveSwingSession() {
977 
978         try {
979             swingSession.save();
980         } catch (Exception e) {
981             if (log.isWarnEnabled()) {
982                 log.warn("Could not save ui config file: " + swingSession.getFile(), e);
983             }
984         }
985 
986     }
987 
988     public TuttiScreen getScreen() {
989         return screen;
990     }
991 
992     public void setScreen(TuttiScreen screen) {
993         Object oldValue = getScreen();
994         this.screen = screen;
995         firePropertyChange(PROPERTY_SCREEN, oldValue, screen);
996     }
997 
998     @Override
999     public boolean isBusy() {
1000         return busy;
1001     }
1002 
1003     @Override
1004     public void setBusy(boolean busy) {
1005         this.busy = busy;
1006         firePropertyChange(PROPERTY_BUSY, null, busy);
1007     }
1008 
1009     @Override
1010     public boolean isHideBody() {
1011         return hideBody;
1012     }
1013 
1014     @Override
1015     public void setHideBody(boolean hideBody) {
1016         this.hideBody = hideBody;
1017         firePropertyChange(PROPERTY_HIDE_BODY, null, hideBody);
1018     }
1019 
1020     @Override
1021     public Color getColorBlockingLayer() {
1022         return getConfig().getColorBlockingLayer();
1023     }
1024 
1025     @Override
1026     public TuttiActionFactory getActionFactory() {
1027         return tuttiActionFactory;
1028     }
1029 
1030     @Override
1031     public ApplicationActionEngine getActionEngine() {
1032         return tuttiActionEngine;
1033     }
1034 
1035     //------------------------------------------------------------------------//
1036     //-- UIMessageNotifier methods                                          --//
1037     //------------------------------------------------------------------------//
1038 
1039     public void addMessageNotifier(UIMessageNotifier messageNotifier) {
1040         this.messageNotifiers.add(messageNotifier);
1041     }
1042 
1043     public void removeMessageNotifier(UIMessageNotifier messageNotifier) {
1044         this.messageNotifiers.remove(messageNotifier);
1045     }
1046 
1047     @Override
1048     public void showInformationMessage(String message) {
1049         for (UIMessageNotifier messageNotifier : messageNotifiers) {
1050             messageNotifier.showInformationMessage(message);
1051         }
1052     }
1053 
1054     //------------------------------------------------------------------------//
1055     //-- Help methods                                                       --//
1056     //------------------------------------------------------------------------//
1057 
1058     public TuttiHelpBroker getHelpBroker() {
1059         return helpBroker;
1060     }
1061 
1062     public void setHelpBroker(TuttiHelpBroker helpBroker) {
1063         this.helpBroker = helpBroker;
1064     }
1065 
1066     @Override
1067     public void showHelp(JAXXContext context,
1068                          JAXXHelpBroker broker,
1069                          String helpId) {
1070         if (helpId == null) {
1071             helpId = broker.getDefaultID();
1072         }
1073 
1074         if (log.isInfoEnabled()) {
1075             log.info("show help " + helpId);
1076         }
1077 
1078         String value = (String) helpMapping.get(helpId);
1079 
1080         if (value == null) {
1081             throw new ApplicationTechnicalException(t("tutti.context.helpPage.notFound", helpId));
1082         }
1083 
1084         String helpDirectory = getConfig().getHelpResourceWithLocale(value);
1085         boolean withFragment = helpDirectory.contains("#");
1086 
1087         String fragment = null;
1088         if (withFragment) {
1089             fragment = StringUtils.substringAfter(helpDirectory, "#");
1090             helpDirectory = StringUtils.substringBefore(helpDirectory, "#");
1091         }
1092 
1093         URI resolvedUri = new File(helpDirectory).toURI();
1094         try {
1095 
1096             if (withFragment) {
1097                 resolvedUri = new URI(resolvedUri.toString() + "#" + fragment);
1098             }
1099             if (log.isInfoEnabled()) {
1100                 log.info("help uri = " + resolvedUri);
1101             }
1102             TuttiUIUtil.openLink(resolvedUri);
1103         } catch (URISyntaxException e) {
1104             throw new ApplicationTechnicalException(t("tutti.context.helpPage.notFound", resolvedUri));
1105         }
1106 
1107     }
1108 
1109     //------------------------------------------------------------------------//
1110     //-- Authentication methods                                             --//
1111     //------------------------------------------------------------------------//
1112 
1113     public AuthenticationInfo getAuthenticationInfo(String url) {
1114 
1115         // get existing info
1116         AuthenticationInfo authentication = updateAuthenticationStore.get(url);
1117 
1118         // ask user authentication
1119         authentication = new LoginUI(this).open(url, authentication).getAuthenticationInfo();
1120 
1121         if (authentication != null) {
1122 
1123             // store it back in authentication store
1124             updateAuthenticationStore.put(url, authentication);
1125         }
1126 
1127         return authentication;
1128     }
1129 
1130     //------------------------------------------------------------------------//
1131     //-- Ichtyometer methods                                                --//
1132     //------------------------------------------------------------------------//
1133 
1134     public IchtyometerFeedReader getIchtyometerReader() {
1135         return ichtyometerReader;
1136     }
1137 
1138     public void setIchtyometerReader(IchtyometerFeedReader ichtyometerReader) {
1139         this.ichtyometerReader = ichtyometerReader;
1140         firePropertyChange(PROPERTY_ICHTYOMETER_CONNECTED, null, isIchtyometerConnected());
1141     }
1142 
1143     public boolean isIchtyometerConnected() {
1144         return ichtyometerReader != null;
1145     }
1146 
1147     //------------------------------------------------------------------------//
1148     //-- Caliper methods                                                --//
1149     //------------------------------------------------------------------------//
1150 
1151     public CaliperFeedReader getCaliperReader() {
1152         return caliperFeedReader;
1153     }
1154 
1155     public void setCaliperReader(CaliperFeedReader caliperFeedReader) {
1156         this.caliperFeedReader = caliperFeedReader;
1157         firePropertyChange(PROPERTY_CALIPER_CONNECTED, null, isCaliperConnected());
1158     }
1159 
1160     public boolean isCaliperConnected() {
1161         return caliperFeedReader != null;
1162     }
1163 
1164     //------------------------------------------------------------------------//
1165     //-- Other methods                                                      --//
1166     //------------------------------------------------------------------------//
1167 
1168     public Locale getLocale() {
1169         return locale;
1170     }
1171 
1172     public void setLocale(Locale locale) {
1173         this.locale = locale;
1174         firePropertyChange(PROPERTY_LOCALE, null, locale);
1175     }
1176 
1177     public void setValidationContext(String validationContext) {
1178         Object oldValue = getValidationContext();
1179         this.validationContext = validationContext;
1180         firePropertyChange(PROPERTY_VALIDATION_CONTEXT, oldValue, validationContext);
1181     }
1182 
1183     public String getValidationContext() {
1184         return validationContext;
1185     }
1186 
1187     @Override
1188     public void firePropertyChanged(String propertyName,
1189                                     Object oldValue,
1190                                     Object newValue) {
1191         firePropertyChange(propertyName, oldValue, newValue);
1192     }
1193 
1194     public void setFallBackScreen() {
1195         if (isDbLoaded()) {
1196             setScreen(TuttiScreen.SELECT_CRUISE);
1197         } else {
1198             setScreen(TuttiScreen.MANAGE_DB);
1199         }
1200     }
1201 
1202     public boolean checkUpdateApplicationReachable(boolean showErrorInPopup) {
1203 
1204         boolean result = true;
1205         String url = config.getUpdateApplicationUrl();
1206 
1207         try {
1208             TuttiUIUtil.tryToConnectToUpdateUrl(
1209                     url,
1210                     n("tutti.error.update.bad.url.syntax"),
1211                     n("tutti.error.update.could.not.reach.url"),
1212                     n("tutti.error.update.could.not.found.url")
1213             );
1214         } catch (ApplicationBusinessException e) {
1215             if (showErrorInPopup) {
1216 
1217                 getErrorHelper().showWarningDialog(e.getMessage());
1218             } else {
1219                 showInformationMessage(e.getMessage());
1220             }
1221             result = false;
1222         }
1223         return result;
1224     }
1225 
1226     public boolean checkUpdateDataReachable(boolean showErrorInPopup) {
1227 
1228         boolean result = true;
1229         String url = config.getUpdateDataUrl();
1230 
1231         try {
1232             TuttiUIUtil.tryToConnectToUpdateUrl(
1233                     url,
1234                     n("tutti.error.update.bad.url.syntax"),
1235                     n("tutti.error.update.could.not.reach.url"),
1236                     n("tutti.error.update.could.not.found.url")
1237             );
1238         } catch (ApplicationBusinessException e) {
1239             if (showErrorInPopup) {
1240 
1241                 getErrorHelper().showWarningDialog(e.getMessage());
1242             } else {
1243                 showInformationMessage(e.getMessage());
1244             }
1245             result = false;
1246         }
1247         return result;
1248     }
1249 
1250     public void closePersistenceService() {
1251 
1252         setDbLoaded(false);
1253         reloadPersistenceService();
1254 
1255     }
1256 
1257     public void openPersistenceService() {
1258 
1259         setDbLoaded(true);
1260         reloadPersistenceService();
1261 
1262     }
1263 
1264     public void deleteDbOnExit() {
1265 
1266         if (log.isInfoEnabled()) {
1267             log.info("Delete db files on exit.");
1268         }
1269 
1270         try {
1271 
1272             DeleteHelper.deleteDirectoryOnExit(config.getDbDirectory().toPath());
1273             DeleteHelper.deleteDirectoryOnExit(config.getCacheDirectory().toPath());
1274             DeleteHelper.deleteDirectoryOnExit(config.getDbAttachmentDirectory().toPath());
1275 
1276         } catch (IOException e) {
1277             throw new ApplicationTechnicalException("Could not mark db files to be deleted on exit.", e);
1278         }
1279 
1280     }
1281 
1282     private Timer timer;
1283 
1284     public synchronized Timer getTimer() {
1285         if (timer == null) {
1286             timer = new Timer("ShowActions::");
1287         }
1288         return timer;
1289     }
1290 
1291     public synchronized Timer reloadTimer() {
1292         timer = null;
1293         return getTimer();
1294     }
1295 
1296 }