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 2008-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027 028package org.opends.guitools.controlpanel.ui; 029 030import static org.opends.messages.AdminToolMessages.*; 031 032import java.awt.GridBagConstraints; 033import java.io.File; 034import java.util.ArrayList; 035import java.util.Collection; 036import java.util.HashSet; 037import java.util.LinkedHashSet; 038import java.util.Set; 039import java.util.TreeSet; 040 041import javax.swing.JLabel; 042import javax.swing.JTextField; 043import javax.swing.SwingUtilities; 044import javax.swing.event.ListSelectionEvent; 045import javax.swing.event.ListSelectionListener; 046 047import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 048import org.opends.guitools.controlpanel.datamodel.BackupDescriptor; 049import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 050import org.opends.guitools.controlpanel.datamodel.ServerDescriptor; 051import org.opends.guitools.controlpanel.event.BackupCreatedEvent; 052import org.opends.guitools.controlpanel.event.BackupCreatedListener; 053import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 054import org.opends.guitools.controlpanel.task.Task; 055import org.opends.guitools.controlpanel.util.Utilities; 056import org.forgerock.i18n.LocalizableMessage; 057import org.opends.server.tools.RestoreDB; 058 059/** 060 * The panel that appears when the user wants to restore from a backup. 061 * 062 */ 063public class RestorePanel extends BackupListPanel 064implements BackupCreatedListener 065{ 066 private static final long serialVersionUID = -205585323128518051L; 067 private ListSelectionListener listener; 068 private JLabel lBackupID; 069 private JTextField backupID; 070 071 /** 072 * Constructor of the panel. 073 * 074 */ 075 public RestorePanel() 076 { 077 super(); 078 createLayout(); 079 } 080 081 /** {@inheritDoc} */ 082 public LocalizableMessage getTitle() 083 { 084 return INFO_CTRL_PANEL_RESTORE_PANEL_TITLE.get(); 085 } 086 087 /** {@inheritDoc} */ 088 public void backupCreated(BackupCreatedEvent ev) 089 { 090 boolean refreshList = false; 091 File f = new File(parentDirectory.getText()); 092 File fBackup = ev.getBackupDescriptor().getPath(); 093 if (fBackup.equals(f)) 094 { 095 refreshList = true; 096 } 097 else 098 { 099 f = f.getParentFile(); 100 if (f != null) 101 { 102 refreshList = fBackup.equals(f); 103 } 104 } 105 if (refreshList && isVisible()) 106 { 107 // If not visible the list will be refreshed next time the dialog is 108 // opened. 109 SwingUtilities.invokeLater(new Runnable() 110 { 111 public void run() 112 { 113 refreshList(); 114 } 115 }); 116 } 117 } 118 119 /** {@inheritDoc} */ 120 public void setInfo(ControlPanelInfo info) 121 { 122 super.setInfo(info); 123 info.addBackupCreatedListener(this); 124 } 125 126 /** {@inheritDoc} */ 127 public void toBeDisplayed(boolean visible) 128 { 129 if (visible) 130 { 131 listener.valueChanged(null); 132 } 133 } 134 135 /** {@inheritDoc} */ 136 public void configurationChanged(ConfigurationChangeEvent ev) 137 { 138 final ServerDescriptor desc = ev.getNewDescriptor(); 139 SwingUtilities.invokeLater(new Runnable() 140 { 141 /** {@inheritDoc} */ 142 public void run() 143 { 144 lBackupID.setVisible(!desc.isLocal()); 145 backupID.setVisible(!desc.isLocal()); 146 } 147 }); 148 super.configurationChanged(ev); 149 updateErrorPaneAndOKButtonIfAuthRequired(desc, 150 isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_RESTORE.get() : 151 INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname())); 152 } 153 154 /** {@inheritDoc} */ 155 protected void verifyBackupClicked() 156 { 157 LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>(); 158 // Launch the task in another progress dialog. 159 ProgressDialog dlg = new ProgressDialog( 160 Utilities.createFrame(), 161 Utilities.getParentDialog(this), 162 INFO_CTRL_PANEL_VERIFY_BACKUP_TITLE.get(), getInfo()); 163 RestoreTask newTask = new RestoreTask(getInfo(), dlg, true); 164 for (Task task : getInfo().getTasks()) 165 { 166 task.canLaunch(newTask, errors); 167 } 168 if (errors.isEmpty()) 169 { 170 BackupDescriptor backup = getSelectedBackup(); 171 launchOperation(newTask, 172 INFO_CTRL_PANEL_VERIFYING_BACKUP_SUMMARY.get(backup.getID()), 173 INFO_CTRL_PANEL_VERIFYING_BACKUP_SUCCESSFUL_SUMMARY.get(), 174 INFO_CTRL_PANEL_VERIFYING_BACKUP_SUCCESSFUL_DETAILS.get(), 175 ERR_CTRL_PANEL_VERIFYING_BACKUP_ERROR_SUMMARY.get(), 176 null, 177 ERR_CTRL_PANEL_VERIFYING_BACKUP_ERROR_DETAILS, 178 dlg); 179 dlg.setVisible(true); 180 } 181 else 182 { 183 displayErrorDialog(errors); 184 } 185 } 186 187 /** 188 * Creates the layout of the panel (but the contents are not populated here). 189 */ 190 private void createLayout() 191 { 192 GridBagConstraints gbc = new GridBagConstraints(); 193 gbc.gridx = 0; 194 gbc.gridy = 0; 195 196 gbc.gridwidth = 3; 197 addErrorPane(gbc); 198 199 super.createLayout(gbc); 200 201 gbc.insets.top = 10; 202 gbc.gridx = 0; 203 gbc.gridy ++; 204 gbc.insets.left = 0; 205 gbc.gridwidth = 1; 206 lBackupID = Utilities.createPrimaryLabel( 207 INFO_CTRL_PANEL_BACKUP_ID_LABEL.get()); 208 add(lBackupID, gbc); 209 backupID = Utilities.createMediumTextField(); 210 gbc.weightx = 0.0; 211 gbc.gridx = 1; 212 gbc.insets.left = 10; 213 gbc.insets.right = 40; 214 gbc.fill = GridBagConstraints.HORIZONTAL; 215 gbc.anchor = GridBagConstraints.WEST; 216 gbc.gridwidth = 2; 217 add(backupID, gbc); 218 219 listener = new ListSelectionListener() 220 { 221 public void valueChanged(ListSelectionEvent ev) 222 { 223 BackupDescriptor backup = getSelectedBackup(); 224 setEnabledOK(backup != null && !errorPane.isVisible()); 225 } 226 }; 227 backupList.getSelectionModel().addListSelectionListener(listener); 228 229 addBottomGlue(gbc); 230 } 231 232 /** {@inheritDoc} */ 233 protected void checkOKButtonEnable() 234 { 235 listener.valueChanged(null); 236 } 237 238 /** {@inheritDoc} */ 239 public void okClicked() 240 { 241 setPrimaryValid(lPath); 242 setPrimaryValid(lAvailableBackups); 243 setPrimaryValid(lBackupID); 244 245 final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>(); 246 247 BackupDescriptor backup = getSelectedBackup(); 248 249 if (isLocal()) 250 { 251 boolean selected = backupList.isVisible() && backup != null; 252 if (!selected) 253 { 254 if (backupList.getRowCount() == 0) 255 { 256 setPrimaryInvalid(lPath); 257 errors.add(ERR_CTRL_PANEL_NO_PARENT_BACKUP_TO_VERIFY.get()); 258 } 259 else 260 { 261 errors.add(ERR_CTRL_PANEL_REQUIRED_BACKUP_TO_VERIFY.get()); 262 } 263 setPrimaryInvalid(lAvailableBackups); 264 } 265 } 266 else 267 { 268 String parentPath = parentDirectory.getText(); 269 if (parentPath == null || parentPath.trim().equals("")) 270 { 271 errors.add(ERR_CTRL_PANEL_NO_BACKUP_PATH_PROVIDED.get()); 272 setPrimaryInvalid(lPath); 273 } 274 275 String id = backupID.getText(); 276 if (id == null || id.trim().equals("")) 277 { 278 errors.add(ERR_CTRL_PANEL_NO_BACKUP_ID_PROVIDED.get()); 279 setPrimaryInvalid(lBackupID); 280 } 281 } 282 283 if (errors.isEmpty()) 284 { 285 ProgressDialog progressDialog = new ProgressDialog( 286 Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(), 287 getInfo()); 288 RestoreTask newTask = new RestoreTask(getInfo(), progressDialog, false); 289 for (Task task : getInfo().getTasks()) 290 { 291 task.canLaunch(newTask, errors); 292 } 293// Ask for confirmation 294 boolean confirmed = true; 295 if (errors.isEmpty()) 296 { 297 confirmed = displayConfirmationDialog( 298 INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(), 299 INFO_CTRL_PANEL_CONFIRM_RESTORE_DETAILS.get()); 300 } 301 302 if (errors.isEmpty() && confirmed) 303 { 304 launchOperation(newTask, 305 INFO_CTRL_PANEL_RESTORING_SUMMARY.get(backup.getID()), 306 INFO_CTRL_PANEL_RESTORING_SUCCESSFUL_SUMMARY.get(), 307 INFO_CTRL_PANEL_RESTORING_SUCCESSFUL_DETAILS.get(), 308 ERR_CTRL_PANEL_RESTORING_ERROR_SUMMARY.get(), 309 null, 310 ERR_CTRL_PANEL_RESTORING_ERROR_DETAILS, 311 progressDialog); 312 progressDialog.setVisible(true); 313 Utilities.getParentDialog(this).setVisible(false); 314 } 315 } 316 if (!errors.isEmpty()) 317 { 318 displayErrorDialog(errors); 319 } 320 } 321 322 /** {@inheritDoc} */ 323 public void cancelClicked() 324 { 325 setPrimaryValid(lPath); 326 setPrimaryValid(lAvailableBackups); 327 328 super.cancelClicked(); 329 } 330 331 /** The task in charge of restoring or verifying the backup. */ 332 protected class RestoreTask extends Task 333 { 334 private Set<String> backendSet; 335 private String dir; 336 private String backupID; 337 private boolean verify; 338 339 /** 340 * The constructor of the task. 341 * @param info the control panel info. 342 * @param dlg the progress dialog that shows the progress of the task. 343 * @param verify whether this is an actual restore or a verify of the 344 * backup. 345 */ 346 public RestoreTask(ControlPanelInfo info, ProgressDialog dlg, 347 boolean verify) 348 { 349 super(info, dlg); 350 this.verify = verify; 351 if (isLocal()) 352 { 353 BackupDescriptor backup = getSelectedBackup(); 354 dir = backup.getPath().getAbsolutePath(); 355 backupID = backup.getID(); 356 } 357 else 358 { 359 dir = parentDirectory.getText(); 360 backupID = RestorePanel.this.backupID.getText(); 361 } 362 backendSet = new HashSet<>(); 363 for (BackendDescriptor backend : info.getServerDescriptor().getBackends()) 364 { 365 if (!backend.isConfigBackend()) 366 { 367 backendSet.add(backend.getBackendID()); 368 } 369 } 370 } 371 372 /** {@inheritDoc} */ 373 public Type getType() 374 { 375 return Type.RESTORE; 376 } 377 378 /** {@inheritDoc} */ 379 public LocalizableMessage getTaskDescription() 380 { 381 if (verify) 382 { 383 return INFO_CTRL_PANEL_VERIFY_TASK_DESCRIPTION.get(backupID, dir); 384 } 385 else 386 { 387 return INFO_CTRL_PANEL_RESTORE_TASK_DESCRIPTION.get(backupID, dir); 388 } 389 } 390 391 /** {@inheritDoc} */ 392 public boolean canLaunch(Task taskToBeLaunched, 393 Collection<LocalizableMessage> incompatibilityReasons) 394 { 395 boolean canLaunch = true; 396 if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched)) 397 { 398 // All the operations are incompatible if they apply to this backend. 399 Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 400 backends.retainAll(getBackends()); 401 if (!backends.isEmpty()) 402 { 403 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 404 canLaunch = false; 405 } 406 } 407 return canLaunch; 408 } 409 410 /** {@inheritDoc} */ 411 public void runTask() 412 { 413 state = State.RUNNING; 414 lastException = null; 415 try 416 { 417 ArrayList<String> arguments = getCommandLineArguments(); 418 419 String[] args = new String[arguments.size()]; 420 421 arguments.toArray(args); 422 if (isServerRunning()) 423 { 424 returnCode = RestoreDB.mainRestoreDB(args, false, outPrintStream, 425 errorPrintStream); 426 } 427 else 428 { 429 returnCode = executeCommandLine(getCommandLinePath(), args); 430 } 431 if (returnCode != 0) 432 { 433 state = State.FINISHED_WITH_ERROR; 434 } 435 else 436 { 437 if (!verify) 438 { 439 for (String backend : getBackends()) 440 { 441 getInfo().unregisterModifiedIndexesInBackend(backend); 442 } 443 } 444 state = State.FINISHED_SUCCESSFULLY; 445 } 446 } 447 catch (Throwable t) 448 { 449 lastException = t; 450 state = State.FINISHED_WITH_ERROR; 451 } 452 HashSet<BackendDescriptor> backends = new HashSet<>(); 453 for (BackendDescriptor backend : 454 getInfo().getServerDescriptor().getBackends()) 455 { 456 for (String backendID : getBackends()) 457 { 458 if (backendID.equalsIgnoreCase(backend.getBackendID())) 459 { 460 backends.add(backend); 461 break; 462 } 463 } 464 } 465 if (!backends.isEmpty()) 466 { 467 getInfo().backendPopulated(backends); 468 } 469 } 470 471 /** {@inheritDoc} */ 472 public Set<String> getBackends() 473 { 474 return backendSet; 475 } 476 477 /** {@inheritDoc} */ 478 protected ArrayList<String> getCommandLineArguments() 479 { 480 ArrayList<String> args = new ArrayList<>(); 481 482 args.add("--backupDirectory"); 483 args.add(dir); 484 485 args.add("--backupID"); 486 args.add(backupID); 487 488 if (verify) 489 { 490 args.add("--dry-run"); 491 } 492 493 args.addAll(getConnectionCommandLineArguments()); 494 495 if (isServerRunning()) 496 { 497 args.addAll(getConfigCommandLineArguments()); 498 } 499 args.add(getNoPropertiesFileArgument()); 500 501 return args; 502 } 503 504 /** {@inheritDoc} */ 505 protected String getCommandLinePath() 506 { 507 return getCommandLinePath("restore"); 508 } 509 } 510}