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 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2016 ForgeRock AS. 016 */ 017 018package org.opends.quicksetup.ui; 019 020import org.opends.quicksetup.util.UIKeyStore; 021import org.opends.quicksetup.Application; 022import org.opends.quicksetup.ButtonName; 023import org.opends.quicksetup.UserData; 024import org.opends.quicksetup.UserDataCertificateException; 025import org.opends.quicksetup.UserDataException; 026import org.opends.quicksetup.WizardStep; 027import org.forgerock.i18n.LocalizableMessage; 028import static org.opends.messages.QuickSetupMessages.*; 029 030import javax.swing.*; 031import java.awt.event.WindowEvent; 032import java.security.cert.X509Certificate; 033import java.util.LinkedHashSet; 034import java.util.Set; 035 036import org.forgerock.i18n.slf4j.LocalizedLogger; 037 038/** 039 * This class represents an application with a wizard GUI that can be run in the 040 * context of QuickSetup. Examples of applications might be 'installer', 041 * and 'uninstaller'. 042 */ 043public abstract class GuiApplication extends Application { 044 045 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 046 047 /** The currently displayed wizard step. */ 048 private WizardStep displayedStep; 049 050 /** The QuickSetupDialog in control. */ 051 private QuickSetupDialog qs; 052 053 private String[] args = {}; 054 055 /** 056 * Constructs an instance of an application. Subclasses 057 * of this application must have a default constructor. 058 */ 059 public GuiApplication() { 060 this.displayedStep = getFirstWizardStep(); 061 } 062 063 /** 064 * Gets the frame title of the GUI application that will be used 065 * in some operating systems. 066 * @return internationalized String representing the frame title 067 */ 068 public abstract LocalizableMessage getFrameTitle(); 069 070 /** 071 * Returns the initial wizard step. 072 * @return Step representing the first step to show in the wizard 073 */ 074 public abstract WizardStep getFirstWizardStep(); 075 076 /** 077 * Called by the quicksetup controller when the user advances to 078 * a new step in the wizard. Applications are expected to manipulate 079 * the QuickSetupDialog to reflect the current step. 080 * 081 * @param step Step indicating the new current step 082 * @param userData UserData representing the data specified by the user 083 * @param dlg QuickSetupDialog hosting the wizard 084 */ 085 public void setDisplayedWizardStep(WizardStep step, 086 UserData userData, 087 QuickSetupDialog dlg) { 088 this.displayedStep = step; 089 090 // First call the panels to do the required updates on their layout 091 dlg.setDisplayedStep(step, userData); 092 setWizardDialogState(dlg, userData, step); 093 } 094 095 /** 096 * Called when the user advances to new step in the wizard. Applications 097 * are expected to manipulate the QuickSetupDialog to reflect the current 098 * step. 099 * @param dlg QuickSetupDialog hosting the wizard 100 * @param userData UserData representing the data specified by the user 101 * @param step Step indicating the new current step 102 */ 103 public abstract void setWizardDialogState(QuickSetupDialog dlg, 104 UserData userData, 105 WizardStep step); 106 107 /** 108 * Returns the tab formatted. 109 * @return the tab formatted. 110 */ 111 protected LocalizableMessage getTab() 112 { 113 return formatter.getTab(); 114 } 115 116 /** 117 * Called by the controller when the window is closing. The application 118 * can take application specific actions here. 119 * @param dlg QuickSetupDialog that will be closing 120 * @param evt The event from the Window indicating closing 121 */ 122 public abstract void windowClosing(QuickSetupDialog dlg, WindowEvent evt); 123 124 /** 125 * This method is called when we detected that there is something installed 126 * we inform of this to the user and the user wants to proceed with the 127 * installation destroying the contents of the data and the configuration 128 * in the current installation. 129 */ 130 public void forceToDisplay() { 131 // This is really only appropriate for Installer. 132 // The default implementation is to do nothing. 133 // The Installer application overrides this with 134 // whatever it needs. 135 } 136 137 /** 138 * Called before the application cancels its operation, giving the 139 * user a chance to confirm the cancellation action. 140 * @param qs QuickSetup that can be used for confirming 141 * @return boolean where true indicates that the user answered 142 * affirmatively to the cancelation confirmation 143 */ 144 public boolean confirmCancel(QuickSetup qs) { 145 return qs.displayConfirmation( 146 INFO_CONFIRM_CANCEL_PROMPT.get(), 147 INFO_CONFIRM_CANCEL_TITLE.get()); 148 } 149 150 /** 151 * Get the name of the button that will receive initial focus. 152 * @return ButtonName of the button to receive initial focus 153 */ 154 public abstract ButtonName getInitialFocusButtonName(); 155 156 /** 157 * Creates the main panel for the wizard dialog. 158 * @param dlg QuickSetupDialog used 159 * @return JPanel frame panel 160 */ 161 public JPanel createFramePanel(QuickSetupDialog dlg) { 162 return new FramePanel(dlg.getStepsPanel(), 163 dlg.getCurrentStepPanel(), 164 dlg.getButtonsPanel()); 165 } 166 167 /** 168 * Returns the set of wizard steps used in this application's wizard. 169 * @return Set of Step objects representing wizard steps 170 */ 171 public abstract Set<? extends WizardStep> getWizardSteps(); 172 173 /** 174 * Creates a wizard panel given a specific step. 175 * @param step for which a panel representation should be created 176 * @return QuickSetupStepPanel for representing the <code>step</code> 177 */ 178 public abstract QuickSetupStepPanel createWizardStepPanel(WizardStep step); 179 180 /** 181 * Gets the next step in the wizard given a current step. 182 * @param step Step the current step 183 * @return Step the next step 184 */ 185 public abstract WizardStep getNextWizardStep(WizardStep step); 186 187 /** 188 * Gets the previous step in the wizard given a current step. 189 * @param step Step the current step 190 * @return Step the previous step 191 */ 192 public abstract WizardStep getPreviousWizardStep(WizardStep step); 193 194 /** 195 * Gets the finished step in the wizard. 196 * @return Step the finished step 197 */ 198 public abstract WizardStep getFinishedStep(); 199 200 /** 201 * Gets the currently displayed wizard step. 202 * @return WizardStep being displayed. 203 */ 204 public WizardStep getCurrentWizardStep() { 205 return displayedStep; 206 } 207 208 /** 209 * Indicates whether the provided <code>step</code> is a sub step or not. 210 * @param step WizardStep for which the return value indicates whether 211 * or not is a sub step. 212 * @return boolean where true indicates the provided <code>step</code> is a 213 * substep. 214 */ 215 public boolean isSubStep(WizardStep step) 216 { 217 return false; 218 } 219 220 /** 221 * Indicates whether the provided <code>step</code> is visible or not 222 * depending on the contents of the UserData object that is provided. 223 * @param step WizardStep for which the return value indicates whether 224 * or not is visible. 225 * @param userData the UserData to be used to determine if the step is 226 * visible or not. 227 * @return boolean where true indicates the provided <code>step</code> is 228 * visible. 229 */ 230 public boolean isVisible(WizardStep step, UserData userData) 231 { 232 return true; 233 } 234 235 /** 236 * Indicates whether the provided <code>step</code> is visible or not 237 * depending on the contents of the QuickSetup object that is provided. 238 * @param step WizardStep for which the return value indicates whether 239 * or not is visible. 240 * @param qs the QuickSetup to be used to determine if the step is 241 * visible or not. 242 * @return boolean where true indicates the provided <code>step</code> is 243 * visible. 244 */ 245 public boolean isVisible(WizardStep step, QuickSetup qs) 246 { 247 return true; 248 } 249 250 /** 251 * Returns the list of all the steps in an ordered manner. This is required 252 * because in the case of an application with substeps the user of the other 253 * interfaces is not enough. This is a default implementation that uses 254 * the getNextWizardStep method to calculate the list that work for 255 * applications with no substeps. 256 * @return a list containing ALL the steps (including substeps) in an ordered 257 * manner. 258 */ 259 public LinkedHashSet<WizardStep> getOrderedSteps() 260 { 261 LinkedHashSet<WizardStep> orderedSteps = new LinkedHashSet<>(); 262 WizardStep step = getFirstWizardStep(); 263 orderedSteps.add(step); 264 while (null != (step = getNextWizardStep(step))) { 265 orderedSteps.add(step); 266 } 267 return orderedSteps; 268 } 269 270 /** 271 * Indicates whether the user is allowed to return to a previous 272 * step from <code>step</code>. 273 * @param step WizardStep for which the the return value indicates whether 274 * or not the user can return to a previous step 275 * @return boolean where true indicates the user can return to a previous 276 * step from <code>step</code> 277 */ 278 public boolean canGoBack(WizardStep step) { 279 return !getFirstWizardStep().equals(step); 280 } 281 282 /** 283 * Indicates whether the user is allowed to move to a new 284 * step from <code>step</code>. 285 * @param step WizardStep for which the the return value indicates whether 286 * or not the user can move to a new step 287 * @return boolean where true indicates the user can move to a new 288 * step from <code>step</code> 289 */ 290 public boolean canGoForward(WizardStep step) { 291 return !step.isProgressStep() && getNextWizardStep(step) != null; 292 } 293 294 /** 295 * Indicates whether the user is allowed to finish the wizard from 296 * <code>step</code>. 297 * @param step WizardStep for which the the return value indicates whether 298 * or not the user can finish the wizard 299 * @return boolean where true indicates the user can finish the wizard 300 */ 301 public abstract boolean canFinish(WizardStep step); 302 303 /** 304 * Called when the user has clicked the 'previous' button. 305 * @param cStep WizardStep at which the user clicked the previous button 306 * @param qs QuickSetup controller 307 */ 308 public abstract void previousClicked(WizardStep cStep, QuickSetup qs); 309 310 /** 311 * Called when the user has clicked the 'finish' button. 312 * @param cStep WizardStep at which the user clicked the previous button 313 * @param qs QuickSetup controller 314 * @return boolean that the application uses to indicate the the 315 * application should be launched. If false, the application is 316 * responsible for updating the user data for the final screen and 317 * launching the application if this is the desired behavior. 318 */ 319 public abstract boolean finishClicked(final WizardStep cStep, 320 final QuickSetup qs); 321 322 /** 323 * Called when the user has clicked the 'next' button. 324 * @param cStep WizardStep at which the user clicked the next button 325 * @param qs QuickSetup controller 326 */ 327 public abstract void nextClicked(WizardStep cStep, QuickSetup qs); 328 329 /** 330 * Called when the user has clicked the 'close' button. 331 * @param cStep WizardStep at which the user clicked the close button 332 * @param qs QuickSetup controller 333 */ 334 public void closeClicked(WizardStep cStep, QuickSetup qs) { 335 qs.quit(); 336 } 337 338 /** 339 * Called when the user has clicked the 'quit' button. 340 * @param step WizardStep at which the user clicked the quit button 341 * @param qs QuickSetup controller 342 */ 343 public void quitClicked(WizardStep step, QuickSetup qs) { 344 qs.quit(); 345 } 346 347 /** 348 * Called whenever this application should update its user data from 349 * values found in QuickSetup. 350 * @param cStep current wizard step 351 * @param qs QuickSetup controller 352 * @throws org.opends.quicksetup.UserDataException if there is a problem with 353 * the data 354 */ 355 public abstract void updateUserData(WizardStep cStep, QuickSetup qs) 356 throws UserDataException; 357 358 /** 359 * Gets the key for the close button's tool tip text. 360 * @return String key of the text in the resource bundle 361 */ 362 public LocalizableMessage getCloseButtonToolTip() { 363 return INFO_CLOSE_BUTTON_TOOLTIP.get(); 364 } 365 366 /** 367 * Gets the key for the quit button's tool tip text. 368 * @return String key of the text in the resource bundle 369 */ 370 public LocalizableMessage getQuitButtonToolTip() { 371 return INFO_QUIT_BUTTON_INSTALL_TOOLTIP.get(); 372 } 373 374 /** 375 * Gets the key for the finish button's tool tip text. 376 * @return String key of the text in the resource bundle 377 */ 378 public LocalizableMessage getFinishButtonToolTip() { 379 return INFO_FINISH_BUTTON_TOOLTIP.get(); 380 } 381 382 /** 383 * Gets the key for the finish button's label. 384 * @return String key of the text in the resource bundle 385 */ 386 public LocalizableMessage getFinishButtonLabel() { 387 return INFO_FINISH_BUTTON_LABEL.get(); 388 } 389 390 /** 391 * Indicates whether the finish button must be placed on the left (close to 392 * "Next" button) or on the right (close to "Quit" button). 393 * @return <CODE>true</CODE> if the finish button must be placed on the left 394 * and <CODE>false</CODE> otherwise. 395 */ 396 public boolean finishOnLeft() 397 { 398 return true; 399 } 400 401 /** 402 * Updates the list of certificates accepted by the user in the trust manager 403 * based on the information stored in the UserDataCertificateException we got 404 * when trying to connect in secure mode. 405 * @param ce the UserDataCertificateException that contains the information to 406 * be used. 407 * @param acceptPermanently whether the certificate must be accepted 408 * permanently or not. 409 */ 410 protected void acceptCertificateForException(UserDataCertificateException ce, 411 boolean acceptPermanently) 412 { 413 X509Certificate[] chain = ce.getChain(); 414 String authType = ce.getAuthType(); 415 String host = ce.getHost(); 416 417 if (chain != null && authType != null && host != null) 418 { 419 logger.info(LocalizableMessage.raw("Accepting certificate presented by host "+host)); 420 getTrustManager().acceptCertificate(chain, authType, host); 421 } 422 else 423 { 424 if (chain == null) 425 { 426 logger.warn(LocalizableMessage.raw( 427 "The chain is null for the UserDataCertificateException")); 428 } 429 if (authType == null) 430 { 431 logger.warn(LocalizableMessage.raw( 432 "The auth type is null for the UserDataCertificateException")); 433 } 434 if (host == null) 435 { 436 logger.warn(LocalizableMessage.raw( 437 "The host is null for the UserDataCertificateException")); 438 } 439 } 440 if (acceptPermanently && chain != null) 441 { 442 try 443 { 444 UIKeyStore.acceptCertificate(chain); 445 } 446 catch (Throwable t) 447 { 448 logger.warn(LocalizableMessage.raw("Error accepting certificate: "+t, t)); 449 } 450 } 451 } 452 453 /** 454 * Gets the amount of addition pixels added to the height 455 * of the tallest panel in order to size the wizard for 456 * asthetic reasons. 457 * @return int height to add 458 */ 459 public int getExtraDialogHeight() { 460 return 0; 461 } 462 463 /** 464 * Sets the QuickSetupDialog driving this application. 465 * @param dialog QuickSetupDialog driving this application 466 */ 467 public void setQuickSetupDialog(QuickSetupDialog dialog) { 468 this.qs = dialog; 469 } 470 471 /** 472 * Sets the arguments passed in the command-line to launch the application. 473 * @param args the arguments passed in the command-line to launch the 474 * application. 475 */ 476 public void setUserArguments(String[] args) 477 { 478 this.args = args; 479 } 480 481 /** 482 * Returns the arguments passed in the command-line to launch the application. 483 * @return the arguments passed in the command-line to launch the application. 484 */ 485 public String[] getUserArguments() 486 { 487 return args; 488 } 489}