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