AbstractJavaFXSpringApplication.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * SteelBlue: DCI User Interfaces
  5.  * http://tidalwave.it/projects/steelblue
  6.  *
  7.  * Copyright (C) 2015 - 2024 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *************************************************************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  12.  * You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  17.  * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
  18.  *
  19.  * *************************************************************************************************************************************************************
  20.  *
  21.  * git clone https://bitbucket.org/tidalwave/steelblue-src
  22.  * git clone https://github.com/tidalwave-it/steelblue-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.ui.javafx;

  27. import javax.annotation.Nonnull;
  28. import java.util.Objects;
  29. import java.util.TreeMap;
  30. import java.util.concurrent.Executors;
  31. import java.io.IOException;
  32. import javafx.stage.Stage;
  33. import javafx.application.Platform;
  34. import org.springframework.context.ApplicationContext;
  35. import org.springframework.context.ConfigurableApplicationContext;
  36. import org.slf4j.Logger;
  37. import org.slf4j.LoggerFactory;
  38. import it.tidalwave.role.ui.javafx.ApplicationPresentationAssembler;
  39. import it.tidalwave.role.ui.javafx.PresentationAssembler;

  40. /***************************************************************************************************************************************************************
  41.  *
  42.  * A base class for all variants of JavaFX applications with Spring.
  43.  *
  44.  * @author  Fabrizio Giudici
  45.  *
  46.  **************************************************************************************************************************************************************/
  47. public abstract class AbstractJavaFXSpringApplication extends JavaFXApplicationWithSplash
  48.   {
  49.     // Don't use Slf4j and its static logger - give Main a chance to initialize things
  50.     private final Logger log = LoggerFactory.getLogger(AbstractJavaFXSpringApplication.class);

  51.     private ConfigurableApplicationContext applicationContext;

  52.     /***********************************************************************************************************************************************************
  53.      *
  54.      **********************************************************************************************************************************************************/
  55.     @Override @Nonnull
  56.     protected NodeAndDelegate<?> createParent()
  57.       throws IOException
  58.       {
  59.         return NodeAndDelegate.load(getClass(), applicationFxml);
  60.       }

  61.     /***********************************************************************************************************************************************************
  62.      *
  63.      **********************************************************************************************************************************************************/
  64.     @Override
  65.     protected void initializeInBackground()
  66.       {
  67.         log.info("initializeInBackground()");

  68.         try
  69.           {
  70.             logProperties();
  71.             // TODO: workaround for NWRCA-41
  72.             System.setProperty("it.tidalwave.util.spring.ClassScanner.basePackages", "it");
  73.             applicationContext = createApplicationContext();
  74.             applicationContext.registerShutdownHook(); // this actually seems not working, onClosing() does
  75.           }
  76.         catch (Throwable t)
  77.           {
  78.             log.error("", t);
  79.           }
  80.       }

  81.     /***********************************************************************************************************************************************************
  82.      * Creates the application context.
  83.      *
  84.      * @return  the application context
  85.      **********************************************************************************************************************************************************/
  86.     @Nonnull
  87.     protected abstract ConfigurableApplicationContext createApplicationContext();

  88.     /***********************************************************************************************************************************************************
  89.      * {@inheritDoc}
  90.      **********************************************************************************************************************************************************/
  91.     @Override
  92.     protected final void onStageCreated (@Nonnull final Stage stage,
  93.                                          @Nonnull final NodeAndDelegate<?> applicationNad)
  94.       {
  95.         assert Platform.isFxApplicationThread();
  96.         JavaFXSafeProxyCreator.getJavaFxBinder().setMainWindow(stage);
  97.         final var delegate = applicationNad.getDelegate();

  98.         if (PresentationAssembler.class.isAssignableFrom(delegate.getClass()))
  99.           {
  100.             ((PresentationAssembler)delegate).assemble(applicationContext);
  101.           }

  102.         runApplicationAssemblers(applicationNad);
  103.         Executors.newSingleThreadExecutor().execute(() -> onStageCreated(applicationContext));
  104.       }

  105.     /***********************************************************************************************************************************************************
  106.      * Invoked when the {@link Stage} is created and the {@link ApplicationContext} has been initialized. Typically
  107.      * the main class overrides this, retrieves a reference to the main controller and boots it.
  108.      * This method is executed in a background thread.
  109.      *
  110.      * @param   applicationContext  the application context
  111.      **********************************************************************************************************************************************************/
  112.     protected void onStageCreated (@Nonnull final ApplicationContext applicationContext)
  113.       {
  114.       }

  115.     /***********************************************************************************************************************************************************
  116.      * {@inheritDoc}
  117.      **********************************************************************************************************************************************************/
  118.     @Override
  119.     protected void onClosing()
  120.       {
  121.         applicationContext.close();
  122.       }

  123.     /***********************************************************************************************************************************************************
  124.      *
  125.      **********************************************************************************************************************************************************/
  126.     private void runApplicationAssemblers (@Nonnull final NodeAndDelegate applicationNad)
  127.       {
  128.         Objects.requireNonNull(applicationContext, "applicationContext is null");
  129.         applicationContext.getBeansOfType(ApplicationPresentationAssembler.class).values()
  130.                 .forEach(a -> a.assemble(applicationNad.getDelegate()));
  131.       }

  132.     /***********************************************************************************************************************************************************
  133.      * Logs all the system properties.
  134.      **********************************************************************************************************************************************************/
  135.     private void logProperties()
  136.       {
  137.         for (final var e : new TreeMap<>(System.getProperties()).entrySet())
  138.           {
  139.             log.debug("{}: {}", e.getKey(), e.getValue());
  140.           }
  141.       }
  142.   }