001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2015 ForgeRock AS. 026 */ 027package org.opends.quicksetup; 028 029import static org.opends.messages.QuickSetupMessages.*; 030 031import java.awt.Dimension; 032import java.awt.Frame; 033import java.awt.Graphics; 034import java.awt.Image; 035import java.awt.MediaTracker; 036import java.awt.Toolkit; 037import java.awt.Window; 038 039import javax.swing.SwingUtilities; 040 041import org.opends.quicksetup.ui.Utilities; 042 043/** 044 * This is the class that displays a splash screen and in the background it will 045 * create QuickSetup object. 046 * 047 * The main method of this class is directly called by the Java Web Start 048 * mechanism to launch the JWS setup. 049 * 050 * This class tries to minimize the time to be displayed. So it does the loading 051 * of the setup class in runtime once we already have displayed the splash 052 * screen. This is why the quickSetup variable is of type Object. 053 * 054 * This class can be reused by simply overwriting the methods 055 * constructApplication() and displayApplication(). 056 */ 057public class SplashScreen extends Window 058{ 059 private static final long serialVersionUID = 8918803902867388766L; 060 061 private Image image; 062 063 private Object quickSetup; 064 065 private Class<?> quickSetupClass; 066 067 /** Constant for the display of the splash screen. */ 068 private static final int MIN_SPLASH_DISPLAY = 3000; 069 070 /** 071 * The main method for this class. 072 * It can be called from the event thread and outside the event thread. 073 * @param args arguments to be passed to the method QuickSetup.initialize 074 */ 075 public static void main(String[] args) 076 { 077 SplashScreen screen = new SplashScreen(); 078 screen.display(args); 079 } 080 081 /** {@inheritDoc} */ 082 public void update(Graphics g) 083 { 084 paint(g); 085 } 086 087 /** {@inheritDoc} */ 088 public void paint(Graphics g) 089 { 090 g.drawImage(image, 0, 0, this); 091 } 092 093 /** Protected constructor to force to use the main method. */ 094 protected SplashScreen() 095 { 096 super(new Frame()); 097 try 098 { 099 image = getSplashImage(); 100 MediaTracker mt = new MediaTracker(this); 101 mt.addImage(image, 0); 102 mt.waitForID(0); 103 104 int width = image.getWidth(this); 105 int height = image.getHeight(this); 106 setPreferredSize(new Dimension(width, height)); 107 setSize(width, height); 108 Utilities.centerOnScreen(this); 109 } catch (Exception ex) 110 { 111 ex.printStackTrace(); // Bug 112 } 113 } 114 115 /** 116 * The method used to display the splash screen. It will also call create 117 * the application associated with this SplashScreen and display it. 118 * It can be called from the event thread and outside the event thread. 119 * @param args arguments to be passed to the method QuickSetup.initialize 120 */ 121 protected void display(String[] args) 122 { 123 if (SwingUtilities.isEventDispatchThread()) 124 { 125 final String[] fArgs = args; 126 Thread t = new Thread(new Runnable() 127 { 128 public void run() 129 { 130 mainOutsideEventThread(fArgs); 131 } 132 }); 133 t.start(); 134 } else 135 { 136 mainOutsideEventThread(args); 137 } 138 } 139 140 /** 141 * This method creates the image directly instead of using UIFactory to reduce 142 * class loading. 143 * @return the splash image. 144 */ 145 private Image getSplashImage() 146 { 147 String resource = INFO_SPLASH_ICON.get().toString(); 148 resource = "org/opends/quicksetup/" + resource; 149 return Toolkit.getDefaultToolkit().createImage( 150 getClass().getClassLoader().getResource(resource)); 151 } 152 153 /** 154 * This is basically the method that is execute in SplashScreen.main but it 155 * it assumes that is being called outside the event thread. 156 * 157 * @param args arguments to be passed to the method QuickSetup.initialize. 158 */ 159 private void mainOutsideEventThread(String[] args) 160 { 161 displaySplashScreen(); 162 long splashDisplayStartTime = System.currentTimeMillis(); 163 constructApplication(args); 164 sleepIfNecessary(splashDisplayStartTime); 165 disposeSplashScreen(); 166 displayApplication(); 167 } 168 169 /** 170 * This methods displays the splash screen. 171 * This method assumes that is being called outside the event thread. 172 */ 173 private void displaySplashScreen() 174 { 175 try 176 { 177 SwingUtilities.invokeAndWait(new Runnable() 178 { 179 public void run() 180 { 181 setVisible(true); 182 } 183 }); 184 } catch (Exception ex) 185 { 186 ex.printStackTrace(); 187 } 188 } 189 190 /** 191 * This methods constructs the objects before displaying them. 192 * This method assumes that is being called outside the event thread. 193 * This method can be overwritten by subclasses to construct other objects 194 * different than the Quick Setup. 195 * @param args arguments passed in the main of this class. 196 */ 197 protected void constructApplication(String[] args) 198 { 199 try 200 { 201 quickSetupClass = Class.forName("org.opends.quicksetup.ui.QuickSetup"); 202 quickSetup = quickSetupClass.newInstance(); 203 quickSetupClass.getMethod("initialize", new Class[] 204 { String[].class }).invoke(quickSetup, new Object[] 205 { args }); 206 } catch (Exception e) 207 { 208 InternalError error = 209 new InternalError("Failed to invoke initialize method"); 210 error.initCause(e); 211 throw error; 212 } 213 } 214 215 /** 216 * This method displays the QuickSetup dialog. 217 * @see org.opends.quicksetup.ui.QuickSetup#display 218 * This method assumes that is being called outside the event thread. 219 * This method can be overwritten by subclasses to construct other objects 220 * different than the Quick Setup. 221 */ 222 protected void displayApplication() 223 { 224 try 225 { 226 SwingUtilities.invokeAndWait(new Runnable() 227 { 228 public void run() 229 { 230 try 231 { 232 quickSetupClass.getMethod("display").invoke(quickSetup); 233 } catch (Exception e) 234 { 235 InternalError error = 236 new InternalError("Failed to invoke display method"); 237 error.initCause(e); 238 throw error; 239 } 240 } 241 }); 242 } catch (Exception ex) 243 { 244 // do nothing; 245 } 246 } 247 248 /** 249 * Disposes the splash screen. 250 * This method assumes that is being called outside the event thread. 251 */ 252 private void disposeSplashScreen() 253 { 254 try 255 { 256 SwingUtilities.invokeAndWait(new Runnable() 257 { 258 public void run() 259 { 260 setVisible(false); 261 dispose(); 262 } 263 }); 264 } catch (Exception ex) 265 { 266 // do nothing; 267 } 268 } 269 270 /** 271 * This method just executes an sleep depending on how long the splash 272 * screen has been displayed. The idea of calling this method is to have the 273 * splash screen displayed a minimum time (specified by 274 * MIN_SPLASH_DISPLAY). 275 * @param splashDisplayStartTime the time in milliseconds when the splash 276 * screen started displaying. 277 */ 278 private void sleepIfNecessary(long splashDisplayStartTime) 279 { 280 long t2 = System.currentTimeMillis(); 281 282 long sleepTime = MIN_SPLASH_DISPLAY - (t2 - splashDisplayStartTime); 283 284 if (sleepTime > 0) 285 { 286 try 287 { 288 Thread.sleep(sleepTime); 289 } catch (Exception ex) 290 { 291 // do nothing; 292 } 293 } 294 } 295}