JavaFXSpringApplication.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * SteelBlue: DCI User Interfaces
  5.  * http://tidalwave.it/projects/steelblue
  6.  *
  7.  * Copyright (C) 2015 - 2023 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
  12.  * the License. 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
  17.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations under the License.
  19.  *
  20.  * *********************************************************************************************************************
  21.  *
  22.  * git clone https://bitbucket.org/tidalwave/steelblue-src
  23.  * git clone https://github.com/tidalwave-it/steelblue-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.ui.javafx;

  28. import javax.annotation.Nonnull;
  29. import java.util.ArrayList;
  30. import java.util.List;
  31. import java.util.Objects;
  32. import java.util.SortedMap;
  33. import java.util.TreeMap;
  34. import java.util.concurrent.Executors;
  35. import java.io.IOException;
  36. import javafx.stage.Stage;
  37. import javafx.application.Platform;
  38. import org.springframework.context.ApplicationContext;
  39. import org.springframework.context.support.ClassPathXmlApplicationContext;
  40. import it.tidalwave.ui.javafx.JavaFXSafeProxyCreator.NodeAndDelegate;
  41. import org.slf4j.Logger;
  42. import org.slf4j.LoggerFactory;
  43. import it.tidalwave.role.ui.javafx.ApplicationPresentationAssembler;

  44. /***********************************************************************************************************************
  45.  *
  46.  * @author  Fabrizio Giudici
  47.  *
  48.  **********************************************************************************************************************/
  49. public class JavaFXSpringApplication extends JavaFXApplicationWithSplash
  50.   {
  51.     // Don't use Slf4j and its static logger - give Main a chance to initialize things
  52.     private final Logger log = LoggerFactory.getLogger(JavaFXSpringApplication.class);

  53.     private ClassPathXmlApplicationContext applicationContext;

  54.     private final List<String> springConfigLocations = new ArrayList<>();

  55.     /*******************************************************************************************************************
  56.      *
  57.      *
  58.      *
  59.      ******************************************************************************************************************/
  60.     @Override @Nonnull
  61.     protected NodeAndDelegate createParent()
  62.       throws IOException
  63.       {
  64.         return NodeAndDelegate.load(getClass(), applicationFxml);
  65.       }

  66.     /*******************************************************************************************************************
  67.      *
  68.      *
  69.      *
  70.      ******************************************************************************************************************/
  71.     @Override
  72.     protected void initializeInBackground()
  73.       {
  74.         log.info("initializeInBackground()");

  75.         try
  76.           {
  77.             logProperties();
  78.             // TODO: workaround for NWRCA-41
  79.             System.setProperty("it.tidalwave.util.spring.ClassScanner.basePackages", "it");

  80.             springConfigLocations.add("classpath*:/META-INF/*AutoBeans.xml");
  81.             final var osName = System.getProperty("os.name", "").toLowerCase();

  82.             if (osName.contains("os x"))
  83.               {
  84.                 springConfigLocations.add("classpath*:/META-INF/*AutoMacOSXBeans.xml");
  85.               }

  86.             if (osName.contains("linux"))
  87.               {
  88.                 springConfigLocations.add("classpath*:/META-INF/*AutoLinuxBeans.xml");
  89.               }

  90.             if (osName.contains("windows"))
  91.               {
  92.                 springConfigLocations.add("classpath*:/META-INF/*AutoWindowsBeans.xml");
  93.               }

  94.             log.info("Loading Spring configuration from {} ...", springConfigLocations);
  95.             applicationContext = new ClassPathXmlApplicationContext(springConfigLocations.toArray(new String[0]));
  96.             applicationContext.registerShutdownHook(); // this actually seems not working, onClosing() does
  97.           }
  98.         catch (Throwable t)
  99.           {
  100.             log.error("", t);
  101.           }
  102.       }

  103.     /*******************************************************************************************************************
  104.      *
  105.      *
  106.      *
  107.      ******************************************************************************************************************/
  108.     @Override
  109.     protected void onStageCreated (@Nonnull final Stage stage,
  110.                                    @Nonnull final NodeAndDelegate applicationNad)
  111.       {
  112.         assert Platform.isFxApplicationThread();
  113.         JavaFXSafeProxyCreator.getJavaFxBinder().setMainWindow(stage);
  114.         runApplicationAssemblers(applicationNad);
  115.         Executors.newSingleThreadExecutor().execute(() -> onStageCreated(applicationContext));
  116.       }

  117.     /*******************************************************************************************************************
  118.      *
  119.      * Invoked when the {@link Stage} is created and the {@link ApplicationContext} has been initialized. Typically
  120.      * the main class overrides this, retrieves a reference to the main controller and boots it.
  121.      * This method is executed in a background thread.
  122.      *
  123.      * @param   applicationContext  the application context
  124.      *
  125.      ******************************************************************************************************************/
  126.     protected void onStageCreated (@Nonnull final ApplicationContext applicationContext)
  127.       {
  128.       }

  129.     /*******************************************************************************************************************
  130.      *
  131.      *
  132.      *
  133.      ******************************************************************************************************************/
  134.     @Override
  135.     protected void onClosing()
  136.       {
  137.         applicationContext.close();
  138.       }

  139.     /*******************************************************************************************************************
  140.      *
  141.      *
  142.      *
  143.      ******************************************************************************************************************/
  144.     private void runApplicationAssemblers (@Nonnull final NodeAndDelegate applicationNad)
  145.       {
  146.         Objects.requireNonNull(applicationContext, "applicationContext is null");
  147.         applicationContext.getBeansOfType(ApplicationPresentationAssembler.class).values()
  148.                 .forEach(a -> a.assemble(applicationNad.getDelegate()));
  149.       }

  150.     /*******************************************************************************************************************
  151.      *
  152.      *
  153.      *
  154.      ******************************************************************************************************************/
  155.     private void logProperties()
  156.       {
  157.         final SortedMap<Object, Object> map = new TreeMap<>(System.getProperties());

  158.         for (final var e : map.entrySet())
  159.           {
  160.             log.debug("{}: {}", e.getKey(), e.getValue());
  161.           }
  162.       }
  163.   }