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 2007-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.admin.ads; 028 029import static org.opends.admin.ads.util.ConnectionUtils.*; 030import static org.opends.quicksetup.util.Utils.*; 031 032import java.util.ArrayList; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.LinkedHashSet; 036import java.util.List; 037import java.util.Map; 038import java.util.Set; 039 040import javax.naming.NameAlreadyBoundException; 041import javax.naming.NameNotFoundException; 042import javax.naming.NamingEnumeration; 043import javax.naming.NamingException; 044import javax.naming.directory.Attribute; 045import javax.naming.directory.Attributes; 046import javax.naming.directory.BasicAttribute; 047import javax.naming.directory.BasicAttributes; 048import javax.naming.directory.SearchControls; 049import javax.naming.directory.SearchResult; 050import javax.naming.ldap.InitialLdapContext; 051import javax.naming.ldap.LdapName; 052import javax.naming.ldap.Rdn; 053 054import org.forgerock.i18n.LocalizableMessage; 055import org.forgerock.i18n.slf4j.LocalizedLogger; 056import org.opends.admin.ads.util.ConnectionUtils; 057import org.opends.quicksetup.Constants; 058import org.opends.server.config.ConfigConstants; 059import org.opends.server.schema.SchemaConstants; 060 061/** The object of this class represent an OpenDS server. */ 062public class ServerDescriptor 063{ 064 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 065 private static final String TRUSTSTORE_DN = "cn=ads-truststore"; 066 067 private final Map<ADSContext.ServerProperty, Object> adsProperties = new HashMap<>(); 068 private final Set<ReplicaDescriptor> replicas = new HashSet<>(); 069 private final Map<ServerProperty, Object> serverProperties = new HashMap<>(); 070 private TopologyCacheException lastException; 071 072 /** 073 * Enumeration containing the different server properties that we can keep in 074 * the ServerProperty object. 075 */ 076 public enum ServerProperty 077 { 078 /** The associated value is a String. */ 079 HOST_NAME, 080 /** The associated value is an ArrayList of Integer. */ 081 LDAP_PORT, 082 /** The associated value is an ArrayList of Integer. */ 083 LDAPS_PORT, 084 /** The associated value is an Integer. */ 085 ADMIN_PORT, 086 /** The associated value is an ArrayList of Boolean. */ 087 LDAP_ENABLED, 088 /** The associated value is an ArrayList of Boolean. */ 089 LDAPS_ENABLED, 090 /** The associated value is an ArrayList of Boolean. */ 091 ADMIN_ENABLED, 092 /** The associated value is an ArrayList of Boolean. */ 093 STARTTLS_ENABLED, 094 /** The associated value is an ArrayList of Integer. */ 095 JMX_PORT, 096 /** The associated value is an ArrayList of Integer. */ 097 JMXS_PORT, 098 /** The associated value is an ArrayList of Boolean. */ 099 JMX_ENABLED, 100 /** The associated value is an ArrayList of Boolean. */ 101 JMXS_ENABLED, 102 /** The associated value is an Integer. */ 103 REPLICATION_SERVER_PORT, 104 /** The associated value is a Boolean. */ 105 IS_REPLICATION_SERVER, 106 /** The associated value is a Boolean. */ 107 IS_REPLICATION_ENABLED, 108 /** The associated value is a Boolean. */ 109 IS_REPLICATION_SECURE, 110 /** List of servers specified in the Replication Server configuration. This is a Set of String. */ 111 EXTERNAL_REPLICATION_SERVERS, 112 /** The associated value is an Integer. */ 113 REPLICATION_SERVER_ID, 114 /** 115 * The instance key-pair public-key certificate. The associated value is a 116 * byte[] (ds-cfg-public-key-certificate;binary). 117 */ 118 INSTANCE_PUBLIC_KEY_CERTIFICATE, 119 /** The schema generation ID. */ 120 SCHEMA_GENERATION_ID 121 } 122 123 /** Default constructor. */ 124 protected ServerDescriptor() 125 { 126 } 127 128 /** 129 * Returns the replicas contained on the server. 130 * @return the replicas contained on the server. 131 */ 132 public Set<ReplicaDescriptor> getReplicas() 133 { 134 return new HashSet<>(replicas); 135 } 136 137 /** 138 * Sets the replicas contained on the server. 139 * @param replicas the replicas contained on the server. 140 */ 141 public void setReplicas(Set<ReplicaDescriptor> replicas) 142 { 143 this.replicas.clear(); 144 this.replicas.addAll(replicas); 145 } 146 147 /** 148 * Returns a Map containing the ADS properties of the server. 149 * @return a Map containing the ADS properties of the server. 150 */ 151 public Map<ADSContext.ServerProperty, Object> getAdsProperties() 152 { 153 return adsProperties; 154 } 155 156 /** 157 * Returns a Map containing the properties of the server. 158 * @return a Map containing the properties of the server. 159 */ 160 public Map<ServerProperty, Object> getServerProperties() 161 { 162 return serverProperties; 163 } 164 165 /** 166 * Tells whether this server is registered in the ADS or not. 167 * @return <CODE>true</CODE> if the server is registered in the ADS and 168 * <CODE>false</CODE> otherwise. 169 */ 170 public boolean isRegistered() 171 { 172 return !adsProperties.isEmpty(); 173 } 174 175 /** 176 * Tells whether this server is a replication server or not. 177 * @return <CODE>true</CODE> if the server is a replication server and 178 * <CODE>false</CODE> otherwise. 179 */ 180 public boolean isReplicationServer() 181 { 182 return Boolean.TRUE.equals( 183 serverProperties.get(ServerProperty.IS_REPLICATION_SERVER)); 184 } 185 186 /** 187 * Tells whether replication is enabled on this server or not. 188 * @return <CODE>true</CODE> if replication is enabled and 189 * <CODE>false</CODE> otherwise. 190 */ 191 public boolean isReplicationEnabled() 192 { 193 return Boolean.TRUE.equals( 194 serverProperties.get(ServerProperty.IS_REPLICATION_ENABLED)); 195 } 196 197 /** 198 * Returns the String representation of this replication server based 199 * on the information we have ("hostname":"replication port") and 200 * <CODE>null</CODE> if this is not a replication server. 201 * @return the String representation of this replication server based 202 * on the information we have ("hostname":"replication port") and 203 * <CODE>null</CODE> if this is not a replication server. 204 */ 205 public String getReplicationServerHostPort() 206 { 207 if (isReplicationServer()) 208 { 209 return getReplicationServer(getHostName(), getReplicationServerPort()); 210 } 211 return null; 212 } 213 214 /** 215 * Returns the replication server ID of this server and -1 if this is not a 216 * replications server. 217 * @return the replication server ID of this server and -1 if this is not a 218 * replications server. 219 */ 220 public int getReplicationServerId() 221 { 222 if (isReplicationServer()) 223 { 224 return (Integer) serverProperties.get(ServerProperty.REPLICATION_SERVER_ID); 225 } 226 return -1; 227 } 228 229 /** 230 * Returns the replication port of this server and -1 if this is not a 231 * replications server. 232 * @return the replication port of this server and -1 if this is not a 233 * replications server. 234 */ 235 public int getReplicationServerPort() 236 { 237 if (isReplicationServer()) 238 { 239 return (Integer) serverProperties.get( 240 ServerProperty.REPLICATION_SERVER_PORT); 241 } 242 return -1; 243 } 244 245 /** 246 * Returns whether the communication with the replication port on the server 247 * is encrypted or not. 248 * @return <CODE>true</CODE> if the communication with the replication port on 249 * the server is encrypted and <CODE>false</CODE> otherwise. 250 */ 251 public boolean isReplicationSecure() 252 { 253 return isReplicationServer() 254 && Boolean.TRUE.equals(serverProperties.get(ServerProperty.IS_REPLICATION_SECURE)); 255 } 256 257 /** 258 * Sets the ADS properties of the server. 259 * @param adsProperties a Map containing the ADS properties of the server. 260 */ 261 public void setAdsProperties( 262 Map<ADSContext.ServerProperty, Object> adsProperties) 263 { 264 this.adsProperties.clear(); 265 this.adsProperties.putAll(adsProperties); 266 } 267 268 /** 269 * Returns the host name of the server. 270 * @return the host name of the server. 271 */ 272 public String getHostName() 273 { 274 String host = (String)serverProperties.get(ServerProperty.HOST_NAME); 275 if (host != null) 276 { 277 return host; 278 } 279 return (String) adsProperties.get(ADSContext.ServerProperty.HOST_NAME); 280 } 281 282 /** 283 * Returns the URL to access this server using LDAP. Returns 284 * <CODE>null</CODE> if the server is not configured to listen on an LDAP 285 * port. 286 * @return the URL to access this server using LDAP. 287 */ 288 public String getLDAPURL() 289 { 290 return getLDAPUrl0(ServerProperty.LDAP_ENABLED, ServerProperty.LDAP_PORT, false); 291 } 292 293 /** 294 * Returns the URL to access this server using LDAPS. Returns 295 * <CODE>null</CODE> if the server is not configured to listen on an LDAPS 296 * port. 297 * @return the URL to access this server using LDAP. 298 */ 299 public String getLDAPsURL() 300 { 301 return getLDAPUrl0(ServerProperty.LDAPS_ENABLED, ServerProperty.LDAPS_PORT, true); 302 } 303 304 private String getLDAPUrl0(ServerProperty enabledProp, ServerProperty portProp, boolean useSSL) 305 { 306 int port = getPort(enabledProp, portProp); 307 if (port != -1) 308 { 309 String host = getHostName(); 310 return getLDAPUrl(host, port, useSSL); 311 } 312 return null; 313 } 314 315 private int getPort(ServerProperty enabledProp, ServerProperty portProp) 316 { 317 if (!serverProperties.isEmpty()) 318 { 319 return getPort(enabledProp, portProp, -1); 320 } 321 return -1; 322 } 323 324 /** 325 * Returns the URL to access this server using the administration connector. 326 * Returns <CODE>null</CODE> if the server cannot get the administration 327 * connector. 328 * @return the URL to access this server using the administration connector. 329 */ 330 public String getAdminConnectorURL() 331 { 332 return getLDAPUrl0(ServerProperty.ADMIN_ENABLED, ServerProperty.ADMIN_PORT, true); 333 } 334 335 /** 336 * Returns the list of enabled administration ports. 337 * @return the list of enabled administration ports. 338 */ 339 public List<Integer> getEnabledAdministrationPorts() 340 { 341 List<Integer> ports = new ArrayList<>(1); 342 ArrayList<?> s = (ArrayList<?>)serverProperties.get(ServerProperty.ADMIN_ENABLED); 343 ArrayList<?> p = (ArrayList<?>)serverProperties.get(ServerProperty.ADMIN_PORT); 344 if (s != null) 345 { 346 for (int i=0; i<s.size(); i++) 347 { 348 if (Boolean.TRUE.equals(s.get(i))) 349 { 350 ports.add((Integer)p.get(i)); 351 } 352 } 353 } 354 return ports; 355 } 356 357 /** 358 * Returns a String of type host-name:port-number for the server. If 359 * the provided securePreferred is set to true the port that will be used 360 * will be the administration connector port. 361 * @param securePreferred whether to try to use the secure port as part 362 * of the returning String or not. 363 * @return a String of type host-name:port-number for the server. 364 */ 365 public String getHostPort(boolean securePreferred) 366 { 367 int port = -1; 368 369 if (!serverProperties.isEmpty()) 370 { 371 port = getPort(ServerProperty.LDAP_ENABLED, ServerProperty.LDAP_PORT, port); 372 if (securePreferred) 373 { 374 port = getPort(ServerProperty.ADMIN_ENABLED, ServerProperty.ADMIN_PORT, port); 375 } 376 } 377 else 378 { 379 ArrayList<ADSContext.ServerProperty> enabledAttrs = new ArrayList<>(); 380 381 if (securePreferred) 382 { 383 enabledAttrs.add(ADSContext.ServerProperty.ADMIN_ENABLED); 384 enabledAttrs.add(ADSContext.ServerProperty.LDAPS_ENABLED); 385 enabledAttrs.add(ADSContext.ServerProperty.LDAP_ENABLED); 386 } 387 else 388 { 389 enabledAttrs.add(ADSContext.ServerProperty.LDAP_ENABLED); 390 enabledAttrs.add(ADSContext.ServerProperty.ADMIN_ENABLED); 391 enabledAttrs.add(ADSContext.ServerProperty.LDAPS_ENABLED); 392 } 393 394 for (ADSContext.ServerProperty prop : enabledAttrs) 395 { 396 Object v = adsProperties.get(prop); 397 if (v != null && "true".equalsIgnoreCase(String.valueOf(v))) 398 { 399 ADSContext.ServerProperty portProp = getPortProperty(prop); 400 Object p = adsProperties.get(portProp); 401 if (p != null) 402 { 403 try 404 { 405 port = Integer.parseInt(String.valueOf(p)); 406 } 407 catch (Throwable t) 408 { 409 logger.warn(LocalizableMessage.raw("Error calculating host port: "+t+" in "+ 410 adsProperties, t)); 411 } 412 break; 413 } 414 else 415 { 416 logger.warn(LocalizableMessage.raw("Value for "+portProp+" is null in "+ 417 adsProperties)); 418 } 419 } 420 } 421 } 422 423 String host = getHostName(); 424 return host + ":" + port; 425 } 426 427 private ADSContext.ServerProperty getPortProperty(ADSContext.ServerProperty prop) 428 { 429 if (prop == ADSContext.ServerProperty.ADMIN_ENABLED) 430 { 431 return ADSContext.ServerProperty.ADMIN_PORT; 432 } 433 else if (prop == ADSContext.ServerProperty.LDAPS_ENABLED) 434 { 435 return ADSContext.ServerProperty.LDAPS_PORT; 436 } 437 else if (prop == ADSContext.ServerProperty.LDAP_ENABLED) 438 { 439 return ADSContext.ServerProperty.LDAP_PORT; 440 } 441 else 442 { 443 throw new IllegalStateException("Unexpected prop: "+prop); 444 } 445 } 446 447 private int getPort(ServerProperty enabledProp, ServerProperty portProp, int defaultValue) 448 { 449 List<?> s = (List<?>) serverProperties.get(enabledProp); 450 if (s != null) 451 { 452 List<?> p = (List<?>) serverProperties.get(portProp); 453 for (int i=0; i<s.size(); i++) 454 { 455 if (Boolean.TRUE.equals(s.get(i))) 456 { 457 return (Integer) p.get(i); 458 } 459 } 460 } 461 return defaultValue; 462 } 463 464 /** 465 * Returns an Id that is unique for this server. 466 * @return an Id that is unique for this server. 467 */ 468 public String getId() 469 { 470 StringBuilder buf = new StringBuilder(); 471 if (!serverProperties.isEmpty()) 472 { 473 buf.append(serverProperties.get(ServerProperty.HOST_NAME)); 474 ServerProperty [] props = 475 { 476 ServerProperty.LDAP_PORT, ServerProperty.LDAPS_PORT, 477 ServerProperty.ADMIN_PORT, 478 ServerProperty.LDAP_ENABLED, ServerProperty.LDAPS_ENABLED, 479 ServerProperty.ADMIN_ENABLED 480 }; 481 for (ServerProperty prop : props) { 482 ArrayList<?> s = (ArrayList<?>) serverProperties.get(prop); 483 for (Object o : s) { 484 buf.append(":").append(o); 485 } 486 } 487 } 488 else 489 { 490 ADSContext.ServerProperty[] props = 491 { 492 ADSContext.ServerProperty.HOST_NAME, 493 ADSContext.ServerProperty.LDAP_PORT, 494 ADSContext.ServerProperty.LDAPS_PORT, 495 ADSContext.ServerProperty.ADMIN_PORT, 496 ADSContext.ServerProperty.LDAP_ENABLED, 497 ADSContext.ServerProperty.LDAPS_ENABLED, 498 ADSContext.ServerProperty.ADMIN_ENABLED 499 }; 500 for (int i=0; i<props.length; i++) 501 { 502 if (i != 0) 503 { 504 buf.append(":"); 505 } 506 buf.append(adsProperties.get(props[i])); 507 } 508 } 509 return buf.toString(); 510 } 511 512 /** 513 * Returns the instance-key public-key certificate retrieved from the 514 * truststore backend of the instance referenced through this descriptor. 515 * 516 * @return The public-key certificate of the instance. 517 */ 518 public byte[] getInstancePublicKeyCertificate() 519 { 520 return (byte[]) serverProperties.get(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE); 521 } 522 523 /** 524 * Returns the schema generation ID of the server. 525 * @return the schema generation ID of the server. 526 */ 527 public String getSchemaReplicationID() 528 { 529 return (String)serverProperties.get(ServerProperty.SCHEMA_GENERATION_ID); 530 } 531 532 /** 533 * Returns the last exception that was encountered reading the configuration 534 * of the server. Returns null if there was no problem loading the 535 * configuration of the server. 536 * @return the last exception that was encountered reading the configuration 537 * of the server. Returns null if there was no problem loading the 538 * configuration of the server. 539 */ 540 public TopologyCacheException getLastException() 541 { 542 return lastException; 543 } 544 545 /** 546 * Sets the last exception that occurred while reading the configuration of 547 * the server. 548 * @param lastException the last exception that occurred while reading the 549 * configuration of the server. 550 */ 551 public void setLastException(TopologyCacheException lastException) 552 { 553 this.lastException = lastException; 554 } 555 556 /** 557 * This methods updates the ADS properties (the ones that were read from 558 * the ADS) with the contents of the server properties (the ones that were 559 * read directly from the server). 560 */ 561 public void updateAdsPropertiesWithServerProperties() 562 { 563 adsProperties.put(ADSContext.ServerProperty.HOST_NAME, getHostName()); 564 ServerProperty[][] sProps = 565 { 566 {ServerProperty.LDAP_ENABLED, ServerProperty.LDAP_PORT}, 567 {ServerProperty.LDAPS_ENABLED, ServerProperty.LDAPS_PORT}, 568 {ServerProperty.ADMIN_ENABLED, ServerProperty.ADMIN_PORT}, 569 {ServerProperty.JMX_ENABLED, ServerProperty.JMX_PORT}, 570 {ServerProperty.JMXS_ENABLED, ServerProperty.JMXS_PORT} 571 }; 572 ADSContext.ServerProperty[][] adsProps = 573 { 574 {ADSContext.ServerProperty.LDAP_ENABLED, 575 ADSContext.ServerProperty.LDAP_PORT}, 576 {ADSContext.ServerProperty.LDAPS_ENABLED, 577 ADSContext.ServerProperty.LDAPS_PORT}, 578 {ADSContext.ServerProperty.ADMIN_ENABLED, 579 ADSContext.ServerProperty.ADMIN_PORT}, 580 {ADSContext.ServerProperty.JMX_ENABLED, 581 ADSContext.ServerProperty.JMX_PORT}, 582 {ADSContext.ServerProperty.JMXS_ENABLED, 583 ADSContext.ServerProperty.JMXS_PORT} 584 }; 585 586 for (int i=0; i<sProps.length; i++) 587 { 588 ArrayList<?> s = (ArrayList<?>)serverProperties.get(sProps[i][0]); 589 ArrayList<?> p = (ArrayList<?>)serverProperties.get(sProps[i][1]); 590 if (s != null) 591 { 592 int port = getPort(s, p); 593 if (port == -1) 594 { 595 adsProperties.put(adsProps[i][0], "false"); 596 if (!p.isEmpty()) 597 { 598 port = (Integer)p.iterator().next(); 599 } 600 } 601 else 602 { 603 adsProperties.put(adsProps[i][0], "true"); 604 } 605 adsProperties.put(adsProps[i][1], String.valueOf(port)); 606 } 607 } 608 609 ArrayList<?> array = (ArrayList<?>)serverProperties.get( 610 ServerProperty.STARTTLS_ENABLED); 611 boolean startTLSEnabled = false; 612 if (array != null && !array.isEmpty()) 613 { 614 startTLSEnabled = Boolean.TRUE.equals(array.get(array.size() -1)); 615 } 616 adsProperties.put(ADSContext.ServerProperty.STARTTLS_ENABLED, Boolean.toString(startTLSEnabled)); 617 adsProperties.put(ADSContext.ServerProperty.ID, getHostPort(true)); 618 adsProperties.put(ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, 619 getInstancePublicKeyCertificate()); 620 } 621 622 private int getPort(List<?> enabled, List<?> port) 623 { 624 for (int j = 0; j < enabled.size(); j++) 625 { 626 if (Boolean.TRUE.equals(enabled.get(j))) 627 { 628 return (Integer) port.get(j); 629 } 630 } 631 return -1; 632 } 633 634 /** 635 * Creates a ServerDescriptor object based on some ADS properties provided. 636 * @param adsProperties the ADS properties of the server. 637 * @return a ServerDescriptor object that corresponds to the provided ADS 638 * properties. 639 */ 640 public static ServerDescriptor createStandalone( 641 Map<ADSContext.ServerProperty, Object> adsProperties) 642 { 643 ServerDescriptor desc = new ServerDescriptor(); 644 desc.setAdsProperties(adsProperties); 645 return desc; 646 } 647 648 /** 649 * Creates a ServerDescriptor object based on the configuration that we read 650 * using the provided InitialLdapContext. 651 * @param ctx the InitialLdapContext that will be used to read the 652 * configuration of the server. 653 * @param filter the topology cache filter describing the information that 654 * must be retrieved. 655 * @return a ServerDescriptor object that corresponds to the read 656 * configuration. 657 * @throws NamingException if a problem occurred reading the server 658 * configuration. 659 */ 660 public static ServerDescriptor createStandalone(InitialLdapContext ctx, 661 TopologyCacheFilter filter) 662 throws NamingException 663 { 664 ServerDescriptor desc = new ServerDescriptor(); 665 666 updateLdapConfiguration(desc, ctx); 667 updateAdminConnectorConfiguration(desc, ctx); 668 updateJmxConfiguration(desc, ctx); 669 updateReplicas(desc, ctx, filter); 670 updateReplication(desc, ctx, filter); 671 updatePublicKeyCertificate(desc, ctx); 672 updateMiscellaneous(desc, ctx); 673 674 desc.serverProperties.put(ServerProperty.HOST_NAME, 675 ConnectionUtils.getHostName(ctx)); 676 677 return desc; 678 } 679 680 private static void updateLdapConfiguration(ServerDescriptor desc, InitialLdapContext ctx) 681 throws NamingException 682 { 683 SearchControls ctls = new SearchControls(); 684 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 685 ctls.setReturningAttributes( 686 new String[] { 687 "ds-cfg-enabled", 688 "ds-cfg-listen-address", 689 "ds-cfg-listen-port", 690 "ds-cfg-use-ssl", 691 "ds-cfg-allow-start-tls", 692 "objectclass" 693 }); 694 String filter = "(objectclass=ds-cfg-ldap-connection-handler)"; 695 696 LdapName jndiName = new LdapName("cn=config"); 697 NamingEnumeration<SearchResult> listeners = 698 ctx.search(jndiName, filter, ctls); 699 700 try 701 { 702 ArrayList<Integer> ldapPorts = new ArrayList<>(); 703 ArrayList<Integer> ldapsPorts = new ArrayList<>(); 704 ArrayList<Boolean> ldapEnabled = new ArrayList<>(); 705 ArrayList<Boolean> ldapsEnabled = new ArrayList<>(); 706 ArrayList<Boolean> startTLSEnabled = new ArrayList<>(); 707 708 desc.serverProperties.put(ServerProperty.LDAP_PORT, ldapPorts); 709 desc.serverProperties.put(ServerProperty.LDAPS_PORT, ldapsPorts); 710 desc.serverProperties.put(ServerProperty.LDAP_ENABLED, ldapEnabled); 711 desc.serverProperties.put(ServerProperty.LDAPS_ENABLED, ldapsEnabled); 712 desc.serverProperties.put(ServerProperty.STARTTLS_ENABLED, 713 startTLSEnabled); 714 715 while(listeners.hasMore()) 716 { 717 SearchResult sr = listeners.next(); 718 719 String port = getFirstValue(sr, "ds-cfg-listen-port"); 720 721 boolean isSecure = "true".equalsIgnoreCase( 722 getFirstValue(sr, "ds-cfg-use-ssl")); 723 724 boolean enabled = "true".equalsIgnoreCase( 725 getFirstValue(sr, "ds-cfg-enabled")); 726 final Integer portNumber = Integer.valueOf(port); 727 if (isSecure) 728 { 729 ldapsPorts.add(portNumber); 730 ldapsEnabled.add(enabled); 731 } 732 else 733 { 734 ldapPorts.add(portNumber); 735 ldapEnabled.add(enabled); 736 enabled = "true".equalsIgnoreCase( 737 getFirstValue(sr, "ds-cfg-allow-start-tls")); 738 startTLSEnabled.add(enabled); 739 } 740 } 741 } 742 finally 743 { 744 listeners.close(); 745 } 746 } 747 748 private static void updateAdminConnectorConfiguration(ServerDescriptor desc, InitialLdapContext ctx) 749 throws NamingException 750 { 751 SearchControls ctls = new SearchControls(); 752 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 753 ctls.setReturningAttributes( 754 new String[] { 755 "ds-cfg-listen-port", 756 "objectclass" 757 }); 758 String filter = "(objectclass=ds-cfg-administration-connector)"; 759 760 LdapName jndiName = new LdapName("cn=config"); 761 NamingEnumeration<SearchResult> listeners = 762 ctx.search(jndiName, filter, ctls); 763 764 try 765 { 766 Integer adminConnectorPort = null; 767 768 // we should have a single administration connector 769 while (listeners.hasMore()) { 770 SearchResult sr = listeners.next(); 771 String port = getFirstValue(sr, "ds-cfg-listen-port"); 772 adminConnectorPort = Integer.valueOf(port); 773 } 774 775 // Even if we have a single port, use an array to be consistent with 776 // other protocols. 777 ArrayList<Integer> adminPorts = new ArrayList<>(); 778 ArrayList<Boolean> adminEnabled = new ArrayList<>(); 779 if (adminConnectorPort != null) 780 { 781 adminPorts.add(adminConnectorPort); 782 adminEnabled.add(Boolean.TRUE); 783 } 784 desc.serverProperties.put(ServerProperty.ADMIN_PORT, adminPorts); 785 desc.serverProperties.put(ServerProperty.ADMIN_ENABLED, adminEnabled); 786 } 787 finally 788 { 789 listeners.close(); 790 } 791 } 792 793 private static void updateJmxConfiguration(ServerDescriptor desc, InitialLdapContext ctx) throws NamingException 794 { 795 SearchControls ctls = new SearchControls(); 796 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 797 ctls.setReturningAttributes( 798 new String[] { 799 "ds-cfg-enabled", 800 "ds-cfg-listen-address", 801 "ds-cfg-listen-port", 802 "ds-cfg-use-ssl", 803 "objectclass" 804 }); 805 String filter = "(objectclass=ds-cfg-jmx-connection-handler)"; 806 807 LdapName jndiName = new LdapName("cn=config"); 808 NamingEnumeration<SearchResult> listeners = 809 ctx.search(jndiName, filter, ctls); 810 811 ArrayList<Integer> jmxPorts = new ArrayList<>(); 812 ArrayList<Integer> jmxsPorts = new ArrayList<>(); 813 ArrayList<Boolean> jmxEnabled = new ArrayList<>(); 814 ArrayList<Boolean> jmxsEnabled = new ArrayList<>(); 815 816 desc.serverProperties.put(ServerProperty.JMX_PORT, jmxPorts); 817 desc.serverProperties.put(ServerProperty.JMXS_PORT, jmxsPorts); 818 desc.serverProperties.put(ServerProperty.JMX_ENABLED, jmxEnabled); 819 desc.serverProperties.put(ServerProperty.JMXS_ENABLED, jmxsEnabled); 820 821 try 822 { 823 while(listeners.hasMore()) 824 { 825 SearchResult sr = listeners.next(); 826 827 String port = getFirstValue(sr, "ds-cfg-listen-port"); 828 829 boolean isSecure = "true".equalsIgnoreCase( 830 getFirstValue(sr, "ds-cfg-use-ssl")); 831 832 boolean enabled = "true".equalsIgnoreCase( 833 getFirstValue(sr, "ds-cfg-enabled")); 834 Integer portNumber = Integer.valueOf(port); 835 if (isSecure) 836 { 837 jmxsPorts.add(portNumber); 838 jmxsEnabled.add(enabled); 839 } 840 else 841 { 842 jmxPorts.add(portNumber); 843 jmxEnabled.add(enabled); 844 } 845 } 846 } 847 finally 848 { 849 listeners.close(); 850 } 851 } 852 853 private static void updateReplicas(ServerDescriptor desc, 854 InitialLdapContext ctx, TopologyCacheFilter cacheFilter) 855 throws NamingException 856 { 857 if (!cacheFilter.searchBaseDNInformation()) 858 { 859 return; 860 } 861 SearchControls ctls = new SearchControls(); 862 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 863 ctls.setReturningAttributes( 864 new String[] { 865 "ds-cfg-base-dn", 866 "ds-cfg-backend-id", 867 ConfigConstants.ATTR_OBJECTCLASS 868 }); 869 String filter = "(objectclass=ds-cfg-backend)"; 870 871 LdapName jndiName = new LdapName("cn=config"); 872 NamingEnumeration<SearchResult> databases = 873 ctx.search(jndiName, filter, ctls); 874 875 try 876 { 877 while(databases.hasMore()) 878 { 879 SearchResult sr = databases.next(); 880 881 String id = getFirstValue(sr, "ds-cfg-backend-id"); 882 883 if (!isConfigBackend(id) || isSchemaBackend(id)) 884 { 885 Set<String> baseDns = getValues(sr, "ds-cfg-base-dn"); 886 887 Set<String> entries; 888 if (cacheFilter.searchMonitoringInformation()) 889 { 890 entries = getBaseDNEntryCount(ctx, id); 891 } 892 else 893 { 894 entries = new HashSet<>(); 895 } 896 897 Set<ReplicaDescriptor> replicas = desc.getReplicas(); 898 for (String baseDn : baseDns) 899 { 900 if (isAddReplica(cacheFilter, baseDn)) 901 { 902 SuffixDescriptor suffix = new SuffixDescriptor(); 903 suffix.setDN(baseDn); 904 ReplicaDescriptor replica = new ReplicaDescriptor(); 905 replica.setServer(desc); 906 replica.setObjectClasses(getValues(sr, ConfigConstants.ATTR_OBJECTCLASS)); 907 replica.setBackendName(id); 908 replicas.add(replica); 909 HashSet<ReplicaDescriptor> r = new HashSet<>(); 910 r.add(replica); 911 suffix.setReplicas(r); 912 replica.setSuffix(suffix); 913 int nEntries = -1; 914 for (String s : entries) 915 { 916 int index = s.indexOf(" "); 917 if (index != -1) 918 { 919 String dn = s.substring(index + 1); 920 if (areDnsEqual(baseDn, dn)) 921 { 922 try 923 { 924 nEntries = Integer.parseInt(s.substring(0, index)); 925 } 926 catch (Throwable t) 927 { 928 /* Ignore */ 929 } 930 break; 931 } 932 } 933 } 934 replica.setEntries(nEntries); 935 } 936 } 937 desc.setReplicas(replicas); 938 } 939 } 940 } 941 finally 942 { 943 databases.close(); 944 } 945 } 946 947 private static boolean isAddReplica(TopologyCacheFilter cacheFilter, String baseDn) 948 { 949 if (cacheFilter.searchAllBaseDNs()) 950 { 951 return true; 952 } 953 954 for (String dn : cacheFilter.getBaseDNsToSearch()) 955 { 956 if (areDnsEqual(dn, baseDn)) 957 { 958 return true; 959 } 960 } 961 return false; 962 } 963 964 private static void updateReplication(ServerDescriptor desc, 965 InitialLdapContext ctx, TopologyCacheFilter cacheFilter) 966 throws NamingException 967 { 968 boolean replicationEnabled = false; 969 SearchControls ctls = new SearchControls(); 970 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 971 ctls.setReturningAttributes( 972 new String[] { 973 "ds-cfg-enabled" 974 }); 975 String filter = "(objectclass=ds-cfg-synchronization-provider)"; 976 977 LdapName jndiName = new LdapName( 978 "cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config"); 979 NamingEnumeration<SearchResult> syncProviders = null; 980 981 try 982 { 983 syncProviders = ctx.search(jndiName, filter, ctls); 984 985 while(syncProviders.hasMore()) 986 { 987 SearchResult sr = syncProviders.next(); 988 989 if ("true".equalsIgnoreCase(getFirstValue(sr, 990 "ds-cfg-enabled"))) 991 { 992 replicationEnabled = true; 993 } 994 } 995 } 996 catch (NameNotFoundException nse) 997 { 998 /* ignore */ 999 } 1000 finally 1001 { 1002 if (syncProviders != null) 1003 { 1004 syncProviders.close(); 1005 } 1006 } 1007 desc.serverProperties.put(ServerProperty.IS_REPLICATION_ENABLED, 1008 Boolean.valueOf(replicationEnabled)); 1009 1010 Set<String> allReplicationServers = new LinkedHashSet<>(); 1011 1012 if (cacheFilter.searchBaseDNInformation()) 1013 { 1014 ctls = new SearchControls(); 1015 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 1016 ctls.setReturningAttributes( 1017 new String[] { 1018 "ds-cfg-base-dn", 1019 "ds-cfg-replication-server", 1020 "ds-cfg-server-id" 1021 }); 1022 filter = "(objectclass=ds-cfg-replication-domain)"; 1023 1024 jndiName = new LdapName( 1025 "cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config"); 1026 1027 syncProviders = null; 1028 try 1029 { 1030 syncProviders = ctx.search(jndiName, filter, ctls); 1031 1032 while(syncProviders.hasMore()) 1033 { 1034 SearchResult sr = syncProviders.next(); 1035 1036 int id = Integer.parseInt( 1037 getFirstValue(sr, "ds-cfg-server-id")); 1038 Set<String> replicationServers = getValues(sr, 1039 "ds-cfg-replication-server"); 1040 Set<String> dns = getValues(sr, "ds-cfg-base-dn"); 1041 for (String dn : dns) 1042 { 1043 for (ReplicaDescriptor replica : desc.getReplicas()) 1044 { 1045 if (areDnsEqual(replica.getSuffix().getDN(), dn)) 1046 { 1047 replica.setReplicationId(id); 1048 // Keep the values of the replication servers in lower case 1049 // to make use of Sets as String simpler. 1050 LinkedHashSet<String> repServers = new LinkedHashSet<>(); 1051 for (String s: replicationServers) 1052 { 1053 repServers.add(s.toLowerCase()); 1054 } 1055 replica.setReplicationServers(repServers); 1056 allReplicationServers.addAll(repServers); 1057 } 1058 } 1059 } 1060 } 1061 } 1062 catch (NameNotFoundException nse) 1063 { 1064 /* ignore */ 1065 } 1066 finally 1067 { 1068 if (syncProviders != null) 1069 { 1070 syncProviders.close(); 1071 } 1072 } 1073 } 1074 1075 ctls = new SearchControls(); 1076 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 1077 ctls.setReturningAttributes( 1078 new String[] { 1079 "ds-cfg-replication-port", "ds-cfg-replication-server", 1080 "ds-cfg-replication-server-id" 1081 }); 1082 filter = "(objectclass=ds-cfg-replication-server)"; 1083 1084 jndiName = new LdapName("cn=Multimaster "+ 1085 "Synchronization,cn=Synchronization Providers,cn=config"); 1086 1087 desc.serverProperties.put(ServerProperty.IS_REPLICATION_SERVER, 1088 Boolean.FALSE); 1089 NamingEnumeration<SearchResult> entries = null; 1090 try 1091 { 1092 entries = ctx.search(jndiName, filter, ctls); 1093 1094 while (entries.hasMore()) 1095 { 1096 SearchResult sr = entries.next(); 1097 1098 desc.serverProperties.put(ServerProperty.IS_REPLICATION_SERVER, 1099 Boolean.TRUE); 1100 String v = getFirstValue(sr, "ds-cfg-replication-port"); 1101 desc.serverProperties.put(ServerProperty.REPLICATION_SERVER_PORT, 1102 Integer.parseInt(v)); 1103 v = getFirstValue(sr, "ds-cfg-replication-server-id"); 1104 desc.serverProperties.put(ServerProperty.REPLICATION_SERVER_ID, 1105 Integer.parseInt(v)); 1106 Set<String> values = getValues(sr, "ds-cfg-replication-server"); 1107 // Keep the values of the replication servers in lower case 1108 // to make use of Sets as String simpler. 1109 LinkedHashSet<String> repServers = new LinkedHashSet<>(); 1110 for (String s: values) 1111 { 1112 repServers.add(s.toLowerCase()); 1113 } 1114 allReplicationServers.addAll(repServers); 1115 desc.serverProperties.put(ServerProperty.EXTERNAL_REPLICATION_SERVERS, 1116 allReplicationServers); 1117 } 1118 } 1119 catch (NameNotFoundException nse) 1120 { 1121 /* ignore */ 1122 } 1123 finally 1124 { 1125 if (entries != null) 1126 { 1127 entries.close(); 1128 } 1129 } 1130 1131 boolean replicationSecure = false; 1132 if (replicationEnabled) 1133 { 1134 ctls = new SearchControls(); 1135 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 1136 ctls.setReturningAttributes( 1137 new String[] {"ds-cfg-ssl-encryption"}); 1138 filter = "(objectclass=ds-cfg-crypto-manager)"; 1139 1140 jndiName = new LdapName("cn=Crypto Manager,cn=config"); 1141 1142 entries = ctx.search(jndiName, filter, ctls); 1143 1144 try 1145 { 1146 while (entries.hasMore()) 1147 { 1148 SearchResult sr = entries.next(); 1149 1150 String v = getFirstValue(sr, "ds-cfg-ssl-encryption"); 1151 replicationSecure = "true".equalsIgnoreCase(v); 1152 } 1153 } 1154 finally 1155 { 1156 entries.close(); 1157 } 1158 } 1159 desc.serverProperties.put(ServerProperty.IS_REPLICATION_SECURE, 1160 Boolean.valueOf(replicationSecure)); 1161 } 1162 1163 /** 1164 Updates the instance key public-key certificate value of this context from 1165 the local truststore of the instance bound by this context. Any current 1166 value of the certificate is overwritten. The intent of this method is to 1167 retrieve the instance-key public-key certificate when this context is bound 1168 to an instance, and cache it for later use in registering the instance into 1169 ADS. 1170 @param desc The map to update with the instance key-pair public-key 1171 certificate. 1172 @param ctx The bound server instance. 1173 @throws NamingException if unable to retrieve certificate from bound 1174 instance. 1175 */ 1176 private static void updatePublicKeyCertificate(ServerDescriptor desc, InitialLdapContext ctx) throws NamingException 1177 { 1178 /* TODO: this DN is declared in some core constants file. Create a constants 1179 file for the installer and import it into the core. */ 1180 final String dnStr = "ds-cfg-key-id=ads-certificate,cn=ads-truststore"; 1181 final LdapName dn = new LdapName(dnStr); 1182 for (int i = 0; i < 2 ; ++i) { 1183 /* If the entry does not exist in the instance's truststore backend, add 1184 it (which induces the CryptoManager to create the public-key 1185 certificate attribute), then repeat the search. */ 1186 try { 1187 final SearchControls searchControls = new SearchControls(); 1188 searchControls.setSearchScope(SearchControls.OBJECT_SCOPE); 1189 final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" }; 1190 searchControls.setReturningAttributes(attrIDs); 1191 final SearchResult certEntry = ctx.search(dn, 1192 "(objectclass=ds-cfg-instance-key)", searchControls).next(); 1193 final Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]); 1194 if (null != certAttr) { 1195 /* attribute ds-cfg-public-key-certificate is a MUST in the schema */ 1196 desc.serverProperties.put( 1197 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, 1198 certAttr.get()); 1199 } 1200 break; 1201 } 1202 catch (NameNotFoundException x) { 1203 if (0 == i) { 1204 // Poke CryptoManager to initialize truststore. Note the special attribute in the request. 1205 final Attributes attrs = new BasicAttributes(); 1206 final Attribute oc = new BasicAttribute("objectclass"); 1207 oc.add("top"); 1208 oc.add("ds-cfg-self-signed-cert-request"); 1209 attrs.put(oc); 1210 ctx.createSubcontext(dn, attrs).close(); 1211 } 1212 else { 1213 throw x; 1214 } 1215 } 1216 } 1217 } 1218 1219 private static void updateMiscellaneous(ServerDescriptor desc, InitialLdapContext ctx) throws NamingException 1220 { 1221 SearchControls ctls = new SearchControls(); 1222 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 1223 ctls.setReturningAttributes( 1224 new String[] { 1225 "ds-sync-generation-id" 1226 }); 1227 String filter = "(|(objectclass=*)(objectclass=ldapsubentry))"; 1228 1229 LdapName jndiName = new LdapName("cn=schema"); 1230 NamingEnumeration<SearchResult> listeners = 1231 ctx.search(jndiName, filter, ctls); 1232 1233 try 1234 { 1235 while(listeners.hasMore()) 1236 { 1237 SearchResult sr = listeners.next(); 1238 1239 desc.serverProperties.put(ServerProperty.SCHEMA_GENERATION_ID, 1240 getFirstValue(sr, "ds-sync-generation-id")); 1241 } 1242 } 1243 finally 1244 { 1245 listeners.close(); 1246 } 1247 } 1248 1249 /** 1250 Seeds the bound instance's local ads-truststore with a set of instance 1251 key-pair public key certificates. The result is the instance will trust any 1252 instance possessing the private key corresponding to one of the public-key 1253 certificates. This trust is necessary at least to initialize replication, 1254 which uses the trusted certificate entries in the ads-truststore for server 1255 authentication. 1256 @param ctx The bound instance. 1257 @param keyEntryMap The set of valid (i.e., not tagged as compromised) 1258 instance key-pair public-key certificate entries in ADS represented as a map 1259 from keyID to public-key certificate (binary). 1260 @throws NamingException in case an error occurs while updating the instance's 1261 ads-truststore via LDAP. 1262 */ 1263 public static void seedAdsTrustStore( 1264 InitialLdapContext ctx, 1265 Map<String, byte[]> keyEntryMap) 1266 throws NamingException 1267 { 1268 /* TODO: this DN is declared in some core constants file. Create a 1269 constants file for the installer and import it into the core. */ 1270 final Attribute oc = new BasicAttribute("objectclass"); 1271 oc.add("top"); 1272 oc.add("ds-cfg-instance-key"); 1273 for (Map.Entry<String, byte[]> keyEntry : keyEntryMap.entrySet()){ 1274 final BasicAttributes keyAttrs = new BasicAttributes(); 1275 keyAttrs.put(oc); 1276 final Attribute rdnAttr = new BasicAttribute( 1277 ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(), 1278 keyEntry.getKey()); 1279 keyAttrs.put(rdnAttr); 1280 keyAttrs.put(new BasicAttribute( 1281 ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE. 1282 getAttributeName() + ";binary", keyEntry.getValue())); 1283 final LdapName keyDn = new LdapName(rdnAttr.getID() + "=" + Rdn.escapeValue(rdnAttr.get()) + "," + TRUSTSTORE_DN); 1284 try { 1285 ctx.createSubcontext(keyDn, keyAttrs).close(); 1286 } 1287 catch(NameAlreadyBoundException x){ 1288 ctx.destroySubcontext(keyDn); 1289 ctx.createSubcontext(keyDn, keyAttrs).close(); 1290 } 1291 } 1292 } 1293 1294 /** 1295 * Cleans up the contents of the ads truststore. 1296 * 1297 * @param ctx the bound instance. 1298 * @throws NamingException in case an error occurs while updating the 1299 * instance's ads-truststore via LDAP. 1300 */ 1301 public static void cleanAdsTrustStore(InitialLdapContext ctx) 1302 throws NamingException 1303 { 1304 try 1305 { 1306 SearchControls sc = new SearchControls(); 1307 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 1308 sc.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); 1309 NamingEnumeration<SearchResult> ne = ctx.search(TRUSTSTORE_DN, 1310 "(objectclass=ds-cfg-instance-key)", sc); 1311 ArrayList<String> dnsToDelete = new ArrayList<>(); 1312 try 1313 { 1314 while (ne.hasMore()) 1315 { 1316 SearchResult sr = ne.next(); 1317 dnsToDelete.add(sr.getName()+","+TRUSTSTORE_DN); 1318 } 1319 } 1320 finally 1321 { 1322 ne.close(); 1323 } 1324 for (String dn : dnsToDelete) 1325 { 1326 ctx.destroySubcontext(dn); 1327 } 1328 } 1329 catch (NameNotFoundException nnfe) 1330 { 1331 // Ignore 1332 logger.warn(LocalizableMessage.raw("Error cleaning truststore: "+nnfe, nnfe)); 1333 } 1334 } 1335 1336 /** 1337 * Returns the values of the ds-base-dn-entry count attributes for the given 1338 * backend monitor entry using the provided InitialLdapContext. 1339 * @param ctx the InitialLdapContext to use to update the configuration. 1340 * @param backendID the id of the backend. 1341 * @return the values of the ds-base-dn-entry count attribute. 1342 * @throws NamingException if there was an error. 1343 */ 1344 private static Set<String> getBaseDNEntryCount(InitialLdapContext ctx, 1345 String backendID) throws NamingException 1346 { 1347 LinkedHashSet<String> v = new LinkedHashSet<>(); 1348 SearchControls ctls = new SearchControls(); 1349 ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE); 1350 ctls.setReturningAttributes( 1351 new String[] { 1352 "ds-base-dn-entry-count" 1353 }); 1354 String filter = "(ds-backend-id="+backendID+")"; 1355 1356 LdapName jndiName = new LdapName("cn=monitor"); 1357 NamingEnumeration<SearchResult> listeners = 1358 ctx.search(jndiName, filter, ctls); 1359 1360 try 1361 { 1362 while(listeners.hasMore()) 1363 { 1364 SearchResult sr = listeners.next(); 1365 1366 v.addAll(getValues(sr, "ds-base-dn-entry-count")); 1367 } 1368 } 1369 finally 1370 { 1371 listeners.close(); 1372 } 1373 return v; 1374 } 1375 1376 /** 1377 * An convenience method to know if the provided ID corresponds to a 1378 * configuration backend or not. 1379 * @param id the backend ID to analyze 1380 * @return <CODE>true</CODE> if the the id corresponds to a configuration 1381 * backend and <CODE>false</CODE> otherwise. 1382 */ 1383 private static boolean isConfigBackend(String id) 1384 { 1385 return "tasks".equalsIgnoreCase(id) || 1386 "schema".equalsIgnoreCase(id) || 1387 "config".equalsIgnoreCase(id) || 1388 "monitor".equalsIgnoreCase(id) || 1389 "backup".equalsIgnoreCase(id) || 1390 "ads-truststore".equalsIgnoreCase(id); 1391 } 1392 1393 /** 1394 * An convenience method to know if the provided ID corresponds to the schema 1395 * backend or not. 1396 * @param id the backend ID to analyze 1397 * @return <CODE>true</CODE> if the the id corresponds to the schema backend 1398 * and <CODE>false</CODE> otherwise. 1399 */ 1400 private static boolean isSchemaBackend(String id) 1401 { 1402 return "schema".equalsIgnoreCase(id); 1403 } 1404 1405 /** 1406 * Returns the replication server normalized String for a given host name 1407 * and replication port. 1408 * @param hostName the host name. 1409 * @param replicationPort the replication port. 1410 * @return the replication server normalized String for a given host name 1411 * and replication port. 1412 */ 1413 public static String getReplicationServer(String hostName, int replicationPort) 1414 { 1415 return getServerRepresentation(hostName, replicationPort); 1416 } 1417 1418 /** 1419 * Returns the normalized server representation for a given host name and 1420 * port. 1421 * @param hostName the host name. 1422 * @param port the port. 1423 * @return the normalized server representation for a given host name and 1424 * port. 1425 */ 1426 public static String getServerRepresentation(String hostName, int port) 1427 { 1428 return hostName.toLowerCase() + ":" + port; 1429 } 1430 1431 /** 1432 * Returns a representation of a base DN for a set of servers. 1433 * @param baseDN the base DN. 1434 * @param servers the servers. 1435 * @return a representation of a base DN for a set of servers. 1436 */ 1437 public static String getSuffixDisplay(String baseDN, 1438 Set<ServerDescriptor> servers) 1439 { 1440 StringBuilder sb = new StringBuilder(); 1441 sb.append(baseDN); 1442 for (ServerDescriptor server : servers) 1443 { 1444 sb.append(Constants.LINE_SEPARATOR).append(" "); 1445 sb.append(server.getHostPort(true)); 1446 } 1447 return sb.toString(); 1448 } 1449 1450 /** 1451 * Tells whether the provided server descriptor represents the same server 1452 * as this object. 1453 * @param server the server to make the comparison. 1454 * @return whether the provided server descriptor represents the same server 1455 * as this object or not. 1456 */ 1457 public boolean isSameServer(ServerDescriptor server) 1458 { 1459 return getId().equals(server.getId()); 1460 } 1461}