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