1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.appmanager; 27 28 import com.sun.javafx.stage.WindowManager; 29 import javafx.application.Application; 30 import javafx.application.Platform; 31 import javafx.stage.Stage; 32 import com.sun.javafx.stage.StageHelper; 33 34 public final class FxApplicationManager { 35 private static FxApplicationManager instance; 36 37 public static synchronized FxApplicationManager getInstance() { 38 if (instance == null) { 39 initializePlatform(); 40 instance = new FxApplicationManager(); 41 } 42 43 return instance; 44 } 45 46 public FxApplicationInstance start( 47 final ClassLoader appClassLoader, 48 final String appClass) throws Exception { 49 final Application application = 50 createFxApplication(appClassLoader, appClass); 51 application.init(); 52 53 final StartAction startAction = 54 new StartAction(appClassLoader, application); 55 Platform.runLater(startAction); 56 57 return startAction.getResult(); 58 } 59 60 private static void initializePlatform() { 61 final ThreadGroup fxPlatformThreadGroup = 62 new ThreadGroup(getTopLevelThreadGroup(), "FX Platform"); 63 new Thread(fxPlatformThreadGroup, "FX Platform") { 64 @Override 65 public void run() { 66 Application.launch(BootstrapApplication.class); 67 } 68 }.start(); 69 try { 70 BootstrapApplication.waitForStart(); 71 } catch (final InterruptedException e) { 72 // ignore 73 } 74 } 75 76 private static Application createFxApplication( 77 final ClassLoader appClassLoader, 78 final String appClassName) throws ClassNotFoundException, 79 InstantiationException, 80 IllegalAccessException { 81 final Class<?> appClass = appClassLoader.loadClass(appClassName); 82 if (!Application.class.isAssignableFrom(appClass)) { 83 throw new ClassNotFoundException("FX application class not found"); 84 } 85 86 return ((Class<Application>) appClass).newInstance(); 87 } 88 89 private static ThreadGroup getTopLevelThreadGroup() { 90 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 91 while (threadGroup.getParent() != null) { 92 threadGroup = threadGroup.getParent(); 93 } 94 95 return threadGroup; 96 } 97 98 private static final class AppInstanceImpl 99 implements FxApplicationInstance { 100 private final ClassLoader appClassLoader; 101 private final Application application; 102 103 public AppInstanceImpl(final ClassLoader appClassLoader, 104 final Application application) { 105 this.appClassLoader = appClassLoader; 106 this.application = application; 107 } 108 109 @Override 110 public void stop() { 111 final StopAction stopAction = new StopAction(appClassLoader, 112 application); 113 114 Platform.runLater(stopAction); 115 try { 116 stopAction.waitForCompletion(); 117 } catch (final InterruptedException e) { 118 // ignore 119 } 120 } 121 } 122 123 private static final class StartAction implements Runnable { 124 private final ClassLoader appClassLoader; 125 private final Application application; 126 127 private Exception exception; 128 private FxApplicationInstance result; 129 130 public StartAction(final ClassLoader appClassLoader, 131 final Application application) { 132 this.appClassLoader = appClassLoader; 133 this.application = application; 134 } 135 136 @Override 137 public void run() { 138 final Thread currentThread = Thread.currentThread(); 139 final ClassLoader oldContextClassLoader = 140 currentThread.getContextClassLoader(); 141 142 currentThread.setContextClassLoader(appClassLoader); 143 try { 144 try { 145 final Stage appPrimaryStage = new Stage(); 146 StageHelper.setPrimary(appPrimaryStage, true); 147 application.start(appPrimaryStage); 148 } finally { 149 currentThread.setContextClassLoader(oldContextClassLoader); 150 } 151 } catch (final Exception e) { 152 synchronized (this) { 153 exception = e; 154 notifyAll(); 155 } 156 return; 157 } 158 159 synchronized (this) { 160 result = new AppInstanceImpl(appClassLoader, application); 161 notifyAll(); 162 } 163 } 164 165 public synchronized FxApplicationInstance getResult() throws Exception { 166 while (result == null) { 167 if (exception != null) { 168 throw exception; 169 } 170 171 wait(); 172 } 173 174 return result; 175 } 176 } 177 178 private static final class StopAction implements Runnable { 179 private final ClassLoader appClassLoader; 180 private final Application application; 181 182 private boolean finished; 183 184 public StopAction(final ClassLoader appClassLoader, 185 final Application application) { 186 this.appClassLoader = appClassLoader; 187 this.application = application; 188 } 189 190 @Override 191 public void run() { 192 try { 193 WindowManager.closeApplicationWindows(appClassLoader); 194 try { 195 application.stop(); 196 } catch (final Exception e) { 197 } 198 } finally { 199 synchronized (this) { 200 finished = true; 201 notifyAll(); 202 } 203 } 204 } 205 206 public synchronized void waitForCompletion() 207 throws InterruptedException { 208 while (!finished) { 209 wait(); 210 } 211 } 212 } 213 }