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