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-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.guitools.controlpanel.util; 028 029import static org.opends.admin.ads.util.ConnectionUtils.*; 030import static org.opends.messages.AdminToolMessages.*; 031import static org.opends.quicksetup.Installation.*; 032import static org.opends.server.types.CommonSchemaElements.*; 033 034import static com.forgerock.opendj.cli.Utils.*; 035import static com.forgerock.opendj.util.OperatingSystem.*; 036 037import java.awt.Color; 038import java.awt.Component; 039import java.awt.Container; 040import java.awt.Dimension; 041import java.awt.Font; 042import java.awt.Image; 043import java.awt.Point; 044import java.awt.Toolkit; 045import java.awt.Window; 046import java.awt.event.MouseAdapter; 047import java.awt.event.MouseEvent; 048import java.io.File; 049import java.io.IOException; 050import java.io.UnsupportedEncodingException; 051import java.text.CharacterIterator; 052import java.text.StringCharacterIterator; 053import java.util.ArrayList; 054import java.util.Collection; 055import java.util.Comparator; 056import java.util.Date; 057import java.util.List; 058import java.util.regex.Pattern; 059 060import javax.naming.CompositeName; 061import javax.naming.InvalidNameException; 062import javax.naming.Name; 063import javax.naming.NamingEnumeration; 064import javax.naming.NamingException; 065import javax.naming.directory.SearchControls; 066import javax.naming.directory.SearchResult; 067import javax.naming.ldap.InitialLdapContext; 068import javax.naming.ldap.LdapName; 069import javax.swing.BorderFactory; 070import javax.swing.DefaultComboBoxModel; 071import javax.swing.ImageIcon; 072import javax.swing.JButton; 073import javax.swing.JCheckBox; 074import javax.swing.JComboBox; 075import javax.swing.JComponent; 076import javax.swing.JDialog; 077import javax.swing.JEditorPane; 078import javax.swing.JFrame; 079import javax.swing.JLabel; 080import javax.swing.JMenu; 081import javax.swing.JMenuItem; 082import javax.swing.JOptionPane; 083import javax.swing.JPasswordField; 084import javax.swing.JRadioButton; 085import javax.swing.JScrollPane; 086import javax.swing.JTable; 087import javax.swing.JTextArea; 088import javax.swing.JTextField; 089import javax.swing.SwingConstants; 090import javax.swing.SwingUtilities; 091import javax.swing.border.Border; 092import javax.swing.border.EmptyBorder; 093import javax.swing.border.EtchedBorder; 094import javax.swing.border.TitledBorder; 095import javax.swing.table.JTableHeader; 096import javax.swing.table.TableCellRenderer; 097import javax.swing.table.TableColumn; 098import javax.swing.table.TableColumnModel; 099 100import org.forgerock.i18n.LocalizableMessage; 101import org.forgerock.i18n.slf4j.LocalizedLogger; 102import org.forgerock.opendj.config.ConfigurationFramework; 103import org.forgerock.opendj.config.server.ConfigException; 104import org.forgerock.opendj.ldap.ByteString; 105import org.forgerock.opendj.ldap.schema.MatchingRule; 106import org.forgerock.opendj.ldap.schema.Syntax; 107import org.opends.guitools.controlpanel.ControlPanel; 108import org.opends.guitools.controlpanel.browser.IconPool; 109import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement; 110import org.opends.guitools.controlpanel.datamodel.ConfigReadException; 111import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 112import org.opends.guitools.controlpanel.datamodel.CustomSearchResult; 113import org.opends.guitools.controlpanel.datamodel.MonitoringAttributes; 114import org.opends.guitools.controlpanel.datamodel.SortableTableModel; 115import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor; 116import org.opends.guitools.controlpanel.event.ClickTooltipDisplayer; 117import org.opends.guitools.controlpanel.event.ComboKeySelectionManager; 118import org.opends.guitools.controlpanel.event.TextComponentFocusListener; 119import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 120import org.opends.guitools.controlpanel.ui.components.LabelWithHelpIcon; 121import org.opends.guitools.controlpanel.ui.components.SelectableLabelWithHelpIcon; 122import org.opends.guitools.controlpanel.ui.renderer.AccessibleTableHeaderRenderer; 123import org.opends.quicksetup.Installation; 124import org.opends.quicksetup.ui.UIFactory; 125import org.opends.quicksetup.util.Utils; 126import org.opends.server.admin.ClassLoaderProvider; 127import org.opends.server.api.ConfigHandler; 128import org.opends.server.config.ConfigEntry; 129import org.opends.server.core.DirectoryServer; 130import org.opends.server.core.LockFileManager; 131import org.opends.server.schema.SchemaConstants; 132import org.opends.server.types.AttributeType; 133import org.opends.server.types.CommonSchemaElements; 134import org.opends.server.types.DN; 135import org.opends.server.types.OpenDsException; 136import org.opends.server.types.RDN; 137import org.opends.server.types.Schema; 138import org.opends.server.types.SchemaFileElement; 139import org.opends.server.util.ServerConstants; 140import org.opends.server.util.StaticUtils; 141 142/** 143 * A static class that provides miscellaneous functions. 144 */ 145public class Utilities 146{ 147 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 148 149 private static File rootDirectory; 150 private static File instanceRootDirectory; 151 152 private static final String HTML_SPACE = " "; 153 private static final String[] attrsToObfuscate = { ServerConstants.ATTR_USER_PASSWORD }; 154 private static final String[] passwordSyntaxOIDs = { SchemaConstants.SYNTAX_USER_PASSWORD_OID }; 155 private static final String[] binarySyntaxOIDs = { 156 SchemaConstants.SYNTAX_BINARY_OID, 157 SchemaConstants.SYNTAX_JPEG_OID, 158 SchemaConstants.SYNTAX_CERTIFICATE_OID, 159 SchemaConstants.SYNTAX_OCTET_STRING_OID 160 }; 161 162 private static ImageIcon warningIcon; 163 private static ImageIcon requiredIcon; 164 165 private final static LocalizableMessage NO_VALUE_SET = INFO_CTRL_PANEL_NO_MONITORING_VALUE.get(); 166 private final static LocalizableMessage NOT_IMPLEMENTED = INFO_CTRL_PANEL_NOT_IMPLEMENTED.get(); 167 168 /** 169 * Creates a combo box. 170 * 171 * @param <T> 172 * The combo box data type. 173 * @return a combo box. 174 */ 175 public static <T> JComboBox<T> createComboBox() 176 { 177 JComboBox<T> combo = new JComboBox<>(); 178 if (isMacOS()) 179 { 180 combo.setOpaque(false); 181 } 182 combo.setKeySelectionManager(new ComboKeySelectionManager(combo)); 183 return combo; 184 } 185 186 /** 187 * Creates a frame. 188 * @return a frame. 189 */ 190 public static JFrame createFrame() 191 { 192 JFrame frame = new JFrame(); 193 frame.setResizable(true); 194 org.opends.quicksetup.ui.Utilities.setFrameIcon(frame); 195 return frame; 196 } 197 198 /** 199 * Returns <CODE>true</CODE> if an attribute value must be obfuscated because 200 * it contains sensitive information (like passwords) and <CODE>false</CODE> 201 * otherwise. 202 * @param attrName the attribute name. 203 * @param schema the schema of the server. 204 * @return <CODE>true</CODE> if an attribute value must be obfuscated because 205 * it contains sensitive information (like passwords) and <CODE>false</CODE> 206 * otherwise. 207 */ 208 public static boolean mustObfuscate(String attrName, Schema schema) 209 { 210 if (schema != null) 211 { 212 return hasPasswordSyntax(attrName, schema); 213 } 214 for (String attr : attrsToObfuscate) 215 { 216 if (attr.equalsIgnoreCase(attrName)) 217 { 218 return true; 219 } 220 } 221 return false; 222 } 223 224 /** 225 * Derives a color by adding the specified offsets to the base color's 226 * hue, saturation, and brightness values. The resulting hue, saturation, 227 * and brightness values will be constrained to be between 0 and 1. 228 * @param base the color to which the HSV offsets will be added 229 * @param dH the offset for hue 230 * @param dS the offset for saturation 231 * @param dB the offset for brightness 232 * @return Color with modified HSV values 233 */ 234 public static Color deriveColorHSB(Color base, float dH, float dS, float dB) 235 { 236 float hsb[] = Color.RGBtoHSB( 237 base.getRed(), base.getGreen(), base.getBlue(), null); 238 239 hsb[0] += dH; 240 hsb[1] += dS; 241 hsb[2] += dB; 242 return Color.getHSBColor( 243 hsb[0] < 0? 0 : (hsb[0] > 1? 1 : hsb[0]), 244 hsb[1] < 0? 0 : (hsb[1] > 1? 1 : hsb[1]), 245 hsb[2] < 0? 0 : (hsb[2] > 1? 1 : hsb[2])); 246 247 } 248 249 /** 250 * Displays an error dialog that contains a set of error messages. 251 * @param parentComponent the parent component relative to which the dialog 252 * will be displayed. 253 * @param errors the set of error messages that the dialog must display. 254 */ 255 public static void displayErrorDialog(Component parentComponent, 256 Collection<LocalizableMessage> errors) 257 { 258 /* 259 ErrorPanel panel = new ErrorPanel("Error", errors); 260 GenericDialog dlg = new GenericDialog(null, panel); 261 dlg.setModal(true); 262 Utilities.centerGoldenMean(dlg, Utilities.getParentDialog(this)); 263 dlg.setVisible(true); 264 */ 265 ArrayList<String> stringErrors = new ArrayList<>(); 266 for (LocalizableMessage err : errors) 267 { 268 stringErrors.add(err.toString()); 269 } 270 String msg = getStringFromCollection(stringErrors, "<br>"); 271 String plainText = msg.replaceAll("<br>", ServerConstants.EOL); 272 String wrappedText = wrapText(plainText, 70); 273 wrappedText = wrappedText.replaceAll(ServerConstants.EOL, "<br>"); 274 JOptionPane.showMessageDialog( 275 parentComponent, "<html>"+wrappedText, 276 INFO_CTRL_PANEL_ERROR_DIALOG_TITLE.get().toString(), 277 JOptionPane.ERROR_MESSAGE); 278 } 279 280 /** 281 * Displays a confirmation dialog. Returns <CODE>true</CODE> if the user 282 * accepts the message and <CODE>false</CODE> otherwise. 283 * @param parentComponent the parent component relative to which the dialog 284 * will be displayed. 285 * @param title the title of the dialog. 286 * @param msg the message to be displayed. 287 * @return <CODE>true</CODE> if the user accepts the message and 288 * <CODE>false</CODE> otherwise. 289 * 290 */ 291 public static boolean displayConfirmationDialog(Component parentComponent, 292 LocalizableMessage title, LocalizableMessage msg) 293 { 294 String plainText = msg.toString().replaceAll("<br>", ServerConstants.EOL); 295 String wrappedText = wrapText(plainText, 70); 296 wrappedText = wrappedText.replaceAll(ServerConstants.EOL, "<br>"); 297 return JOptionPane.YES_OPTION == JOptionPane.showOptionDialog( 298 parentComponent, "<html>"+wrappedText, 299 title.toString(), 300 JOptionPane.YES_NO_OPTION, 301 JOptionPane.QUESTION_MESSAGE, 302 null, // don't use a custom Icon 303 null, // the titles of buttons 304 null); // default button title 305 } 306 307 /** 308 * Displays a warning dialog. 309 * @param parentComponent the parent component relative to which the dialog 310 * will be displayed. 311 * @param title the title of the dialog. 312 * @param msg the message to be displayed. 313 */ 314 public static void displayWarningDialog(Component parentComponent, 315 LocalizableMessage title, LocalizableMessage msg) 316 { 317 String plainText = msg.toString().replaceAll("<br>", ServerConstants.EOL); 318 String wrappedText = wrapText(plainText, 70); 319 wrappedText = wrappedText.replaceAll(ServerConstants.EOL, "<br>"); 320 JOptionPane.showMessageDialog( 321 parentComponent, "<html>"+wrappedText, 322 title.toString(), 323 JOptionPane.WARNING_MESSAGE); 324 } 325 326 327 /** 328 * Creates a JEditorPane that displays a message. 329 * @param text the message of the editor pane in HTML format. 330 * @param font the font to be used in the message. 331 * @return a JEditorPane that displays a message. 332 */ 333 public static JEditorPane makeHtmlPane(CharSequence text, Font font) 334 { 335 JEditorPane pane = new JEditorPane(); 336 pane.setContentType("text/html"); 337 pane.setFont(font); 338 if (text != null) 339 { 340 pane.setText(applyFont(text, font)); 341 } 342 pane.setEditable(false); 343 pane.setBorder(new EmptyBorder(0, 0, 0, 0)); 344 pane.setOpaque(false); 345 pane.setFocusCycleRoot(false); 346 return pane; 347 } 348 349 /** 350 * Creates a JEditorPane that displays a message. 351 * @param text the message of the editor pane in plain text format. 352 * @param font the font to be used in the message. 353 * @return a JEditorPane that displays a message. 354 */ 355 public static JEditorPane makePlainTextPane(String text, Font font) 356 { 357 JEditorPane pane = new JEditorPane(); 358 pane.setContentType("text/plain"); 359 if (text != null) 360 { 361 pane.setText(text); 362 } 363 pane.setFont(font); 364 pane.setEditable(false); 365 pane.setBorder(new EmptyBorder(0, 0, 0, 0)); 366 pane.setOpaque(false); 367 pane.setFocusCycleRoot(false); 368 return pane; 369 } 370 371 /** 372 * Returns the HTML style representation for the given font. 373 * @param font the font for which we want to get an HTML style representation. 374 * @return the HTML style representation for the given font. 375 */ 376 private static String getFontStyle(Font font) 377 { 378 StringBuilder buf = new StringBuilder(); 379 380 buf.append("font-family:").append(font.getName()) 381 .append(";font-size:").append(font.getSize()).append("pt"); 382 383 if (font.isItalic()) 384 { 385 buf.append(";font-style:italic"); 386 } 387 388 if (font.isBold()) 389 { 390 buf.append(";font-weight:bold;"); 391 } 392 393 return buf.toString(); 394 } 395 396 /** 397 * Creates a titled border. 398 * @param msg the message to be displayed in the titled border. 399 * @return the created titled border. 400 */ 401 public static Border makeTitledBorder(LocalizableMessage msg) 402 { 403 TitledBorder border = new TitledBorder(new EtchedBorder(), 404 " "+msg+" "); 405 border.setTitleFont(ColorAndFontConstants.titleFont); 406 border.setTitleColor(ColorAndFontConstants.foreground); 407 return border; 408 } 409 410 /** 411 * Returns a JScrollPane that contains the provided component. The scroll 412 * pane will not contain any border. 413 * @param comp the component contained in the scroll pane. 414 * @return a JScrollPane that contains the provided component. The scroll 415 * pane will not contain any border. 416 */ 417 public static JScrollPane createBorderLessScrollBar(Component comp) 418 { 419 JScrollPane scroll = new JScrollPane(comp); 420 scroll.setBorder(new EmptyBorder(0, 0, 0, 0)); 421 scroll.setViewportBorder(new EmptyBorder(0, 0, 0, 0)); 422 scroll.setOpaque(false); 423 scroll.getViewport().setOpaque(false); 424 scroll.getViewport().setBackground(ColorAndFontConstants.background); 425 scroll.setBackground(ColorAndFontConstants.background); 426 UIFactory.setScrollIncrementUnit(scroll); 427 return scroll; 428 } 429 430 /** 431 * Returns a JScrollPane that contains the provided component. 432 * @param comp the component contained in the scroll pane. 433 * @return a JScrollPane that contains the provided component. 434 */ 435 public static JScrollPane createScrollPane(Component comp) 436 { 437 JScrollPane scroll = new JScrollPane(comp); 438 scroll.getViewport().setOpaque(false); 439 scroll.setOpaque(false); 440 scroll.getViewport().setBackground(ColorAndFontConstants.background); 441 scroll.setBackground(ColorAndFontConstants.background); 442 UIFactory.setScrollIncrementUnit(scroll); 443 return scroll; 444 } 445 446 /** 447 * Creates a button. 448 * @param text the message to be displayed by the button. 449 * @return the created button. 450 */ 451 public static JButton createButton(LocalizableMessage text) 452 { 453 JButton button = new JButton(text.toString()); 454 button.setOpaque(false); 455 button.setForeground(ColorAndFontConstants.buttonForeground); 456 button.getAccessibleContext().setAccessibleName(text.toString()); 457 return button; 458 } 459 460 /** 461 * Creates a radio button. 462 * @param text the message to be displayed by the radio button. 463 * @return the created radio button. 464 */ 465 public static JRadioButton createRadioButton(LocalizableMessage text) 466 { 467 JRadioButton button = new JRadioButton(text.toString()); 468 button.setOpaque(false); 469 button.setForeground(ColorAndFontConstants.buttonForeground); 470 button.getAccessibleContext().setAccessibleName(text.toString()); 471 return button; 472 } 473 474 /** 475 * Creates a check box. 476 * @param text the message to be displayed by the check box. 477 * @return the created check box. 478 */ 479 public static JCheckBox createCheckBox(LocalizableMessage text) 480 { 481 JCheckBox cb = new JCheckBox(text.toString()); 482 cb.setOpaque(false); 483 cb.setForeground(ColorAndFontConstants.buttonForeground); 484 cb.getAccessibleContext().setAccessibleName(text.toString()); 485 return cb; 486 } 487 488 /** 489 * Creates a menu item with the provided text. 490 * @param msg the text. 491 * @return a menu item with the provided text. 492 */ 493 public static JMenuItem createMenuItem(LocalizableMessage msg) 494 { 495 return new JMenuItem(msg.toString()); 496 } 497 498 /** 499 * Creates a menu with the provided text. 500 * @param msg the text. 501 * @param description the accessible description. 502 * @return a menu with the provided text. 503 */ 504 public static JMenu createMenu(LocalizableMessage msg, LocalizableMessage description) 505 { 506 JMenu menu = new JMenu(msg.toString()); 507 menu.getAccessibleContext().setAccessibleDescription( 508 description.toString()); 509 return menu; 510 } 511 512 /** 513 * Creates a label of type 'primary' (with bigger font than usual) with no 514 * text. 515 * @return the label of type 'primary' (with bigger font than usual) with no 516 * text. 517 */ 518 public static JLabel createPrimaryLabel() 519 { 520 return createPrimaryLabel(LocalizableMessage.EMPTY); 521 } 522 523 /** 524 * Creates a label of type 'primary' (with bigger font than usual). 525 * @param text the message to be displayed by the label. 526 * @return the label of type 'primary' (with bigger font than usual). 527 */ 528 public static JLabel createPrimaryLabel(LocalizableMessage text) 529 { 530 JLabel label = new JLabel(text.toString()); 531 label.setFont(ColorAndFontConstants.primaryFont); 532 label.setForeground(ColorAndFontConstants.foreground); 533 return label; 534 } 535 536 /** 537 * Creates a label of type 'inline help' (with smaller font). 538 * @param text the message to be displayed by the label. 539 * @return the label of type 'inline help' (with smaller font). 540 */ 541 public static JLabel createInlineHelpLabel(LocalizableMessage text) 542 { 543 JLabel label = new JLabel(text.toString()); 544 label.setFont(ColorAndFontConstants.inlineHelpFont); 545 label.setForeground(ColorAndFontConstants.foreground); 546 return label; 547 } 548 549 /** 550 * Creates a label of type 'title' (with bigger font). 551 * @param text the message to be displayed by the label. 552 * @return the label of type 'title' (with bigger font). 553 */ 554 public static JLabel createTitleLabel(LocalizableMessage text) 555 { 556 JLabel label = new JLabel(text.toString()); 557 label.setFont(ColorAndFontConstants.titleFont); 558 label.setForeground(ColorAndFontConstants.foreground); 559 return label; 560 } 561 562 /** 563 * Creates a label (with default font) with no text. 564 * @return the label (with default font) with no text. 565 */ 566 public static JLabel createDefaultLabel() 567 { 568 return createDefaultLabel(LocalizableMessage.EMPTY); 569 } 570 571 /** 572 * Creates a label (with default font). 573 * @param text the message to be displayed by the label. 574 * @return the label (with default font). 575 */ 576 public static JLabel createDefaultLabel(LocalizableMessage text) 577 { 578 JLabel label = new JLabel(text.toString()); 579 label.setFont(ColorAndFontConstants.defaultFont); 580 label.setForeground(ColorAndFontConstants.foreground); 581 return label; 582 } 583 584 /** 585 * Returns a table created with the provided model and renderers. 586 * @param tableModel the table model. 587 * @param renderer the cell renderer. 588 * @return a table created with the provided model and renderers. 589 */ 590 public static JTable createSortableTable(final SortableTableModel tableModel, 591 TableCellRenderer renderer) 592 { 593 final JTable table = new JTable(tableModel); 594 table.setShowGrid(true); 595 table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); 596 table.setGridColor(ColorAndFontConstants.gridColor); 597 if (isMacOS()) 598 { 599 table.getTableHeader().setBorder( 600 BorderFactory.createMatteBorder(1, 1, 0, 0, 601 ColorAndFontConstants.gridColor)); 602 } 603 if (isWindows()) 604 { 605 table.getTableHeader().setBorder( 606 BorderFactory.createMatteBorder(1, 1, 0, 1, 607 ColorAndFontConstants.gridColor)); 608 } 609 table.getTableHeader().setDefaultRenderer( 610 new AccessibleTableHeaderRenderer( 611 table.getTableHeader().getDefaultRenderer())); 612 613 for (int i=0; i<tableModel.getColumnCount(); i++) 614 { 615 TableColumn col = table.getColumn(table.getColumnName(i)); 616 col.setCellRenderer(renderer); 617 } 618 MouseAdapter listMouseListener = new MouseAdapter() { 619 @Override 620 public void mouseClicked(MouseEvent e) { 621 TableColumnModel columnModel = table.getColumnModel(); 622 int viewColumn = columnModel.getColumnIndexAtX(e.getX()); 623 int sortedBy = table.convertColumnIndexToModel(viewColumn); 624 if (e.getClickCount() == 1 && sortedBy != -1) { 625 tableModel.setSortAscending(!tableModel.isSortAscending()); 626 tableModel.setSortColumn(sortedBy); 627 tableModel.forceResort(); 628 updateTableSizes(table); 629 } 630 } 631 }; 632 table.getTableHeader().addMouseListener(listMouseListener); 633 return table; 634 } 635 636 /** 637 * Creates a text area with borders similar to the ones of a text field. 638 * @param text the text of the text area. 639 * @param rows the rows of the text area. 640 * @param cols the columns of the text area. 641 * @return a text area with borders similar to the ones of a text field. 642 */ 643 public static JTextArea createTextAreaWithBorder(LocalizableMessage text, int rows, 644 int cols) 645 { 646 JTextArea ta = createTextArea(text, rows, cols); 647 if (ColorAndFontConstants.textAreaBorder != null) 648 { 649 setBorder(ta, ColorAndFontConstants.textAreaBorder); 650 } 651 return ta; 652 } 653 654 /** 655 * Creates a non-editable text area. 656 * @param text the text of the text area. 657 * @param rows the rows of the text area. 658 * @param cols the columns of the text area. 659 * @return a non-editable text area. 660 */ 661 public static JTextArea createNonEditableTextArea(LocalizableMessage text, int rows, 662 int cols) 663 { 664 JTextArea ta = createTextArea(text, rows, cols); 665 ta.setEditable(false); 666 ta.setOpaque(false); 667 ta.setForeground(ColorAndFontConstants.foreground); 668 return ta; 669 } 670 671 /** 672 * Creates a text area. 673 * @param text the text of the text area. 674 * @param rows the rows of the text area. 675 * @param cols the columns of the text area. 676 * @return a text area. 677 */ 678 public static JTextArea createTextArea(LocalizableMessage text, int rows, 679 int cols) 680 { 681 JTextArea ta = new JTextArea(text.toString(), rows, cols); 682 ta.setFont(ColorAndFontConstants.defaultFont); 683 return ta; 684 } 685 686 /** 687 * Creates a text field. 688 * @param text the text of the text field. 689 * @param cols the columns of the text field. 690 * @return the created text field. 691 */ 692 public static JTextField createTextField(String text, int cols) 693 { 694 JTextField tf = createTextField(); 695 tf.setText(text); 696 tf.setColumns(cols); 697 return tf; 698 } 699 700 /** 701 * Creates a short text field. 702 * @return the created text field. 703 */ 704 public static JTextField createShortTextField() 705 { 706 JTextField tf = createTextField(); 707 tf.setColumns(10); 708 return tf; 709 } 710 711 /** 712 * Creates a medium sized text field. 713 * @return the created text field. 714 */ 715 public static JTextField createMediumTextField() 716 { 717 JTextField tf = createTextField(); 718 tf.setColumns(20); 719 return tf; 720 } 721 722 /** 723 * Creates a long text field. 724 * @return the created text field. 725 */ 726 public static JTextField createLongTextField() 727 { 728 JTextField tf = createTextField(); 729 tf.setColumns(30); 730 return tf; 731 } 732 733 734 /** 735 * Creates a text field with the default size. 736 * @return the created text field. 737 */ 738 public static JTextField createTextField() 739 { 740 JTextField tf = new JTextField(); 741 tf.addFocusListener(new TextComponentFocusListener(tf)); 742 tf.setFont(ColorAndFontConstants.defaultFont); 743 return tf; 744 } 745 746 /** 747 * Creates a pasword text field. 748 * @return the created password text field. 749 */ 750 public static JPasswordField createPasswordField() 751 { 752 JPasswordField pf = new JPasswordField(); 753 pf.addFocusListener(new TextComponentFocusListener(pf)); 754 pf.setFont(ColorAndFontConstants.defaultFont); 755 return pf; 756 } 757 758 /** 759 * Creates a pasword text field. 760 * @param cols the columns of the password text field. 761 * @return the created password text field. 762 */ 763 public static JPasswordField createPasswordField(int cols) 764 { 765 JPasswordField pf = createPasswordField(); 766 pf.setColumns(cols); 767 return pf; 768 } 769 770 771 /** 772 * Sets the border in a given component. If the component already has a 773 * border, creates a compound border. 774 * @param comp the component. 775 * @param border the border to be set. 776 */ 777 public static void setBorder(JComponent comp, Border border) 778 { 779 if (comp.getBorder() != null) 780 { 781 comp.setBorder(BorderFactory.createCompoundBorder(comp.getBorder(), border)); 782 } 783 else 784 { 785 comp.setBorder(border); 786 } 787 } 788 789 /** 790 * Checks the size of the table and of the scroll bar where it is contained, 791 * and depending on it updates the auto resize mode. 792 * @param scroll the scroll pane containing the table. 793 * @param table the table. 794 */ 795 public static void updateScrollMode(JScrollPane scroll, JTable table) 796 { 797 int width1 = table.getPreferredScrollableViewportSize().width; 798 int width2 = scroll.getViewport().getWidth(); 799 800 if (width1 > width2) 801 { 802 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 803 } 804 else 805 { 806 table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); 807 } 808 } 809 810 /** 811 * Updates the size of the table rows according to the size of the 812 * rendered component. 813 * @param table the table to handle. 814 */ 815 public static void updateTableSizes(JTable table) 816 { 817 updateTableSizes(table, -1); 818 } 819 820 /** 821 * Updates the size of the table rows according to the size of the 822 * rendered component. 823 * @param table the table to handle. 824 * @param rows the maximum rows to be displayed (-1 for unlimited) 825 */ 826 public static void updateTableSizes(JTable table, int rows) 827 { 828 int horizontalMargin = table.getIntercellSpacing().width; 829 int verticalMargin = table.getIntercellSpacing().height; 830 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 831 832 int headerMaxHeight = 5; 833 int headerMaxWidth = 0; 834 835 JTableHeader header = table.getTableHeader(); 836 if (header != null && header.isVisible()) 837 { 838 for (int col=0; col<table.getColumnCount(); col++) 839 { 840 TableColumn tcol = table.getColumnModel().getColumn(col); 841 TableCellRenderer renderer = tcol.getHeaderRenderer(); 842 if (renderer == null) 843 { 844 renderer = table.getTableHeader().getDefaultRenderer(); 845 } 846 Component comp = renderer.getTableCellRendererComponent(table, 847 table.getModel().getColumnName(col), false, false, 0, col); 848 int colHeight = comp.getPreferredSize().height + 2 * verticalMargin; 849 if (colHeight > screenSize.height) 850 { 851 // There are some issues on Mac OS and sometimes the preferred size 852 // is too big. 853 colHeight = 0; 854 } 855 headerMaxHeight = Math.max(headerMaxHeight, colHeight); 856 } 857 } 858 859 for (int col=0; col<table.getColumnCount(); col++) 860 { 861 int colMaxWidth = 8; 862 TableColumn tcol = table.getColumnModel().getColumn(col); 863 TableCellRenderer renderer = tcol.getHeaderRenderer(); 864 865 if (renderer == null && header != null) 866 { 867 renderer = header.getDefaultRenderer(); 868 } 869 870 if (renderer != null) 871 { 872 Component comp = renderer.getTableCellRendererComponent(table, 873 table.getModel().getColumnName(col), false, false, 0, col); 874 colMaxWidth = comp.getPreferredSize().width + 2 * horizontalMargin + 8; 875 } 876 877 if (colMaxWidth > screenSize.width) 878 { 879 colMaxWidth = 8; 880 } 881 882 for (int row=0; row<table.getRowCount(); row++) 883 { 884 renderer = table.getCellRenderer(row, col); 885 Component comp = table.prepareRenderer(renderer, row, col); 886 int colWidth = comp.getPreferredSize().width + 2 * horizontalMargin; 887 colMaxWidth = Math.max(colMaxWidth, colWidth); 888 } 889 tcol.setPreferredWidth(colMaxWidth); 890 headerMaxWidth += colMaxWidth; 891 } 892 893 894 if (header != null && header.isVisible()) 895 { 896 header.setPreferredSize(new Dimension(headerMaxWidth, headerMaxHeight)); 897 } 898 899 900 int maxRow = table.getRowHeight(); 901 for (int row=0; row<table.getRowCount(); row++) 902 { 903 for (int col=0; col<table.getColumnCount(); col++) 904 { 905 TableCellRenderer renderer = table.getCellRenderer(row, col); 906 Component comp = renderer.getTableCellRendererComponent(table, 907 table.getModel().getValueAt(row, col), false, false, row, col); 908 int colHeight = comp.getPreferredSize().height + 2 * verticalMargin; 909 if (colHeight > screenSize.height) 910 { 911 colHeight = 0; 912 } 913 maxRow = Math.max(maxRow, colHeight); 914 } 915 } 916 if (maxRow > table.getRowHeight()) 917 { 918 table.setRowHeight(maxRow); 919 } 920 Dimension d1; 921 if (rows == -1) 922 { 923 d1 = table.getPreferredSize(); 924 } 925 else 926 { 927 d1 = new Dimension(table.getPreferredSize().width, rows * maxRow); 928 } 929 table.setPreferredScrollableViewportSize(d1); 930 } 931 932 /** 933 * Returns a String that contains the html passed as parameter with a span 934 * applied. The span style corresponds to the Font specified as parameter. 935 * The goal of this method is to be able to specify a font for an HTML string. 936 * 937 * @param html the original html text. 938 * @param font the font to be used to generate the new HTML. 939 * @return a string that represents the original HTML with the font specified 940 * as parameter. 941 */ 942 public static String applyFont(CharSequence html, Font font) 943 { 944 return "<span style=\"" + getFontStyle(font) + "\">" + html + "</span>"; 945 } 946 947 948 /** 949 * Returns an ImageIcon or <CODE>null</CODE> if the path was invalid. 950 * @param path the path of the image. 951 * @param loader the class loader to use to load the image. If 952 * <CODE>null</CODE> this class class loader will be used. 953 * @return an ImageIcon or <CODE>null</CODE> if the path was invalid. 954 */ 955 public static ImageIcon createImageIcon(String path, ClassLoader loader) { 956 if (loader == null) 957 { 958 loader = ControlPanel.class.getClassLoader(); 959 } 960 java.net.URL imgURL = loader.getResource(path); 961 return imgURL != null ? new ImageIcon(imgURL) : null; 962 } 963 964 /** 965 * Returns an ImageIcon or <CODE>null</CODE> if the path was invalid. 966 * @param path the path of the image. 967 * @return an ImageIcon or <CODE>null</CODE> if the path was invalid. 968 */ 969 public static ImageIcon createImageIcon(String path) { 970 return createImageIcon(path, null); 971 } 972 973 /** 974 * Creates an image icon using an array of bytes that contain the image and 975 * specifying the maximum height of the image. 976 * @param bytes the byte array. 977 * @param maxHeight the maximum height of the image. 978 * @param description the description of the image. 979 * @param useFast whether a fast algorithm must be used to transform the image 980 * or an algorithm with a better result. 981 * @return an image icon using an array of bytes that contain the image and 982 * specifying the maximum height of the image. 983 */ 984 public static ImageIcon createImageIcon(byte[] bytes, int maxHeight, 985 LocalizableMessage description, boolean useFast) 986 { 987 ImageIcon icon = new ImageIcon(bytes, description.toString()); 988 if (maxHeight > icon.getIconHeight() || icon.getIconHeight() <= 0) 989 { 990 return icon; 991 } 992 int newHeight = maxHeight; 993 int newWidth = (newHeight * icon.getIconWidth()) / icon.getIconHeight(); 994 int algo = useFast ? Image.SCALE_FAST : Image.SCALE_SMOOTH; 995 Image scaledImage = icon.getImage().getScaledInstance(newWidth, newHeight, algo); 996 return new ImageIcon(scaledImage); 997 } 998 999 /** 1000 * Updates the preferred size of an editor pane. 1001 * @param pane the panel to be updated. 1002 * @param nCols the number of columns that the panel must have. 1003 * @param plainText the text to be displayed (plain text). 1004 * @param font the font to be used. 1005 * @param applyBackground whether an error/warning background must be applied 1006 * to the text or not. 1007 */ 1008 public static void updatePreferredSize(JEditorPane pane, int nCols, 1009 String plainText, Font font, boolean applyBackground) 1010 { 1011 String wrappedText = wrapText(plainText, nCols); 1012 wrappedText = wrappedText.replaceAll(ServerConstants.EOL, "<br>"); 1013 if (applyBackground) 1014 { 1015 wrappedText = UIFactory.applyErrorBackgroundToHtml( 1016 Utilities.applyFont(wrappedText, font)); 1017 } 1018 JEditorPane pane2 = makeHtmlPane(wrappedText, font); 1019 pane.setPreferredSize(pane2.getPreferredSize()); 1020 JFrame frame = getFrame(pane); 1021 if (frame != null && frame.isVisible()) 1022 { 1023 frame.getRootPane().revalidate(); 1024 frame.getRootPane().repaint(); 1025 } 1026 } 1027 1028 /** 1029 * Strips any potential HTML markup from a given string. 1030 * @param s string to strip 1031 * @return resulting string 1032 */ 1033 public static String stripHtmlToSingleLine(String s) { 1034 String o = null; 1035 if (s != null) { 1036 s = s.replaceAll("<br>", " "); 1037 // This is not a comprehensive solution but addresses 1038 // the few tags that we have in Resources.properties 1039 // at the moment. Note that the following might strip 1040 // out more than is intended for non-tags like 1041 // '<your name here>' or for funky tags like 1042 // '<tag attr="1 > 0">'. See test class for cases that 1043 // might cause problems. 1044 o = s.replaceAll("\\<.*?\\>",""); 1045 } 1046 return o; 1047 } 1048 1049 /** 1050 * Wraps the contents of the provided message using the specified number of 1051 * columns. 1052 * @param msg the message to be wrapped. 1053 * @param nCols the number of columns. 1054 * @return the wrapped message. 1055 */ 1056 public static LocalizableMessage wrapHTML(LocalizableMessage msg, int nCols) 1057 { 1058 String s = msg.toString(); 1059 StringBuilder sb = new StringBuilder(); 1060 StringBuilder lastLine = new StringBuilder(); 1061 int lastOpenTag = -1; 1062 boolean inTag = false; 1063 int lastSpace = -1; 1064 int lastLineLengthInLastSpace = 0; 1065 int lastLineLength = 0; 1066 for (int i=0; i<s.length() ; i++) 1067 { 1068 boolean isNormalChar = false; 1069 char c = s.charAt(i); 1070 if (c == '<') 1071 { 1072 inTag = true; 1073 lastOpenTag = i; 1074 lastLine.append(c); 1075 } 1076 else if (c == '>') 1077 { 1078 if (lastOpenTag != -1) 1079 { 1080 inTag = false; 1081 String tag = s.substring(lastOpenTag, i+1); 1082 lastOpenTag = -1; 1083 lastLine.append(c); 1084 if (isLineBreakTag(tag)) 1085 { 1086 sb.append(lastLine); 1087 lastLine.delete(0, lastLine.length()); 1088 lastLineLength = 0; 1089 lastSpace = -1; 1090 lastLineLengthInLastSpace = 0; 1091 } 1092 } 1093 else 1094 { 1095 isNormalChar = true; 1096 } 1097 } 1098 else if (inTag) 1099 { 1100 lastLine.append(c); 1101 } 1102 else if (c == HTML_SPACE.charAt(0)) 1103 { 1104 if (s.length() >= i + HTML_SPACE.length()) 1105 { 1106 if (HTML_SPACE.equalsIgnoreCase(s.substring(i, i 1107 + HTML_SPACE.length()))) 1108 { 1109 if (lastLineLength < nCols) 1110 { 1111 // Only count as 1 space 1112 lastLine.append(HTML_SPACE); 1113 lastSpace = lastLine.length() - HTML_SPACE.length(); 1114 lastLineLength ++; 1115 lastLineLengthInLastSpace = lastLineLength; 1116 i += HTML_SPACE.length() - 1; 1117 } 1118 else 1119 { 1120 // Insert a line break 1121 sb.append(lastLine); 1122 sb.append("<br>"); 1123 lastLine.delete(0, lastLine.length()); 1124 lastLineLength = 0; 1125 lastSpace = -1; 1126 lastLineLengthInLastSpace = 0; 1127 i += HTML_SPACE.length() - 1; 1128 } 1129 } 1130 else 1131 { 1132 isNormalChar = true; 1133 } 1134 } 1135 else 1136 { 1137 isNormalChar = true; 1138 } 1139 } 1140 else if (c == ' ') 1141 { 1142 if (lastLineLength < nCols) 1143 { 1144 // Only count as 1 space 1145 lastLine.append(c); 1146 lastSpace = lastLine.length() - 1; 1147 lastLineLength ++; 1148 lastLineLengthInLastSpace = lastLineLength; 1149 } 1150 else 1151 { 1152 // Insert a line break 1153 sb.append(lastLine); 1154 sb.append("<br>"); 1155 lastLine.delete(0, lastLine.length()); 1156 lastLineLength = 0; 1157 lastSpace = -1; 1158 lastLineLengthInLastSpace = 0; 1159 } 1160 } 1161 else 1162 { 1163 isNormalChar = true; 1164 } 1165 1166 if (isNormalChar) 1167 { 1168 if (lastLineLength < nCols) 1169 { 1170 lastLine.append(c); 1171 lastLineLength ++; 1172 } 1173 else 1174 { 1175 // Check where to insert a line break 1176 if (lastSpace != -1) 1177 { 1178 sb.append(lastLine, 0, lastSpace); 1179 sb.append("<br>"); 1180 lastLine.delete(0, lastSpace + 1); 1181 lastLine.append(c); 1182 lastLineLength = lastLineLength - lastLineLengthInLastSpace + 1; 1183 lastLineLengthInLastSpace = 0; 1184 lastSpace = -1; 1185 } 1186 else 1187 { 1188 // Force the line break. 1189 sb.append(lastLine); 1190 sb.append("<br>"); 1191 lastLine.delete(0, lastLine.length()); 1192 lastLine.append(c); 1193 lastLineLength = 1; 1194 } 1195 } 1196 } 1197 } 1198 if (lastLine.length() > 0) 1199 { 1200 sb.append(lastLine); 1201 } 1202 return LocalizableMessage.raw(sb.toString()); 1203 } 1204 1205 private static boolean isLineBreakTag(String tag) 1206 { 1207 return "<br>".equalsIgnoreCase(tag) || 1208 "</br>".equalsIgnoreCase(tag) || 1209 "</div>".equalsIgnoreCase(tag) || 1210 "<p>".equalsIgnoreCase(tag) || 1211 "</p>".equalsIgnoreCase(tag); 1212 } 1213 1214 /** 1215 * Center the component location based on its preferred size. The code 1216 * considers the particular case of 2 screens and puts the component on the 1217 * center of the left screen 1218 * 1219 * @param comp the component to be centered. 1220 */ 1221 public static void centerOnScreen(Component comp) 1222 { 1223 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 1224 1225 int width = comp.getPreferredSize().width; 1226 int height = comp.getPreferredSize().height; 1227 1228 boolean multipleScreen = screenSize.width / screenSize.height >= 2; 1229 1230 if (multipleScreen) 1231 { 1232 comp.setLocation(screenSize.width / 4 - width / 2, 1233 (screenSize.height - height) / 2); 1234 } else 1235 { 1236 comp.setLocation((screenSize.width - width) / 2, 1237 (screenSize.height - height) / 2); 1238 } 1239 } 1240 1241 /** 1242 * Center the component location of the ref component. 1243 * 1244 * @param comp the component to be centered. 1245 * @param ref the component to be used as reference. 1246 * 1247 */ 1248 public static void centerGoldenMean(Window comp, Component ref) 1249 { 1250 comp.setLocationRelativeTo(ref); 1251 // Apply the golden mean 1252 if (ref != null && ref.isVisible()) 1253 { 1254 int refY = ref.getY(); 1255 int refHeight = ref.getHeight(); 1256 int compHeight = comp.getPreferredSize().height; 1257 1258 int newY = refY + (int) (refHeight * 0.3819 - compHeight * 0.5); 1259 // Check that the new window will be fully visible 1260 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 1261 if (newY > 0 && screenSize.height > newY + compHeight) 1262 { 1263 comp.setLocation(comp.getX(), newY); 1264 } 1265 } 1266 } 1267 1268 /** 1269 * Returns the parent frame of a component. <CODE>null</CODE> if this 1270 * component is not contained in any frame. 1271 * @param comp the component. 1272 * @return the parent frame of a component. <CODE>null</CODE> if this 1273 * component is not contained in any frame. 1274 */ 1275 public static JFrame getFrame(Component comp) 1276 { 1277 Component parent = comp; 1278 while (parent != null && !(parent instanceof JFrame)) 1279 { 1280 parent = parent.getParent(); 1281 } 1282 return parent != null ? (JFrame) parent : null; 1283 } 1284 1285 /** 1286 * Returns the parent dialog of a component. <CODE>null</CODE> if this 1287 * component is not contained in any dialog. 1288 * @param comp the component. 1289 * @return the parent dialog of a component. <CODE>null</CODE> if this 1290 * component is not contained in any dialog. 1291 */ 1292 public static Window getParentDialog(Component comp) 1293 { 1294 Component parent = comp; 1295 while (parent != null) 1296 { 1297 if (parent instanceof JDialog || parent instanceof JFrame) 1298 { 1299 return (Window)parent; 1300 } 1301 parent = parent.getParent(); 1302 } 1303 return null; 1304 } 1305 1306 /** 1307 * Unescapes UTF-8 text and generates a String from it. 1308 * @param v the string in UTF-8 format. 1309 * @return the string with unescaped characters. 1310 */ 1311 public static String unescapeUtf8(String v) 1312 { 1313 try 1314 { 1315 byte[] stringBytes = v.getBytes("UTF-8"); 1316 byte[] decodedBytes = new byte[stringBytes.length]; 1317 int pos = 0; 1318 for (int i = 0; i < stringBytes.length; i++) 1319 { 1320 if (stringBytes[i] == '\\' 1321 && i + 2 < stringBytes.length 1322 && StaticUtils.isHexDigit(stringBytes[i+1]) 1323 && StaticUtils.isHexDigit(stringBytes[i+2])) 1324 { 1325 // Convert hex-encoded UTF-8 to 16-bit chars. 1326 byte b; 1327 1328 byte escapedByte1 = stringBytes[++i]; 1329 switch (escapedByte1) 1330 { 1331 case '0': 1332 b = (byte) 0x00; 1333 break; 1334 case '1': 1335 b = (byte) 0x10; 1336 break; 1337 case '2': 1338 b = (byte) 0x20; 1339 break; 1340 case '3': 1341 b = (byte) 0x30; 1342 break; 1343 case '4': 1344 b = (byte) 0x40; 1345 break; 1346 case '5': 1347 b = (byte) 0x50; 1348 break; 1349 case '6': 1350 b = (byte) 0x60; 1351 break; 1352 case '7': 1353 b = (byte) 0x70; 1354 break; 1355 case '8': 1356 b = (byte) 0x80; 1357 break; 1358 case '9': 1359 b = (byte) 0x90; 1360 break; 1361 case 'a': 1362 case 'A': 1363 b = (byte) 0xA0; 1364 break; 1365 case 'b': 1366 case 'B': 1367 b = (byte) 0xB0; 1368 break; 1369 case 'c': 1370 case 'C': 1371 b = (byte) 0xC0; 1372 break; 1373 case 'd': 1374 case 'D': 1375 b = (byte) 0xD0; 1376 break; 1377 case 'e': 1378 case 'E': 1379 b = (byte) 0xE0; 1380 break; 1381 case 'f': 1382 case 'F': 1383 b = (byte) 0xF0; 1384 break; 1385 default: 1386 throw new RuntimeException("Unexpected byte: "+escapedByte1); 1387 } 1388 1389 byte escapedByte2 = stringBytes[++i]; 1390 switch (escapedByte2) 1391 { 1392 case '0': 1393 break; 1394 case '1': 1395 b |= 0x01; 1396 break; 1397 case '2': 1398 b |= 0x02; 1399 break; 1400 case '3': 1401 b |= 0x03; 1402 break; 1403 case '4': 1404 b |= 0x04; 1405 break; 1406 case '5': 1407 b |= 0x05; 1408 break; 1409 case '6': 1410 b |= 0x06; 1411 break; 1412 case '7': 1413 b |= 0x07; 1414 break; 1415 case '8': 1416 b |= 0x08; 1417 break; 1418 case '9': 1419 b |= 0x09; 1420 break; 1421 case 'a': 1422 case 'A': 1423 b |= 0x0A; 1424 break; 1425 case 'b': 1426 case 'B': 1427 b |= 0x0B; 1428 break; 1429 case 'c': 1430 case 'C': 1431 b |= 0x0C; 1432 break; 1433 case 'd': 1434 case 'D': 1435 b |= 0x0D; 1436 break; 1437 case 'e': 1438 case 'E': 1439 b |= 0x0E; 1440 break; 1441 case 'f': 1442 case 'F': 1443 b |= 0x0F; 1444 break; 1445 default: 1446 throw new RuntimeException("Unexpected byte: "+escapedByte2); 1447 } 1448 1449 decodedBytes[pos++] = b; 1450 } 1451 else { 1452 decodedBytes[pos++] = stringBytes[i]; 1453 } 1454 } 1455 return new String(decodedBytes, 0, pos, "UTF-8"); 1456 } 1457 catch (UnsupportedEncodingException uee) 1458 { 1459// This is a bug, UTF-8 should be supported always by the JVM 1460 throw new RuntimeException("UTF-8 encoding not supported", uee); 1461 } 1462 } 1463 1464 /** 1465 * Returns <CODE>true</CODE> if the the provided strings represent the same 1466 * DN and <CODE>false</CODE> otherwise. 1467 * @param dn1 the first dn to compare. 1468 * @param dn2 the second dn to compare. 1469 * @return <CODE>true</CODE> if the the provided strings represent the same 1470 * DN and <CODE>false</CODE> otherwise. 1471 */ 1472 public static boolean areDnsEqual(String dn1, String dn2) 1473 { 1474 try 1475 { 1476 LdapName name1 = new LdapName(dn1); 1477 LdapName name2 = new LdapName(dn2); 1478 return name1.equals(name2); 1479 } catch (Exception ex) 1480 { 1481 return false; 1482 } 1483 } 1484 1485 1486 /** 1487 * Gets the RDN string for a given attribute name and value. 1488 * @param attrName the attribute name. 1489 * @param attrValue the attribute value. 1490 * @return the RDN string for the attribute name and value. 1491 */ 1492 public static String getRDNString(String attrName, String attrValue) 1493 { 1494 AttributeType attrType = DirectoryServer.getAttributeTypeOrDefault(attrName); 1495 RDN rdn = new RDN(attrType, attrName, ByteString.valueOfUtf8(attrValue)); 1496 return rdn.toString(); 1497 } 1498 1499 /** 1500 * Returns the attribute name with no options (or subtypes). 1501 * @param attrName the complete attribute name. 1502 * @return the attribute name with no options (or subtypes). 1503 */ 1504 1505 public static String getAttributeNameWithoutOptions(String attrName) 1506 { 1507 int index = attrName.indexOf(";"); 1508 if (index != -1) 1509 { 1510 attrName = attrName.substring(0, index); 1511 } 1512 return attrName; 1513 } 1514 1515 /** 1516 * Strings any potential "separator" from a given string. 1517 * @param s string to strip 1518 * @param separator the separator string to remove 1519 * @return resulting string 1520 */ 1521 private static String stripStringToSingleLine(String s, String separator) 1522 { 1523 if (s != null) 1524 { 1525 return s.replaceAll(separator, ""); 1526 } 1527 return null; 1528 } 1529 1530 /** The pattern for control characters. */ 1531 private final static Pattern cntrl_pattern = Pattern.compile("\\p{Cntrl}", Pattern.MULTILINE); 1532 1533 /** 1534 * Checks if a string contains control characters. 1535 * @param s : the string to check 1536 * @return true if s contains control characters, false otherwise 1537 */ 1538 public static boolean hasControlCharaters(String s) 1539 { 1540 return cntrl_pattern.matcher(s).find(); 1541 } 1542 1543 /** 1544 * This is a helper method that gets a String representation of the elements 1545 * in the Collection. The String will display the different elements separated 1546 * by the separator String. 1547 * 1548 * @param col 1549 * the collection containing the String. 1550 * @param separator 1551 * the separator String to be used. 1552 * @return the String representation for the collection. 1553 */ 1554 public static String getStringFromCollection(Collection<String> col, String separator) 1555 { 1556 StringBuilder msg = new StringBuilder(); 1557 for (String m : col) 1558 { 1559 if (msg.length() > 0) 1560 { 1561 msg.append(separator); 1562 } 1563 msg.append(stripStringToSingleLine(m, separator)); 1564 } 1565 return msg.toString(); 1566 } 1567 1568 /** 1569 * Commodity method to get the Name object representing a dn. 1570 * It is preferable to use Name objects when doing JNDI operations to avoid 1571 * problems with the '/' character. 1572 * @param dn the DN as a String. 1573 * @return a Name object representing the DN. 1574 * @throws InvalidNameException if the provided DN value is not valid. 1575 * 1576 */ 1577 public static Name getJNDIName(String dn) throws InvalidNameException 1578 { 1579 Name name = new CompositeName(); 1580 if (dn != null && dn.length() > 0) { 1581 name.add(dn); 1582 } 1583 return name; 1584 } 1585 1586 /** 1587 * Returns the HTML representation of the 'Done' string. 1588 * @param progressFont the font to be used. 1589 * @return the HTML representation of the 'Done' string. 1590 */ 1591 public static String getProgressDone(Font progressFont) 1592 { 1593 return applyFont(INFO_CTRL_PANEL_PROGRESS_DONE.get(), 1594 progressFont.deriveFont(Font.BOLD)); 1595 } 1596 1597 /** 1598 * Returns the HTML representation of a message to which some points have 1599 * been appended. 1600 * @param plainText the plain text. 1601 * @param progressFont the font to be used. 1602 * @return the HTML representation of a message to which some points have 1603 * been appended. 1604 */ 1605 public static String getProgressWithPoints(LocalizableMessage plainText, 1606 Font progressFont) 1607 { 1608 return applyFont(plainText.toString(), progressFont)+ 1609 applyFont(" ..... ", 1610 progressFont.deriveFont(Font.BOLD)); 1611 } 1612 1613 /** 1614 * Returns the HTML representation of an error for a given text. 1615 * @param title the title. 1616 * @param titleFont the font for the title. 1617 * @param details the details. 1618 * @param detailsFont the font to be used for the details. 1619 * @return the HTML representation of an error for the given text. 1620 */ 1621 public static String getFormattedError(LocalizableMessage title, Font titleFont, 1622 LocalizableMessage details, Font detailsFont) 1623 { 1624 StringBuilder buf = new StringBuilder(); 1625 buf.append(UIFactory.getIconHtml(UIFactory.IconType.ERROR_LARGE)) 1626 .append(HTML_SPACE).append(HTML_SPACE) 1627 .append(applyFont(title.toString(), titleFont)); 1628 if (details != null) 1629 { 1630 buf.append("<br><br>") 1631 .append(applyFont(details.toString(), detailsFont)); 1632 } 1633 return "<form>"+UIFactory.applyErrorBackgroundToHtml(buf.toString())+ 1634 "</form>"; 1635 } 1636 1637 /** 1638 * Returns the HTML representation of a success for a given text. 1639 * @param title the title. 1640 * @param titleFont the font for the title. 1641 * @param details the details. 1642 * @param detailsFont the font to be used for the details. 1643 * @return the HTML representation of a success for the given text. 1644 */ 1645 public static String getFormattedSuccess(LocalizableMessage title, Font titleFont, 1646 LocalizableMessage details, Font detailsFont) 1647 { 1648 StringBuilder buf = new StringBuilder(); 1649 buf.append(UIFactory.getIconHtml(UIFactory.IconType.INFORMATION_LARGE)) 1650 .append(HTML_SPACE).append(HTML_SPACE) 1651 .append(applyFont(title.toString(), titleFont)); 1652 if (details != null) 1653 { 1654 buf.append("<br><br>") 1655 .append(applyFont(details.toString(), detailsFont)); 1656 } 1657 return "<form>"+UIFactory.applyErrorBackgroundToHtml(buf.toString())+ 1658 "</form>"; 1659 } 1660 1661 /** 1662 * Returns the HTML representation of a confirmation for a given text. 1663 * @param title the title. 1664 * @param titleFont the font for the title. 1665 * @param details the details. 1666 * @param detailsFont the font to be used for the details. 1667 * @return the HTML representation of a confirmation for the given text. 1668 */ 1669 public static String getFormattedConfirmation(LocalizableMessage title, Font titleFont, 1670 LocalizableMessage details, Font detailsFont) 1671 { 1672 StringBuilder buf = new StringBuilder(); 1673 buf.append(UIFactory.getIconHtml(UIFactory.IconType.WARNING_LARGE)) 1674 .append(HTML_SPACE).append(HTML_SPACE) 1675 .append(applyFont(title.toString(), titleFont)); 1676 if (details != null) 1677 { 1678 buf.append("<br><br>") 1679 .append(applyFont(details.toString(), detailsFont)); 1680 } 1681 return "<form>" + buf + "</form>"; 1682 } 1683 1684 1685 /** 1686 * Returns the HTML representation of a warning for a given text. 1687 * @param title the title. 1688 * @param titleFont the font for the title. 1689 * @param details the details. 1690 * @param detailsFont the font to be used for the details. 1691 * @return the HTML representation of a success for the given text. 1692 */ 1693 public static String getFormattedWarning(LocalizableMessage title, Font titleFont, 1694 LocalizableMessage details, Font detailsFont) 1695 { 1696 StringBuilder buf = new StringBuilder(); 1697 buf.append(UIFactory.getIconHtml(UIFactory.IconType.WARNING_LARGE)) 1698 .append(HTML_SPACE).append(HTML_SPACE) 1699 .append(applyFont(title.toString(), titleFont)); 1700 if (details != null) 1701 { 1702 buf.append("<br><br>") 1703 .append(applyFont(details.toString(), detailsFont)); 1704 } 1705 return "<form>"+UIFactory.applyErrorBackgroundToHtml(buf.toString())+ 1706 "</form>"; 1707 } 1708 1709 /** 1710 * Sets the not available text to a label and associates a help icon and 1711 * a tooltip explaining that the data is not available because the server is 1712 * down. 1713 * @param l the label. 1714 */ 1715 public static void setNotAvailableBecauseServerIsDown(LabelWithHelpIcon l) 1716 { 1717 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1718 l.setHelpIconVisible(true); 1719 l.setHelpTooltip(INFO_NOT_AVAILABLE_SERVER_DOWN_TOOLTIP.get().toString()); 1720 } 1721 1722 /** 1723 * Sets the not available text to a label and associates a help icon and 1724 * a tooltip explaining that the data is not available because authentication 1725 * is required. 1726 * @param l the label. 1727 */ 1728 public static void setNotAvailableBecauseAuthenticationIsRequired( 1729 LabelWithHelpIcon l) 1730 { 1731 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1732 l.setHelpIconVisible(true); 1733 l.setHelpTooltip(INFO_NOT_AVAILABLE_AUTHENTICATION_REQUIRED_TOOLTIP.get().toString()); 1734 } 1735 1736 /** 1737 * Sets the not available text to a label and associates a help icon and 1738 * a tooltip explaining that the data is not available because the server is 1739 * down. 1740 * @param l the label. 1741 */ 1742 public static void setNotAvailableBecauseServerIsDown( 1743 SelectableLabelWithHelpIcon l) 1744 { 1745 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1746 l.setHelpIconVisible(true); 1747 l.setHelpTooltip(INFO_NOT_AVAILABLE_SERVER_DOWN_TOOLTIP.get().toString()); 1748 } 1749 1750 /** 1751 * Sets the not available text to a label and associates a help icon and 1752 * a tooltip explaining that the data is not available because authentication 1753 * is required. 1754 * @param l the label. 1755 */ 1756 public static void setNotAvailableBecauseAuthenticationIsRequired( 1757 SelectableLabelWithHelpIcon l) 1758 { 1759 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1760 l.setHelpIconVisible(true); 1761 l.setHelpTooltip(INFO_NOT_AVAILABLE_AUTHENTICATION_REQUIRED_TOOLTIP.get().toString()); 1762 } 1763 1764 /** 1765 * Updates a label by setting a warning icon and a text. 1766 * @param l the label to be updated. 1767 * @param text the text to be set on the label. 1768 */ 1769 public static void setWarningLabel(JLabel l, LocalizableMessage text) 1770 { 1771 l.setText(text.toString()); 1772 if (warningIcon == null) 1773 { 1774 warningIcon = 1775 createImageIcon("org/opends/quicksetup/images/warning_medium.gif"); 1776 warningIcon.setDescription( 1777 INFO_WARNING_ICON_ACCESSIBLE_DESCRIPTION.get().toString()); 1778 warningIcon.getAccessibleContext().setAccessibleName( 1779 INFO_WARNING_ICON_ACCESSIBLE_DESCRIPTION.get().toString()); 1780 } 1781 l.setIcon(warningIcon); 1782 l.setToolTipText(text.toString()); 1783 l.setHorizontalTextPosition(SwingConstants.RIGHT); 1784 } 1785 1786 /** 1787 * Sets the not available text to a label with no icon nor tooltip. 1788 * @param l the label. 1789 */ 1790 public static void setNotAvailable(LabelWithHelpIcon l) 1791 { 1792 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1793 l.setHelpIconVisible(false); 1794 l.setHelpTooltip(null); 1795 } 1796 1797 /** 1798 * Sets the a text to a label with no icon nor tooltip. 1799 * @param l the label. 1800 * @param text the text. 1801 */ 1802 public static void setTextValue(LabelWithHelpIcon l, String text) 1803 { 1804 l.setText(text); 1805 l.setHelpIconVisible(false); 1806 l.setHelpTooltip(null); 1807 } 1808 1809 /** 1810 * Sets the not available text to a label with no icon nor tooltip. 1811 * @param l the label. 1812 */ 1813 public static void setNotAvailable(SelectableLabelWithHelpIcon l) 1814 { 1815 l.setText(INFO_CTRL_PANEL_NOT_AVAILABLE_LONG_LABEL.get().toString()); 1816 l.setHelpIconVisible(false); 1817 l.setHelpTooltip(null); 1818 } 1819 1820 /** 1821 * Sets the a text to a label with no icon nor tooltip. 1822 * @param l the label. 1823 * @param text the text. 1824 */ 1825 public static void setTextValue(SelectableLabelWithHelpIcon l, String text) 1826 { 1827 l.setText(text); 1828 l.setHelpIconVisible(false); 1829 l.setHelpTooltip(null); 1830 } 1831 1832 /** 1833 * Returns the server root directory (the path where the server is installed). 1834 * <p> 1835 * Note: this method is called by SNMP code. 1836 * 1837 * @return the server root directory (the path where the server is installed). 1838 */ 1839 public static File getServerRootDirectory() 1840 { 1841 if (rootDirectory == null) 1842 { 1843 // This allows testing of configuration components when the OpenDJ.jar 1844 // in the classpath does not necessarily point to the server's 1845 String installRoot = System.getProperty("org.opends.quicksetup.Root"); 1846 1847 if (installRoot == null) { 1848 installRoot = getInstallPathFromClasspath(); 1849 } 1850 rootDirectory = new File(installRoot); 1851 } 1852 return rootDirectory; 1853 } 1854 1855 /** 1856 * Returns the instance root directory (the path where the instance is 1857 * installed). 1858 * @param installPath The installRoot path. 1859 * @return the instance root directory (the path where the instance is 1860 * installed). 1861 */ 1862 public static File getInstanceRootDirectory(String installPath) 1863 { 1864 if (instanceRootDirectory == null) 1865 { 1866 instanceRootDirectory = new File( 1867 Utils.getInstancePathFromInstallPath(installPath)); 1868 } 1869 return instanceRootDirectory; 1870 } 1871 1872 /** 1873 * Returns the path of the installation of the directory server. Note that 1874 * this method assumes that this code is being run locally. 1875 * @return the path of the installation of the directory server. 1876 */ 1877 public static String getInstallPathFromClasspath() 1878 { 1879 String installPath = null; 1880 1881 /* Get the install path from the Class Path */ 1882 String sep = System.getProperty("path.separator"); 1883 String[] classPaths = System.getProperty("java.class.path").split(sep); 1884 String path = getInstallPath(classPaths); 1885 if (path != null) { 1886 File f = new File(path).getAbsoluteFile(); 1887 File librariesDir = f.getParentFile(); 1888 1889 /* 1890 * Do a best effort to avoid having a relative representation (for 1891 * instance to avoid having ../../../). 1892 */ 1893 try 1894 { 1895 installPath = librariesDir.getParentFile().getCanonicalPath(); 1896 } 1897 catch (IOException ioe) 1898 { 1899 // Best effort 1900 installPath = librariesDir.getParent(); 1901 } 1902 } 1903 return installPath; 1904 } 1905 1906 private static String getInstallPath(String[] classPaths) 1907 { 1908 for (String classPath : classPaths) 1909 { 1910 final String normPath = classPath.replace(File.separatorChar, '/'); 1911 if (normPath.endsWith(OPENDJ_BOOTSTRAP_CLIENT_JAR_RELATIVE_PATH) 1912 || normPath.endsWith(OPENDJ_BOOTSTRAP_JAR_RELATIVE_PATH)) 1913 { 1914 return classPath; 1915 } 1916 } 1917 return null; 1918 } 1919 1920 /** 1921 * Returns <CODE>true</CODE> if the server located in the provided path 1922 * is running and <CODE>false</CODE> otherwise. 1923 * @param serverRootDirectory the path where the server is installed. 1924 * @return <CODE>true</CODE> if the server located in the provided path 1925 * is running and <CODE>false</CODE> otherwise. 1926 */ 1927 public static boolean isServerRunning(File serverRootDirectory) 1928 { 1929 String lockFileName = ServerConstants.SERVER_LOCK_FILE_NAME + ServerConstants.LOCK_FILE_SUFFIX; 1930 String lockPathRelative = Installation.LOCKS_PATH_RELATIVE; 1931 File locksPath = new File(serverRootDirectory, lockPathRelative); 1932 String lockFile = new File(locksPath, lockFileName).getAbsolutePath(); 1933 StringBuilder failureReason = new StringBuilder(); 1934 try { 1935 if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 1936 { 1937 LockFileManager.releaseLock(lockFile, failureReason); 1938 return false; 1939 } 1940 return true; 1941 } 1942 catch (Throwable t) { 1943 // Assume that if we cannot acquire the lock file the 1944 // server is running. 1945 return true; 1946 } 1947 } 1948 1949 private static final String VALID_SCHEMA_SYNTAX = 1950 "abcdefghijklmnopqrstuvwxyz0123456789-"; 1951 1952 /** 1953 * Returns <CODE>true</CODE> if the provided string can be used as objectclass 1954 * name and <CODE>false</CODE> otherwise. 1955 * @param s the string to be analyzed. 1956 * @return <CODE>true</CODE> if the provided string can be used as objectclass 1957 * name and <CODE>false</CODE> otherwise. 1958 */ 1959 private static boolean isValidObjectclassName(String s) 1960 { 1961 if (s == null || s.length() == 0) 1962 { 1963 return false; 1964 } 1965 1966 final StringCharacterIterator iter = new StringCharacterIterator(s, 0); 1967 char c = iter.first(); 1968 while (c != CharacterIterator.DONE) 1969 { 1970 if (VALID_SCHEMA_SYNTAX.indexOf(Character.toLowerCase(c)) == -1) 1971 { 1972 return false; 1973 } 1974 c = iter.next(); 1975 } 1976 return true; 1977 } 1978 1979 /** 1980 * Returns <CODE>true</CODE> if the provided string can be used as attribute 1981 * name and <CODE>false</CODE> otherwise. 1982 * @param s the string to be analyzed. 1983 * @return <CODE>true</CODE> if the provided string can be used as attribute 1984 * name and <CODE>false</CODE> otherwise. 1985 */ 1986 public static boolean isValidAttributeName(String s) 1987 { 1988 return isValidObjectclassName(s); 1989 } 1990 1991 /** 1992 * Returns the representation of the VLV index as it must be used in the 1993 * command-line. 1994 * @param index the VLV index. 1995 * @return the representation of the VLV index as it must be used in the 1996 * command-line. 1997 */ 1998 public static String getVLVNameInCommandLine(VLVIndexDescriptor index) 1999 { 2000 return "vlv."+index.getName(); 2001 } 2002 2003 /** 2004 * Returns a string representing the VLV index in a cell. 2005 * @param index the VLV index to be represented. 2006 * @return the string representing the VLV index in a cell. 2007 */ 2008 public static String getVLVNameInCellRenderer(VLVIndexDescriptor index) 2009 { 2010 return INFO_CTRL_PANEL_VLV_INDEX_CELL.get(index.getName()).toString(); 2011 } 2012 2013 private static final String[] standardSchemaFileNames = 2014 { 2015 "00-core.ldif", "01-pwpolicy.ldif", "03-changelog.ldif", 2016 "03-uddiv3.ldif", "05-solaris.ldif" 2017 }; 2018 2019 private static final String[] configurationSchemaOrigins = 2020 { 2021 "OpenDJ Directory Server", "OpenDS Directory Server", 2022 "Sun Directory Server", "Microsoft Active Directory" 2023 }; 2024 2025 private static final String[] standardSchemaOrigins = 2026 { 2027 "Sun Java System Directory Server", "Solaris Specific", "X.501" 2028 }; 2029 2030 private static final String[] configurationSchemaFileNames = 2031 { 2032 "02-config.ldif", "06-compat.ldif" 2033 }; 2034 2035 /** 2036 * Returns <CODE>true</CODE> if the provided schema element is part of the 2037 * standard and <CODE>false</CODE> otherwise. 2038 * @param fileElement the schema element. 2039 * @return <CODE>true</CODE> if the provided schema element is part of the 2040 * standard and <CODE>false</CODE> otherwise. 2041 */ 2042 public static boolean isStandard(SchemaFileElement fileElement) 2043 { 2044 final String fileName = getSchemaFile(fileElement); 2045 if (fileName != null) 2046 { 2047 return contains(standardSchemaFileNames, fileName) || fileName.toLowerCase().contains("-rfc"); 2048 } 2049 else if (fileElement instanceof CommonSchemaElements) 2050 { 2051 String xOrigin = getOrigin(fileElement); 2052 if (xOrigin != null) 2053 { 2054 return contains(standardSchemaOrigins, xOrigin) || xOrigin.startsWith("RFC ") || xOrigin.startsWith("draft-"); 2055 } 2056 } 2057 return false; 2058 } 2059 2060 /** 2061 * Returns <CODE>true</CODE> if the provided schema element is part of the 2062 * configuration and <CODE>false</CODE> otherwise. 2063 * @param fileElement the schema element. 2064 * @return <CODE>true</CODE> if the provided schema element is part of the 2065 * configuration and <CODE>false</CODE> otherwise. 2066 */ 2067 public static boolean isConfiguration(SchemaFileElement fileElement) 2068 { 2069 String fileName = getSchemaFile(fileElement); 2070 if (fileName != null) 2071 { 2072 return contains(configurationSchemaFileNames, fileName); 2073 } 2074 else if (fileElement instanceof CommonSchemaElements) 2075 { 2076 String xOrigin = getOrigin(fileElement); 2077 if (xOrigin != null) 2078 { 2079 return contains(configurationSchemaOrigins, xOrigin); 2080 } 2081 } 2082 return false; 2083 } 2084 2085 private static boolean contains(String[] names, String toFind) 2086 { 2087 for (String name : names) 2088 { 2089 if (toFind.equals(name)) 2090 { 2091 return true; 2092 } 2093 } 2094 return false; 2095 } 2096 2097 /** 2098 * Returns the origin of the provided schema element. 2099 * @param element the schema element. 2100 * @return the origin of the provided schema element. 2101 */ 2102 public static String getOrigin(SchemaFileElement element) 2103 { 2104 return CommonSchemaElements.getSingleValueProperty( 2105 element, ServerConstants.SCHEMA_PROPERTY_ORIGIN); 2106 } 2107 2108 /** 2109 * Returns the string representation of an attribute syntax. 2110 * @param syntax the attribute syntax. 2111 * @return the string representation of an attribute syntax. 2112 */ 2113 public static String getSyntaxText(Syntax syntax) 2114 { 2115 String syntaxName = syntax.getName(); 2116 String syntaxOID = syntax.getOID(); 2117 if (syntaxName != null) 2118 { 2119 return syntaxName + " - " + syntaxOID; 2120 } 2121 return syntaxOID; 2122 } 2123 2124 /** 2125 * Returns <CODE>true</CODE> if the provided attribute has image syntax and 2126 * <CODE>false</CODE> otherwise. 2127 * @param attrName the name of the attribute. 2128 * @param schema the schema. 2129 * @return <CODE>true</CODE> if the provided attribute has image syntax and 2130 * <CODE>false</CODE> otherwise. 2131 */ 2132 public static boolean hasImageSyntax(String attrName, Schema schema) 2133 { 2134 attrName = Utilities.getAttributeNameWithoutOptions(attrName).toLowerCase(); 2135 if ("photo".equals(attrName)) 2136 { 2137 return true; 2138 } 2139 // Check all the attributes that we consider binaries. 2140 if (schema != null) 2141 { 2142 AttributeType attr = schema.getAttributeType(attrName); 2143 if (attr != null) 2144 { 2145 String syntaxOID = attr.getSyntax().getOID(); 2146 return SchemaConstants.SYNTAX_JPEG_OID.equals(syntaxOID); 2147 } 2148 } 2149 return false; 2150 } 2151 2152 /** 2153 * Returns <CODE>true</CODE> if the provided attribute has binary syntax and 2154 * <CODE>false</CODE> otherwise. 2155 * @param attrName the name of the attribute. 2156 * @param schema the schema. 2157 * @return <CODE>true</CODE> if the provided attribute has binary syntax and 2158 * <CODE>false</CODE> otherwise. 2159 */ 2160 public static boolean hasBinarySyntax(String attrName, Schema schema) 2161 { 2162 return attrName.toLowerCase().contains(";binary") 2163 || hasAnySyntax(attrName, schema, binarySyntaxOIDs); 2164 } 2165 2166 /** 2167 * Returns <CODE>true</CODE> if the provided attribute has password syntax and 2168 * <CODE>false</CODE> otherwise. 2169 * @param attrName the name of the attribute. 2170 * @param schema the schema. 2171 * @return <CODE>true</CODE> if the provided attribute has password syntax and 2172 * <CODE>false</CODE> otherwise. 2173 */ 2174 public static boolean hasPasswordSyntax(String attrName, Schema schema) 2175 { 2176 return hasAnySyntax(attrName, schema, passwordSyntaxOIDs); 2177 } 2178 2179 private static boolean hasAnySyntax(String attrName, Schema schema, String[] oids) 2180 { 2181 if (schema != null) 2182 { 2183 attrName = Utilities.getAttributeNameWithoutOptions(attrName).toLowerCase(); 2184 AttributeType attr = schema.getAttributeType(attrName); 2185 if (attr != null) 2186 { 2187 return contains(oids, attr.getSyntax().getOID()); 2188 } 2189 } 2190 return false; 2191 } 2192 2193 /** 2194 * Returns the string representation of a matching rule. 2195 * @param matchingRule the matching rule. 2196 * @return the string representation of a matching rule. 2197 */ 2198 public static String getMatchingRuleText(MatchingRule matchingRule) 2199 { 2200 String nameOrOID = matchingRule.getNameOrOID(); 2201 String oid = matchingRule.getOID(); 2202 if (!nameOrOID.equals(oid)) 2203 { 2204 // This is the name only 2205 return nameOrOID + " - " + oid; 2206 } 2207 return oid; 2208 } 2209 2210 /** 2211 * Returns the InitialLdapContext to connect to the administration connector 2212 * of the server using the information in the ControlCenterInfo object (which 2213 * provides the host and administration connector port to be used) and some 2214 * LDAP credentials. 2215 * It also tests that the provided credentials have enough rights to read the 2216 * configuration. 2217 * @param controlInfo the object which provides the connection parameters. 2218 * @param bindDN the base DN to be used to bind. 2219 * @param pwd the password to be used to bind. 2220 * @return the InitialLdapContext connected to the server. 2221 * @throws NamingException if there was a problem connecting to the server 2222 * or the provided credentials do not have enough rights. 2223 * @throws ConfigReadException if there is an error reading the configuration. 2224 */ 2225 public static InitialLdapContext getAdminDirContext( 2226 ControlPanelInfo controlInfo, String bindDN, String pwd) 2227 throws NamingException, ConfigReadException 2228 { 2229 String usedUrl = controlInfo.getAdminConnectorURL(); 2230 if (usedUrl == null) 2231 { 2232 throw new ConfigReadException( 2233 ERR_COULD_NOT_FIND_VALID_LDAPURL.get()); 2234 } 2235 2236 InitialLdapContext ctx = createLdapsContext(usedUrl, 2237 bindDN, pwd, controlInfo.getConnectTimeout(), null, 2238 controlInfo.getTrustManager(), null); 2239 // Search for the config to check that it is the directory manager. 2240 checkCanReadConfig(ctx); 2241 return ctx; 2242 } 2243 2244 2245 /** 2246 * Returns the InitialLdapContext to connect to the server using the 2247 * information in the ControlCenterInfo object (which provides the host, port 2248 * and protocol to be used) and some LDAP credentials. It also tests that 2249 * the provided credentials have enough rights to read the configuration. 2250 * @param controlInfo the object which provides the connection parameters. 2251 * @param bindDN the base DN to be used to bind. 2252 * @param pwd the password to be used to bind. 2253 * @return the InitialLdapContext connected to the server. 2254 * @throws NamingException if there was a problem connecting to the server 2255 * or the provided credentials do not have enough rights. 2256 * @throws ConfigReadException if there is an error reading the configuration. 2257 */ 2258 public static InitialLdapContext getUserDataDirContext( 2259 ControlPanelInfo controlInfo, 2260 String bindDN, String pwd) throws NamingException, ConfigReadException 2261 { 2262 InitialLdapContext ctx; 2263 String usedUrl; 2264 if (controlInfo.connectUsingStartTLS()) 2265 { 2266 usedUrl = controlInfo.getStartTLSURL(); 2267 if (usedUrl == null) 2268 { 2269 throw new ConfigReadException( 2270 ERR_COULD_NOT_FIND_VALID_LDAPURL.get()); 2271 } 2272 ctx = Utils.createStartTLSContext(usedUrl, 2273 bindDN, pwd, controlInfo.getConnectTimeout(), null, 2274 controlInfo.getTrustManager(), null); 2275 } 2276 else if (controlInfo.connectUsingLDAPS()) 2277 { 2278 usedUrl = controlInfo.getLDAPSURL(); 2279 if (usedUrl == null) 2280 { 2281 throw new ConfigReadException( 2282 ERR_COULD_NOT_FIND_VALID_LDAPURL.get()); 2283 } 2284 ctx = createLdapsContext(usedUrl, 2285 bindDN, pwd, controlInfo.getConnectTimeout(), null, 2286 controlInfo.getTrustManager(), null); 2287 } 2288 else 2289 { 2290 usedUrl = controlInfo.getLDAPURL(); 2291 if (usedUrl == null) 2292 { 2293 throw new ConfigReadException( 2294 ERR_COULD_NOT_FIND_VALID_LDAPURL.get()); 2295 } 2296 ctx = createLdapContext(usedUrl, 2297 bindDN, pwd, controlInfo.getConnectTimeout(), null); 2298 } 2299 2300 checkCanReadConfig(ctx); 2301 return ctx; 2302 } 2303 2304 /** 2305 * Checks that the provided connection can read cn=config. 2306 * @param ctx the connection to be tested. 2307 * @throws NamingException if an error occurs while reading cn=config. 2308 */ 2309 private static void checkCanReadConfig(InitialLdapContext ctx) 2310 throws NamingException 2311 { 2312 // Search for the config to check that it is the directory manager. 2313 SearchControls searchControls = new SearchControls(); 2314 searchControls.setSearchScope(SearchControls.OBJECT_SCOPE); 2315 searchControls.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); 2316 NamingEnumeration<SearchResult> sr = 2317 ctx.search("cn=config", "objectclass=*", searchControls); 2318 try 2319 { 2320 while (sr.hasMore()) 2321 { 2322 sr.next(); 2323 } 2324 } 2325 finally 2326 { 2327 sr.close(); 2328 } 2329 } 2330 2331 /** 2332 * Ping the specified InitialLdapContext. 2333 * This method sends a search request on the root entry of the DIT 2334 * and forward the corresponding exception (if any). 2335 * @param ctx the InitialLdapContext to be "pinged". 2336 * @throws NamingException if the ping could not be performed. 2337 */ 2338 public static void pingDirContext(InitialLdapContext ctx) 2339 throws NamingException { 2340 SearchControls sc = new SearchControls( 2341 SearchControls.OBJECT_SCOPE, 2342 0, // count limit 2343 0, // time limit 2344 new String[0], // No attributes 2345 false, // Don't return bound object 2346 false // Don't dereference link 2347 ); 2348 ctx.search("", "objectClass=*", sc); 2349 } 2350 2351 /** 2352 * Deletes a configuration subtree using the provided configuration handler. 2353 * @param confHandler the configuration handler to be used to delete the 2354 * subtree. 2355 * @param dn the DN of the subtree to be deleted. 2356 * @throws OpenDsException if an error occurs. 2357 * @throws ConfigException if an error occurs. 2358 */ 2359 public static void deleteConfigSubtree(ConfigHandler confHandler, DN dn) 2360 throws OpenDsException, ConfigException 2361 { 2362 ConfigEntry confEntry = confHandler.getConfigEntry(dn); 2363 if (confEntry != null) 2364 { 2365 // Copy the values to avoid problems with this recursive method. 2366 ArrayList<DN> childDNs = new ArrayList<>(confEntry.getChildren().keySet()); 2367 for (DN childDN : childDNs) 2368 { 2369 deleteConfigSubtree(confHandler, childDN); 2370 } 2371 confHandler.deleteEntry(dn, null); 2372 } 2373 } 2374 2375 2376 /** 2377 * Sets the required icon to the provided label. 2378 * @param label the label to be updated. 2379 */ 2380 public static void setRequiredIcon(JLabel label) 2381 { 2382 if (requiredIcon == null) 2383 { 2384 requiredIcon = 2385 createImageIcon(IconPool.IMAGE_PATH+"/required.gif"); 2386 requiredIcon.setDescription( 2387 INFO_REQUIRED_ICON_ACCESSIBLE_DESCRIPTION.get().toString()); 2388 requiredIcon.getAccessibleContext().setAccessibleName( 2389 INFO_REQUIRED_ICON_ACCESSIBLE_DESCRIPTION.get().toString()); 2390 } 2391 label.setIcon(requiredIcon); 2392 label.setHorizontalTextPosition(SwingConstants.LEADING); 2393 } 2394 2395 2396 /** 2397 * Updates the scrolls with the provided points. 2398 * This method uses SwingUtilities.invokeLater so it can be also called 2399 * outside the event thread. 2400 * @param pos the scroll and points. 2401 */ 2402 public static void updateViewPositions(final ViewPositions pos) 2403 { 2404 SwingUtilities.invokeLater(new Runnable() 2405 { 2406 @Override 2407 public void run() 2408 { 2409 for (int i=0; i<pos.size(); i++) 2410 { 2411 pos.getScrollPane(i).getViewport().setViewPosition(pos.getPoint(i)); 2412 } 2413 } 2414 }); 2415 } 2416 2417 /** 2418 * Gets the view positions object for the provided component. This includes 2419 * all the scroll panes inside the provided component. 2420 * @param comp the component. 2421 * @return the view positions for the provided component. 2422 */ 2423 public static ViewPositions getViewPositions(Component comp) 2424 { 2425 ViewPositions pos = new ViewPositions(); 2426 if (comp instanceof Container) 2427 { 2428 updateContainedViewPositions((Container)comp, pos); 2429 } 2430 return pos; 2431 } 2432 2433 /** 2434 * Returns the scrolpane where the provided component is contained. 2435 * <CODE>null</CODE> if the component is not contained in any scrolpane. 2436 * @param comp the component. 2437 * @return the scrolpane where the provided component is contained. 2438 */ 2439 public static JScrollPane getContainingScroll(Component comp) 2440 { 2441 JScrollPane scroll = null; 2442 Container parent = comp.getParent(); 2443 while (scroll == null && parent != null) 2444 { 2445 if (parent instanceof JScrollPane) 2446 { 2447 scroll = (JScrollPane)parent; 2448 } 2449 else 2450 { 2451 parent = parent.getParent(); 2452 } 2453 } 2454 return scroll; 2455 } 2456 2457 private static void updateContainedViewPositions(Container comp, 2458 ViewPositions pos) 2459 { 2460 if (comp instanceof JScrollPane) 2461 { 2462 JScrollPane scroll = (JScrollPane)comp; 2463 Point p = scroll.getViewport().getViewPosition(); 2464 pos.add(scroll, p); 2465 } 2466 else 2467 { 2468 for (int i=0; i<comp.getComponentCount(); i++) 2469 { 2470 Component child = comp.getComponent(i); 2471 if (child instanceof Container) 2472 { 2473 updateContainedViewPositions((Container)child, pos); 2474 } 2475 } 2476 } 2477 } 2478 2479 private static Object getFirstMonitoringValue(CustomSearchResult sr, String attrName) 2480 { 2481 if (sr != null) 2482 { 2483 List<Object> values = sr.getAttributeValues(attrName); 2484 if (values != null && !values.isEmpty()) 2485 { 2486 Object o = values.iterator().next(); 2487 try 2488 { 2489 return Long.parseLong(o.toString()); 2490 } 2491 catch (Throwable t1) 2492 { 2493 try 2494 { 2495 return Double.parseDouble(o.toString()); 2496 } 2497 catch (Throwable t2) 2498 { 2499 // Cannot convert it, just return it 2500 return o; 2501 } 2502 } 2503 } 2504 } 2505 return null; 2506 } 2507 2508 /** 2509 * Returns the first value as a String for a given attribute in the provided 2510 * entry. 2511 * 2512 * @param sr 2513 * the entry. It may be <CODE>null</CODE>. 2514 * @param attrName 2515 * the attribute name. 2516 * @return the first value as a String for a given attribute in the provided 2517 * entry. 2518 */ 2519 public static String getFirstValueAsString(CustomSearchResult sr, String attrName) 2520 { 2521 if (sr != null) 2522 { 2523 final List<Object> values = sr.getAttributeValues(attrName); 2524 if (values != null && !values.isEmpty()) 2525 { 2526 final Object o = values.get(0); 2527 if (o != null) 2528 { 2529 return String.valueOf(o); 2530 } 2531 } 2532 } 2533 return null; 2534 } 2535 2536 /** 2537 * Returns the monitoring value in a String form to be displayed to the user. 2538 * @param attr the attribute to analyze. 2539 * @param monitoringEntry the monitoring entry. 2540 * @return the monitoring value in a String form to be displayed to the user. 2541 */ 2542 public static String getMonitoringValue(MonitoringAttributes attr, 2543 CustomSearchResult monitoringEntry) 2544 { 2545 String monitoringValue = getFirstValueAsString(monitoringEntry, attr.getAttributeName()); 2546 if (monitoringValue == null) 2547 { 2548 return NO_VALUE_SET.toString(); 2549 } 2550 else if (isNotImplemented(attr, monitoringEntry)) 2551 { 2552 return NOT_IMPLEMENTED.toString(); 2553 } 2554 else if (attr.isNumericDate()) 2555 { 2556 if ("0".equals(monitoringValue)) 2557 { 2558 return NO_VALUE_SET.toString(); 2559 } 2560 Long l = Long.parseLong(monitoringValue); 2561 Date date = new Date(l); 2562 return ConfigFromDirContext.formatter.format(date); 2563 } 2564 else if (attr.isTime()) 2565 { 2566 if ("-1".equals(monitoringValue)) 2567 { 2568 return NO_VALUE_SET.toString(); 2569 } 2570 return monitoringValue; 2571 } 2572 else if (attr.isGMTDate()) 2573 { 2574 try 2575 { 2576 Date date = ConfigFromDirContext.utcParser.parse(monitoringValue); 2577 return ConfigFromDirContext.formatter.format(date); 2578 } 2579 catch (Throwable t) 2580 { 2581 return monitoringValue; 2582 } 2583 } 2584 else if (attr.isValueInBytes()) 2585 { 2586 Long l = Long.parseLong(monitoringValue); 2587 long mb = l / (1024 * 1024); 2588 long kbs = (l - mb * 1024 * 1024) / 1024; 2589 return INFO_CTRL_PANEL_MEMORY_VALUE.get(mb, kbs).toString(); 2590 } 2591 return monitoringValue; 2592 } 2593 2594 /** 2595 * Returns <CODE>true</CODE> if the provided monitoring value represents the 2596 * non implemented label and <CODE>false</CODE> otherwise. 2597 * @param attr the attribute to analyze. 2598 * @param monitoringEntry the monitoring entry. 2599 * @return <CODE>true</CODE> if the provided monitoring value represents the 2600 * non implemented label and <CODE>false</CODE> otherwise. 2601 */ 2602 private static boolean isNotImplemented(MonitoringAttributes attr, 2603 CustomSearchResult monitoringEntry) 2604 { 2605 String monitoringValue = getFirstValueAsString(monitoringEntry, attr.getAttributeName()); 2606 if (attr.isNumeric() && monitoringValue != null) 2607 { 2608 try 2609 { 2610 Long.parseLong(monitoringValue); 2611 return false; 2612 } 2613 catch (Throwable t) 2614 { 2615 return true; 2616 } 2617 } 2618 return false; 2619 } 2620 2621 /** 2622 * Adds a click tool tip listener to the provided component. 2623 * @param comp the component. 2624 */ 2625 public static void addClickTooltipListener(JComponent comp) 2626 { 2627 comp.addMouseListener(new ClickTooltipDisplayer()); 2628 } 2629 2630 /** 2631 * Updates a combo box model with a number of items. 2632 * The method assumes that is being called from the event thread. 2633 * @param newElements the new items for the combo box model. 2634 * @param model the combo box model to be updated. 2635 */ 2636 public static void updateComboBoxModel(Collection<?> newElements, 2637 DefaultComboBoxModel model) 2638 { 2639 updateComboBoxModel(newElements, model, null); 2640 } 2641 2642 /** 2643 * Updates a combo box model with a number of items. 2644 * The method assumes that is being called from the event thread. 2645 * @param newElements the new items for the combo box model. 2646 * @param model the combo box model to be updated. 2647 * @param comparator the object that will be used to compare the objects in 2648 * the model. If <CODE>null</CODE>, the equals method will be used. 2649 */ 2650 public static void updateComboBoxModel(Collection<?> newElements, 2651 DefaultComboBoxModel model, 2652 Comparator<Object> comparator) 2653 { 2654 boolean changed = newElements.size() != model.getSize(); 2655 if (!changed) 2656 { 2657 int i = 0; 2658 for (Object newElement : newElements) 2659 { 2660 if (comparator != null) 2661 { 2662 changed = 2663 comparator.compare(newElement, model.getElementAt(i)) != 0; 2664 } 2665 else 2666 { 2667 changed = !newElement.equals(model.getElementAt(i)); 2668 } 2669 if (changed) 2670 { 2671 break; 2672 } 2673 i++; 2674 } 2675 } 2676 if (changed) 2677 { 2678 Object selected = model.getSelectedItem(); 2679 model.removeAllElements(); 2680 boolean selectDefault = false; 2681 for (Object newElement : newElements) 2682 { 2683 model.addElement(newElement); 2684 } 2685 if (selected != null) 2686 { 2687 if (model.getIndexOf(selected) != -1) 2688 { 2689 model.setSelectedItem(selected); 2690 } 2691 else 2692 { 2693 selectDefault = true; 2694 } 2695 } 2696 else 2697 { 2698 selectDefault = true; 2699 } 2700 if (selectDefault) 2701 { 2702 for (int i=0; i<model.getSize(); i++) 2703 { 2704 Object o = model.getElementAt(i); 2705 if (o instanceof CategorizedComboBoxElement 2706 && ((CategorizedComboBoxElement)o).getType() == CategorizedComboBoxElement.Type.CATEGORY) 2707 { 2708 continue; 2709 } 2710 model.setSelectedItem(o); 2711 break; 2712 } 2713 } 2714 } 2715 } 2716 2717 /** 2718 * Computes the possible comparison results for monitoring information. 2719 * 2720 * @param monitor1 2721 * the first monitor to compare 2722 * @param monitor2 2723 * the second monitor to compare 2724 * @param possibleResults 2725 * where possible results are output 2726 * @param attrNames 2727 * the names for which to compute possible comparison results 2728 */ 2729 public static void computeMonitoringPossibleResults(CustomSearchResult monitor1, CustomSearchResult monitor2, 2730 ArrayList<Integer> possibleResults, Collection<String> attrNames) 2731 { 2732 for (String attrName : attrNames) 2733 { 2734 int possibleResult; 2735 if (monitor1 == null) 2736 { 2737 if (monitor2 == null) 2738 { 2739 possibleResult = 0; 2740 } 2741 else 2742 { 2743 possibleResult = -1; 2744 } 2745 } 2746 else if (monitor2 == null) 2747 { 2748 possibleResult = 1; 2749 } 2750 else 2751 { 2752 Object v1 = getFirstValue(monitor1, attrName); 2753 Object v2 = getFirstValue(monitor2, attrName); 2754 if (v1 == null) 2755 { 2756 if (v2 == null) 2757 { 2758 possibleResult = 0; 2759 } 2760 else 2761 { 2762 possibleResult = -1; 2763 } 2764 } 2765 else if (v2 == null) 2766 { 2767 possibleResult = 1; 2768 } 2769 else if (v1 instanceof Number) 2770 { 2771 if (v2 instanceof Number) 2772 { 2773 if (v1 instanceof Double || v2 instanceof Double) 2774 { 2775 double n1 = ((Number) v1).doubleValue(); 2776 double n2 = ((Number) v2).doubleValue(); 2777 if (n1 > n2) 2778 { 2779 possibleResult = 1; 2780 } 2781 else if (n1 < n2) 2782 { 2783 possibleResult = -1; 2784 } 2785 else 2786 { 2787 possibleResult = 0; 2788 } 2789 } 2790 else 2791 { 2792 long n1 = ((Number) v1).longValue(); 2793 long n2 = ((Number) v2).longValue(); 2794 if (n1 > n2) 2795 { 2796 possibleResult = 1; 2797 } 2798 else if (n1 < n2) 2799 { 2800 possibleResult = -1; 2801 } 2802 else 2803 { 2804 possibleResult = 0; 2805 } 2806 } 2807 } 2808 else 2809 { 2810 possibleResult = 1; 2811 } 2812 } 2813 else if (v2 instanceof Number) 2814 { 2815 possibleResult = -1; 2816 } 2817 else 2818 { 2819 possibleResult = v1.toString().compareTo(v2.toString()); 2820 } 2821 } 2822 possibleResults.add(possibleResult); 2823 } 2824 } 2825 2826 private static Object getFirstValue(CustomSearchResult monitor, String attrName) 2827 { 2828 for (String attr : monitor.getAttributeNames()) 2829 { 2830 if (attr.equalsIgnoreCase(attrName)) 2831 { 2832 return getFirstMonitoringValue(monitor, attrName); 2833 } 2834 } 2835 return null; 2836 } 2837 2838 /** 2839 * Throw the first exception of the list (if any). 2840 * 2841 * @param <E> 2842 * The exception type 2843 * @param exceptions 2844 * A list of exceptions. 2845 * @throws E 2846 * The first element of the provided list (if the list is not 2847 * empty). 2848 */ 2849 public static <E extends Exception> void throwFirstFrom(List<? extends E> exceptions) throws E 2850 { 2851 if (!exceptions.isEmpty()) 2852 { 2853 throw exceptions.get(0); 2854 } 2855 } 2856 2857 /** 2858 * Initialize the configuration framework. 2859 */ 2860 public static void initializeConfigurationFramework() 2861 { 2862 if (!ConfigurationFramework.getInstance().isInitialized()) 2863 { 2864 try 2865 { 2866 ConfigurationFramework.getInstance().initialize(); 2867 } 2868 catch (ConfigException e) 2869 { 2870 final LocalizableMessage message = ERROR_CTRL_PANEL_INITIALIZE_CONFIG_OFFLINE.get(e.getLocalizedMessage()); 2871 logger.error(message); 2872 throw new RuntimeException(message.toString(), e); 2873 } 2874 } 2875 } 2876 2877 /** Initialize the legacy configuration framework. */ 2878 public static void initializeLegacyConfigurationFramework() 2879 { 2880 try 2881 { 2882 final ClassLoaderProvider provider = ClassLoaderProvider.getInstance(); 2883 if (!provider.isEnabled()) 2884 { 2885 provider.enable(); 2886 } 2887 } 2888 catch (Exception e) 2889 { 2890 final LocalizableMessage message = ERROR_CTRL_PANEL_INITIALIZE_CONFIG_OFFLINE.get(e.getLocalizedMessage()); 2891 logger.error(message); 2892 throw new RuntimeException(message.toString(), e); 2893 } 2894 2895 } 2896 2897}