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 2013-2015 ForgeRock AS. 026 */ 027 028package org.opends.guitools.controlpanel.ui; 029 030import static org.opends.messages.AdminToolMessages.*; 031 032import java.awt.Component; 033import java.awt.GridBagConstraints; 034import java.awt.datatransfer.Transferable; 035import java.awt.datatransfer.UnsupportedFlavorException; 036import java.awt.dnd.DnDConstants; 037import java.awt.dnd.DropTarget; 038import java.awt.dnd.DropTargetDragEvent; 039import java.awt.dnd.DropTargetDropEvent; 040import java.awt.dnd.DropTargetEvent; 041import java.awt.dnd.DropTargetListener; 042import java.awt.event.ActionEvent; 043import java.awt.event.ActionListener; 044import java.io.IOException; 045import java.util.ArrayList; 046import java.util.LinkedHashSet; 047import java.util.List; 048import java.util.Set; 049 050import javax.swing.JButton; 051import javax.swing.JLabel; 052import javax.swing.JScrollPane; 053import javax.swing.JTextArea; 054import javax.swing.SwingUtilities; 055 056import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 057import org.opends.guitools.controlpanel.task.AddToGroupTask; 058import org.opends.guitools.controlpanel.task.Task; 059import org.opends.guitools.controlpanel.ui.nodes.BrowserNodeInfo; 060import org.opends.guitools.controlpanel.ui.nodes.DndBrowserNodes; 061import org.opends.guitools.controlpanel.util.BackgroundTask; 062import org.opends.guitools.controlpanel.util.Utilities; 063import org.forgerock.i18n.LocalizableMessage; 064import org.opends.server.types.DN; 065import org.opends.server.types.OpenDsException; 066import org.opends.server.util.ServerConstants; 067 068/** 069 * The dialog that is displayed when we want to add entries to a set of groups. 070 * @author jvergara 071 * 072 */ 073public class AddToGroupPanel extends StatusGenericPanel 074{ 075 private static final long serialVersionUID = 1837745944604435848L; 076 private JTextArea groups; 077 private JTextArea entries; 078 private JScrollPane scrollEntries; 079 private JLabel lEntries = Utilities.createDefaultLabel(); 080 private JLabel lGroups = Utilities.createDefaultLabel(); 081 private LinkedHashSet<DN> dns = new LinkedHashSet<>(); 082 083 private GenericDialog browseGroupDlg; 084 private LDAPEntrySelectionPanel browseGroupPanel; 085 086 /** 087 * Default constructor. 088 * 089 */ 090 public AddToGroupPanel() 091 { 092 super(); 093 createLayout(); 094 } 095 096 /** 097 * Sets the entries we want to add to groups. 098 * @param dns the DN of the entries we want to add to groups. 099 */ 100 public void setEntriesToAdd(Set<DN> dns) 101 { 102 ArrayList<String> sDns = new ArrayList<>(); 103 for (DN dn : dns) 104 { 105 sDns.add(dn.toString()); 106 } 107 if (dns.size() > 5) 108 { 109 entries.setText(Utilities.getStringFromCollection(sDns, "\n")); 110 scrollEntries.setVisible(true); 111 lEntries.setVisible(false); 112 } 113 else 114 { 115 lEntries.setText("<html>"+Utilities.applyFont( 116 "<li>"+Utilities.getStringFromCollection(sDns, "<li>"), 117 ColorAndFontConstants.defaultFont)); 118 scrollEntries.setVisible(false); 119 lEntries.setVisible(true); 120 } 121 this.dns.clear(); 122 this.dns.addAll(dns); 123 packParentDialog(); 124 } 125 126 /** {@inheritDoc} */ 127 public Component getPreferredFocusComponent() 128 { 129 return groups; 130 } 131 132 /** {@inheritDoc} */ 133 public void okClicked() 134 { 135 final ArrayList<LocalizableMessage> errors = new ArrayList<>(); 136 BackgroundTask<Void> worker = new BackgroundTask<Void>() 137 { 138 /** {@inheritDoc} */ 139 public Void processBackgroundTask() 140 { 141 try 142 { 143 Thread.sleep(2000); 144 } 145 catch (Throwable t) 146 { 147 } 148 updateErrors(errors); 149 return null; 150 } 151 /** {@inheritDoc} */ 152 public void backgroundTaskCompleted(Void returnValue, Throwable t) 153 { 154 if (t != null) 155 { 156 errors.add(ERR_CTRL_PANEL_UNEXPECTED_DETAILS.get(t)); 157 } 158 displayMainPanel(); 159 setEnabledCancel(true); 160 setEnabledOK(true); 161 handleErrorsAndLaunchTask(errors); 162 } 163 }; 164 displayMessage(INFO_CTRL_PANEL_CHECKING_SUMMARY.get()); 165 setEnabledCancel(false); 166 setEnabledOK(false); 167 worker.startBackgroundTask(); 168 } 169 170 /** {@inheritDoc} */ 171 public LocalizableMessage getTitle() 172 { 173 return INFO_CTRL_PANEL_ADD_TO_GROUP_TITLE.get(); 174 } 175 176 /** {@inheritDoc} */ 177 public void configurationChanged(ConfigurationChangeEvent ev) 178 { 179 } 180 181 /** 182 * Creates the layout of the panel (but the contents are not populated here). 183 */ 184 private void createLayout() 185 { 186 GridBagConstraints gbc = new GridBagConstraints(); 187 gbc.gridx = 0; 188 gbc.gridy = 0; 189 gbc.weightx = 0.0; 190 gbc.weighty = 0.0; 191 gbc.gridwidth = 2; 192 gbc.fill = GridBagConstraints.HORIZONTAL; 193 JLabel l = Utilities.createDefaultLabel( 194 INFO_CTRL_PANEL_ADD_TO_GROUP_ENTRIES_LABEL.get()); 195 add(l, gbc); 196 gbc.insets.top = 5; 197 entries = Utilities.createNonEditableTextArea(LocalizableMessage.EMPTY, 6, 40); 198 scrollEntries = Utilities.createScrollPane(entries); 199 gbc.weighty = 0.1; 200 gbc.fill = GridBagConstraints.BOTH; 201 gbc.gridy ++; 202 add(scrollEntries, gbc); 203 gbc.weighty = 0.0; 204 gbc.fill = GridBagConstraints.HORIZONTAL; 205 gbc.insets.top = 0; 206 add(lEntries, gbc); 207 208 gbc.insets.top = 10; 209 gbc.gridy ++ ; 210 lGroups.setText(INFO_CTRL_PANEL_ADD_TO_GROUP_GROUPS_LABEL.get().toString()); 211 add(lGroups, gbc); 212 gbc.insets.top = 5; 213 gbc.gridwidth = 1; 214 groups = Utilities.createTextArea(LocalizableMessage.EMPTY, 8, 40); 215 JScrollPane scrollGroups = Utilities.createScrollPane(groups); 216 gbc.weightx = 1.0; 217 gbc.weighty = 1.0; 218 gbc.fill = GridBagConstraints.BOTH; 219 gbc.gridy ++; 220 add(scrollGroups, gbc); 221 gbc.gridx ++; 222 gbc.insets.left = 5; 223 gbc.weightx = 0.0; 224 gbc.fill = GridBagConstraints.HORIZONTAL; 225 JButton browse = Utilities.createButton( 226 INFO_CTRL_PANEL_ADD_GROUPS_BUTTON_LABEL.get()); 227 gbc.anchor = GridBagConstraints.NORTH; 228 add(browse, gbc); 229 browse.addActionListener(new ActionListener() 230 { 231 /** {@inheritDoc} */ 232 public void actionPerformed(ActionEvent ev) 233 { 234 browseGroupsClicked(); 235 } 236 }); 237 238 DropTargetListener dropTargetlistener = new DropTargetListener() 239 { 240 /** {@inheritDoc} */ 241 public void dragEnter(DropTargetDragEvent e) 242 { 243 } 244 245 /** {@inheritDoc} */ 246 public void dragExit(DropTargetEvent e) 247 { 248 } 249 250 /** {@inheritDoc} */ 251 public void dragOver(DropTargetDragEvent e) 252 { 253 } 254 255 /** {@inheritDoc} */ 256 public void dropActionChanged(DropTargetDragEvent e) 257 { 258 } 259 260 /** {@inheritDoc} */ 261 public void drop(DropTargetDropEvent e) 262 { 263 try { 264 Transferable tr = e.getTransferable(); 265 266 //flavor not supported, reject drop 267 if (!tr.isDataFlavorSupported(DndBrowserNodes.INFO_FLAVOR)) 268 { 269 e.rejectDrop(); 270 } 271 272 //cast into appropriate data type 273 DndBrowserNodes nodes = 274 (DndBrowserNodes) tr.getTransferData(DndBrowserNodes.INFO_FLAVOR); 275 276 StringBuilder sb = new StringBuilder(); 277 sb.append(groups.getText()); 278 for (BrowserNodeInfo node : nodes.getNodes()) 279 { 280 if (sb.length() > 0) 281 { 282 sb.append("\n"); 283 } 284 sb.append(node.getNode().getDN()); 285 } 286 groups.setText(sb.toString()); 287 groups.setCaretPosition(sb.length()); 288 289 e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); 290 e.getDropTargetContext().dropComplete(true); 291 } 292 catch (IOException | UnsupportedFlavorException io) 293 { 294 e.rejectDrop(); 295 } 296 } 297 }; 298 new DropTarget(groups, dropTargetlistener); 299 } 300 301 private void browseGroupsClicked() 302 { 303 if (browseGroupDlg == null) 304 { 305 browseGroupPanel = new LDAPEntrySelectionPanel(); 306 browseGroupPanel.setTitle(INFO_CTRL_PANEL_CHOOSE_GROUP_TITLE.get()); 307 browseGroupPanel.setFilter( 308 LDAPEntrySelectionPanel.Filter.STATIC_GROUPS); 309 browseGroupPanel.setMultipleSelection(true); 310 browseGroupPanel.setInfo(getInfo()); 311 browseGroupDlg = new GenericDialog(Utilities.getFrame(this), 312 browseGroupPanel); 313 Utilities.centerGoldenMean(browseGroupDlg, 314 Utilities.getParentDialog(this)); 315 browseGroupDlg.setModal(true); 316 } 317 browseGroupDlg.setVisible(true); 318 String[] dns = browseGroupPanel.getDNs(); 319 if (dns.length > 0) 320 { 321 StringBuilder sb = new StringBuilder(); 322 sb.append(groups.getText()); 323 for (String dn : dns) 324 { 325 if (sb.length() > 0) 326 { 327 sb.append("\n"); 328 } 329 sb.append(dn); 330 } 331 groups.setText(sb.toString()); 332 groups.setCaretPosition(sb.length()); 333 } 334 } 335 336 private void updateErrors(List<LocalizableMessage> errors) 337 { 338 SwingUtilities.invokeLater(new Runnable() 339 { 340 /** {@inheritDoc} */ 341 public void run() 342 { 343 setPrimaryValid(lGroups); 344 } 345 }); 346 347 String[] grs = groups.getText().split("\n"); 348 boolean oneGroupDefined = false; 349 for (String groupDn : grs) 350 { 351 groupDn = groupDn.trim(); 352 if (groupDn.length() > 0) 353 { 354 try 355 { 356 DN.valueOf(groupDn); 357 if (!entryExists(groupDn)) 358 { 359 errors.add( 360 ERR_CTRL_PANEL_GROUP_COULD_NOT_BE_FOUND.get(groupDn)); 361 } 362 else if (!hasObjectClass(groupDn, ServerConstants.OC_GROUP_OF_NAMES, 363 ServerConstants.OC_GROUP_OF_ENTRIES, 364 ServerConstants.OC_GROUP_OF_UNIQUE_NAMES)) 365 { 366 errors.add(ERR_CTRL_PANEL_NOT_A_STATIC_GROUP.get(groupDn)); 367 } 368 else 369 { 370 oneGroupDefined = true; 371 } 372 } 373 catch (OpenDsException ode) 374 { 375 errors.add(INFO_CTRL_PANEL_INVALID_DN_DETAILS.get(groupDn, 376 ode.getMessageObject())); 377 } 378 } 379 } 380 if (!oneGroupDefined && errors.isEmpty()) 381 { 382 errors.add(ERR_CTRL_PANEL_GROUP_NOT_PROVIDED.get()); 383 } 384 385 if (!errors.isEmpty()) 386 { 387 SwingUtilities.invokeLater(new Runnable() 388 { 389 /** {@inheritDoc} */ 390 public void run() 391 { 392 setPrimaryInvalid(lGroups); 393 } 394 }); 395 } 396 } 397 398 private void handleErrorsAndLaunchTask(ArrayList<LocalizableMessage> errors) 399 { 400 if (errors.isEmpty()) 401 { 402 ProgressDialog dlg = new ProgressDialog( 403 Utilities.createFrame(), 404 Utilities.getParentDialog(this), 405 INFO_CTRL_PANEL_ADD_TO_GROUP_TITLE.get(), getInfo()); 406 LinkedHashSet<DN> groupDns = new LinkedHashSet<>(); 407 String[] grs = groups.getText().split("\n"); 408 try 409 { 410 for (String groupDn : grs) 411 { 412 groupDn = groupDn.trim(); 413 if (groupDn.length() > 0) 414 { 415 groupDns.add(DN.valueOf(groupDn)); 416 } 417 } 418 } 419 catch (OpenDsException ode) 420 { 421 throw new RuntimeException( 422 "Unexpected error decoding dn. Details: "+ode.getMessageObject(), 423 ode); 424 } 425 try 426 { 427 AddToGroupTask newTask = 428 new AddToGroupTask(getInfo(), dlg, dns, groupDns); 429 for (Task task : getInfo().getTasks()) 430 { 431 task.canLaunch(newTask, errors); 432 } 433 if (errors.isEmpty()) 434 { 435 launchOperation(newTask, 436 INFO_CTRL_PANEL_ADDING_TO_GROUP_SUMMARY.get(), 437 INFO_CTRL_PANEL_ADDING_TO_GROUP_SUCCESSFUL_SUMMARY.get(), 438 INFO_CTRL_PANEL_ADDING_TO_GROUP_SUCCESSFUL_DETAILS.get(), 439 ERR_CTRL_PANEL_ADDING_TO_GROUP_ERROR_SUMMARY.get(), 440 ERR_CTRL_PANEL_ADDING_TO_GROUP_ERROR_DETAILS.get(), 441 null, 442 dlg); 443 dlg.setVisible(true); 444 Utilities.getParentDialog(this).setVisible(false); 445 } 446 } 447 catch (Throwable t) 448 { 449 // Unexpected error: getEntry() should work after calling checkSyntax 450 throw new RuntimeException("Unexpected error: "+t, t); 451 } 452 } 453 if (!errors.isEmpty()) 454 { 455 displayErrorDialog(errors); 456 } 457 } 458}