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-2016 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 private TempLogFile tempLogFile; 054 055 /** Constant for the display of the splash screen. */ 056 private static final int MIN_SPLASH_DISPLAY = 3000; 057 058 /** 059 * The main method for this class. 060 * It can be called from the event thread and outside the event thread. 061 * 062 * @param tempLogFile 063 * temporary log file where messages will be logged 064 * @param args 065 * arguments to be passed to the method QuickSetup.initialize 066 */ 067 public static void main(final TempLogFile tempLogFile, String[] args) 068 { 069 SplashScreen screen = new SplashScreen(); 070 screen.tempLogFile = tempLogFile; 071 screen.display(args); 072 } 073 074 @Override 075 public void update(Graphics g) 076 { 077 paint(g); 078 } 079 080 @Override 081 public void paint(Graphics g) 082 { 083 g.drawImage(image, 0, 0, this); 084 } 085 086 /** Protected constructor to force to use the main method. */ 087 protected SplashScreen() 088 { 089 super(new Frame()); 090 try 091 { 092 image = getSplashImage(); 093 MediaTracker mt = new MediaTracker(this); 094 mt.addImage(image, 0); 095 mt.waitForID(0); 096 097 int width = image.getWidth(this); 098 int height = image.getHeight(this); 099 setPreferredSize(new Dimension(width, height)); 100 setSize(width, height); 101 Utilities.centerOnScreen(this); 102 } catch (Exception ex) 103 { 104 ex.printStackTrace(); // Bug 105 } 106 } 107 108 /** 109 * The method used to display the splash screen. It will also call create 110 * the application associated with this SplashScreen and display it. 111 * It can be called from the event thread and outside the event thread. 112 * @param args arguments to be passed to the method QuickSetup.initialize 113 */ 114 protected void display(String[] args) 115 { 116 if (SwingUtilities.isEventDispatchThread()) 117 { 118 final String[] fArgs = args; 119 Thread t = new Thread(new Runnable() 120 { 121 @Override 122 public void run() 123 { 124 mainOutsideEventThread(fArgs); 125 } 126 }); 127 t.start(); 128 } else 129 { 130 mainOutsideEventThread(args); 131 } 132 } 133 134 /** 135 * This method creates the image directly instead of using UIFactory to reduce 136 * class loading. 137 * @return the splash image. 138 */ 139 private Image getSplashImage() 140 { 141 String resource = INFO_SPLASH_ICON.get().toString(); 142 resource = "org/opends/quicksetup/" + resource; 143 return Toolkit.getDefaultToolkit().createImage( 144 getClass().getClassLoader().getResource(resource)); 145 } 146 147 /** 148 * This is basically the method that is execute in SplashScreen.main but it 149 * it assumes that is being called outside the event thread. 150 * 151 * @param args arguments to be passed to the method QuickSetup.initialize. 152 */ 153 private void mainOutsideEventThread(String[] args) 154 { 155 displaySplashScreen(); 156 long splashDisplayStartTime = System.currentTimeMillis(); 157 constructApplication(args); 158 sleepIfNecessary(splashDisplayStartTime); 159 disposeSplashScreen(); 160 displayApplication(); 161 } 162 163 /** 164 * This methods displays the splash screen. 165 * This method assumes that is being called outside the event thread. 166 */ 167 private void displaySplashScreen() 168 { 169 try 170 { 171 SwingUtilities.invokeAndWait(new Runnable() 172 { 173 @Override 174 public void run() 175 { 176 setVisible(true); 177 } 178 }); 179 } catch (Exception ex) 180 { 181 ex.printStackTrace(); 182 } 183 } 184 185 /** 186 * This methods constructs the objects before displaying them. 187 * This method assumes that is being called outside the event thread. 188 * This method can be overwritten by subclasses to construct other objects 189 * different than the Quick Setup. 190 * @param args arguments passed in the main of this class. 191 */ 192 protected void constructApplication(String[] args) 193 { 194 try 195 { 196 quickSetupClass = Class.forName("org.opends.quicksetup.ui.QuickSetup"); 197 quickSetup = quickSetupClass.newInstance(); 198 quickSetupClass.getMethod("initialize", new Class[] { TempLogFile.class, String[].class }) 199 .invoke(quickSetup, tempLogFile, args); 200 } catch (Exception e) 201 { 202 InternalError error = 203 new InternalError("Failed to invoke initialize method"); 204 error.initCause(e); 205 throw error; 206 } 207 } 208 209 /** 210 * This method displays the QuickSetup dialog. 211 * @see org.opends.quicksetup.ui.QuickSetup#display 212 * This method assumes that is being called outside the event thread. 213 * This method can be overwritten by subclasses to construct other objects 214 * different than the Quick Setup. 215 */ 216 protected void displayApplication() 217 { 218 try 219 { 220 SwingUtilities.invokeAndWait(new Runnable() 221 { 222 @Override 223 public void run() 224 { 225 try 226 { 227 quickSetupClass.getMethod("display").invoke(quickSetup); 228 } catch (Exception e) 229 { 230 InternalError error = 231 new InternalError("Failed to invoke display method"); 232 error.initCause(e); 233 throw error; 234 } 235 } 236 }); 237 } catch (Exception ex) 238 { 239 // do nothing; 240 } 241 } 242 243 /** 244 * Disposes the splash screen. 245 * This method assumes that is being called outside the event thread. 246 */ 247 private void disposeSplashScreen() 248 { 249 try 250 { 251 SwingUtilities.invokeAndWait(new Runnable() 252 { 253 @Override 254 public void run() 255 { 256 setVisible(false); 257 dispose(); 258 } 259 }); 260 } catch (Exception ex) 261 { 262 // do nothing; 263 } 264 } 265 266 /** 267 * This method just executes an sleep depending on how long the splash 268 * screen has been displayed. The idea of calling this method is to have the 269 * splash screen displayed a minimum time (specified by 270 * MIN_SPLASH_DISPLAY). 271 * @param splashDisplayStartTime the time in milliseconds when the splash 272 * screen started displaying. 273 */ 274 private void sleepIfNecessary(long splashDisplayStartTime) 275 { 276 long t2 = System.currentTimeMillis(); 277 278 long sleepTime = MIN_SPLASH_DISPLAY - (t2 - splashDisplayStartTime); 279 280 if (sleepTime > 0) 281 { 282 try 283 { 284 Thread.sleep(sleepTime); 285 } catch (Exception ex) 286 { 287 // do nothing; 288 } 289 } 290 } 291}