001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.guitools.controlpanel.datamodel; 018 019import static org.opends.admin.ads.util.ConnectionUtils.*; 020import static org.opends.admin.ads.util.PreferredConnection.Type.*; 021import static org.opends.guitools.controlpanel.util.Utilities.*; 022import static org.opends.server.tools.ConfigureWindowsService.*; 023import static com.forgerock.opendj.cli.Utils.*; 024import static com.forgerock.opendj.util.OperatingSystem.*; 025 026import java.io.File; 027import java.net.InetAddress; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.HashSet; 031import java.util.LinkedHashSet; 032import java.util.Objects; 033import java.util.Set; 034import java.util.SortedSet; 035 036import javax.naming.NamingException; 037import javax.naming.ldap.InitialLdapContext; 038 039import org.forgerock.i18n.LocalizableMessage; 040import org.forgerock.i18n.slf4j.LocalizedLogger; 041import org.forgerock.opendj.config.ConfigurationFramework; 042import org.forgerock.opendj.config.server.ConfigException; 043import org.opends.admin.ads.util.ApplicationTrustManager; 044import org.opends.admin.ads.util.ConnectionUtils; 045import org.opends.admin.ads.util.ConnectionWrapper; 046import org.opends.guitools.controlpanel.browser.IconPool; 047import org.opends.guitools.controlpanel.browser.LDAPConnectionPool; 048import org.opends.guitools.controlpanel.datamodel.ServerDescriptor.ServerStatus; 049import org.opends.guitools.controlpanel.event.BackendPopulatedEvent; 050import org.opends.guitools.controlpanel.event.BackendPopulatedListener; 051import org.opends.guitools.controlpanel.event.BackupCreatedEvent; 052import org.opends.guitools.controlpanel.event.BackupCreatedListener; 053import org.opends.guitools.controlpanel.event.ConfigChangeListener; 054import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 055import org.opends.guitools.controlpanel.event.IndexModifiedEvent; 056import org.opends.guitools.controlpanel.event.IndexModifiedListener; 057import org.opends.guitools.controlpanel.task.Task; 058import org.opends.guitools.controlpanel.task.Task.State; 059import org.opends.guitools.controlpanel.task.Task.Type; 060import org.opends.guitools.controlpanel.util.ConfigFromDirContext; 061import org.opends.guitools.controlpanel.util.ConfigFromFile; 062import org.opends.guitools.controlpanel.util.ConfigReader; 063import org.opends.guitools.controlpanel.util.Utilities; 064import org.opends.quicksetup.util.UIKeyStore; 065import org.opends.quicksetup.util.Utils; 066import org.opends.server.util.DynamicConstants; 067import org.opends.server.util.StaticUtils; 068 069import com.forgerock.opendj.cli.CliConstants; 070 071/** 072 * This is the classes that is shared among all the different places in the 073 * Control Panel. It contains information about the server status and 074 * configuration and some objects that are shared everywhere. 075 */ 076public class ControlPanelInfo 077{ 078 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 079 080 private static boolean mustDeregisterConfig; 081 private static ControlPanelInfo instance; 082 083 private final Set<Task> tasks = new HashSet<>(); 084 private ConnectionWrapper connWrapper; 085 private InitialLdapContext userDataCtx; 086 private final LDAPConnectionPool connectionPool = new LDAPConnectionPool(); 087 /** Used by the browsers. */ 088 private final IconPool iconPool = new IconPool(); 089 090 private long poolingPeriod = 20000; 091 private Thread poolingThread; 092 private boolean stopPooling; 093 private boolean pooling; 094 095 private ApplicationTrustManager trustManager; 096 private int connectTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT; 097 private ConnectionProtocolPolicy connectionPolicy = 098 ConnectionProtocolPolicy.USE_MOST_SECURE_AVAILABLE; 099 100 private ServerDescriptor serverDesc; 101 private String ldapURL; 102 private String startTLSURL; 103 private String ldapsURL; 104 private String adminConnectorURL; 105 private String localAdminConnectorURL; 106 private String lastWorkingBindDN; 107 private String lastWorkingBindPwd; 108 private String lastRemoteHostName; 109 private String lastRemoteAdministrationURL; 110 111 private boolean isLocal = true; 112 113 private final Set<AbstractIndexDescriptor> modifiedIndexes = new HashSet<>(); 114 private final Set<ConfigChangeListener> configListeners = new LinkedHashSet<>(); 115 private final Set<BackupCreatedListener> backupListeners = new LinkedHashSet<>(); 116 private final Set<BackendPopulatedListener> backendPopulatedListeners = new LinkedHashSet<>(); 117 private final Set<IndexModifiedListener> indexListeners = new LinkedHashSet<>(); 118 119 /** Default constructor. */ 120 private ControlPanelInfo() 121 { 122 } 123 124 /** 125 * Returns a singleton for this instance. 126 * @return the control panel info. 127 */ 128 public static ControlPanelInfo getInstance() 129 { 130 if (instance == null) 131 { 132 instance = new ControlPanelInfo(); 133 try 134 { 135 instance.setTrustManager( 136 new ApplicationTrustManager(UIKeyStore.getInstance())); 137 } 138 catch (Throwable t) 139 { 140 logger.warn(LocalizableMessage.raw("Error retrieving UI key store: "+t, t)); 141 instance.setTrustManager(new ApplicationTrustManager(null)); 142 } 143 } 144 return instance; 145 } 146 147 /** 148 * Returns the last ServerDescriptor that has been retrieved. 149 * @return the last ServerDescriptor that has been retrieved. 150 */ 151 public ServerDescriptor getServerDescriptor() 152 { 153 return serverDesc; 154 } 155 156 /** 157 * Returns the list of tasks. 158 * @return the list of tasks. 159 */ 160 public Set<Task> getTasks() 161 { 162 return Collections.unmodifiableSet(tasks); 163 } 164 165 /** 166 * Registers a task. The Control Panel creates a task every time an operation 167 * is made and they are stored here. 168 * @param task the task to be registered. 169 */ 170 public void registerTask(Task task) 171 { 172 tasks.add(task); 173 } 174 175 /** 176 * Unregisters a task. 177 * @param task the task to be unregistered. 178 */ 179 private void unregisterTask(Task task) 180 { 181 tasks.remove(task); 182 } 183 184 /** 185 * Tells whether an index must be reindexed or not. 186 * @param index the index. 187 * @return <CODE>true</CODE> if the index must be reindexed and 188 * <CODE>false</CODE> otherwise. 189 */ 190 public boolean mustReindex(AbstractIndexDescriptor index) 191 { 192 boolean mustReindex = false; 193 for (AbstractIndexDescriptor i : modifiedIndexes) 194 { 195 if (i.getName().equals(index.getName()) && 196 i.getBackend().getBackendID().equals( 197 index.getBackend().getBackendID())) 198 { 199 mustReindex = true; 200 break; 201 } 202 } 203 return mustReindex; 204 } 205 206 /** 207 * Registers an index as modified. This is used by the panels to be able 208 * to inform the user that a rebuild of the index is required. 209 * @param index the index. 210 */ 211 public void registerModifiedIndex(AbstractIndexDescriptor index) 212 { 213 modifiedIndexes.add(index); 214 indexModified(index); 215 } 216 217 /** 218 * Unregisters a modified index. 219 * @param index the index. 220 * @return <CODE>true</CODE> if the index is found in the list of modified 221 * indexes and <CODE>false</CODE> otherwise. 222 */ 223 public boolean unregisterModifiedIndex(AbstractIndexDescriptor index) 224 { 225 // We might have stored indexes whose configuration has changed, just remove 226 // them if they have the same name, are of the same type and are defined in 227 // the same backend. 228 Set<AbstractIndexDescriptor> toRemove = new HashSet<>(); 229 for (AbstractIndexDescriptor i : modifiedIndexes) 230 { 231 if (i.getName().equalsIgnoreCase(index.getName()) && 232 i.getBackend().getBackendID().equalsIgnoreCase( 233 index.getBackend().getBackendID()) && 234 i.getClass().equals(index.getClass())) 235 { 236 toRemove.add(i); 237 } 238 } 239 240 if (!toRemove.isEmpty()) 241 { 242 boolean returnValue = modifiedIndexes.removeAll(toRemove); 243 indexModified(toRemove.iterator().next()); 244 return returnValue; 245 } 246 return false; 247 } 248 249 /** 250 * Unregisters all the modified indexes on a given backend. 251 * @param backendName the name of the backend. 252 */ 253 public void unregisterModifiedIndexesInBackend(String backendName) 254 { 255 HashSet<AbstractIndexDescriptor> toDelete = new HashSet<>(); 256 for (AbstractIndexDescriptor index : modifiedIndexes) 257 { 258 // Compare only the Backend ID, since the backend object attached to 259 // the registered index might have changed (for instance the number of 260 // entries). Relying on the backend ID to identify the backend is 261 // safe. 262 if (index.getBackend().getBackendID().equalsIgnoreCase(backendName)) 263 { 264 toDelete.add(index); 265 } 266 } 267 modifiedIndexes.removeAll(toDelete); 268 for (BackendDescriptor backend : getServerDescriptor().getBackends()) 269 { 270 if (backend.getBackendID().equals(backendName)) 271 { 272 IndexModifiedEvent ev = new IndexModifiedEvent(backend); 273 for (IndexModifiedListener listener : indexListeners) 274 { 275 listener.backendIndexesModified(ev); 276 } 277 break; 278 } 279 } 280 } 281 282 /** 283 * Returns a collection with all the modified indexes. 284 * @return a collection with all the modified indexes. 285 */ 286 public Collection<AbstractIndexDescriptor> getModifiedIndexes() 287 { 288 return Collections.unmodifiableCollection(modifiedIndexes); 289 } 290 291 /** 292 * Sets the dir context to be used by the ControlPanelInfo to retrieve 293 * monitoring and configuration information. 294 * @param connWrapper the connection. 295 */ 296 public void setConnection(ConnectionWrapper connWrapper) 297 { 298 this.connWrapper = connWrapper; 299 if (connWrapper != null) 300 { 301 InitialLdapContext ctx = connWrapper.getLdapContext(); 302 lastWorkingBindDN = ConnectionUtils.getBindDN(ctx); 303 lastWorkingBindPwd = ConnectionUtils.getBindPassword(ctx); 304 lastRemoteHostName = connWrapper.getHostPort().getHost(); 305 lastRemoteAdministrationURL = ConnectionUtils.getLdapUrl(ctx); 306 } 307 } 308 309 /** 310 * Returns the connection to be used by the ControlPanelInfo to retrieve 311 * monitoring and configuration information. 312 * @return the connection to be used by the ControlPanelInfo to retrieve 313 * monitoring and configuration information. 314 */ 315 public ConnectionWrapper getConnection() 316 { 317 return connWrapper; 318 } 319 320 /** 321 * Sets the dir context to be used by the ControlPanelInfo to retrieve 322 * user data. 323 * @param ctx the connection. 324 * @throws NamingException if there is a problem updating the connection pool. 325 */ 326 public void setUserDataDirContext(InitialLdapContext ctx) 327 throws NamingException 328 { 329 if (userDataCtx != null) 330 { 331 unregisterConnection(connectionPool, ctx); 332 } 333 this.userDataCtx = ctx; 334 if (ctx != null) 335 { 336 InitialLdapContext cloneLdc = 337 ConnectionUtils.cloneInitialLdapContext(userDataCtx, 338 getConnectTimeout(), 339 getTrustManager(), null); 340 connectionPool.registerConnection(cloneLdc); 341 } 342 } 343 344 /** 345 * Returns the dir context to be used by the ControlPanelInfo to retrieve 346 * user data. 347 * @return the dir context to be used by the ControlPanelInfo to retrieve 348 * user data. 349 */ 350 public InitialLdapContext getUserDataDirContext() 351 { 352 return userDataCtx; 353 } 354 355 /** 356 * Informs that a backup has been created. The method will notify to all 357 * the backup listeners that a backup has been created. 358 * @param newBackup the new created backup. 359 */ 360 public void backupCreated(BackupDescriptor newBackup) 361 { 362 BackupCreatedEvent ev = new BackupCreatedEvent(newBackup); 363 for (BackupCreatedListener listener : backupListeners) 364 { 365 listener.backupCreated(ev); 366 } 367 } 368 369 /** 370 * Informs that a set of backends have been populated. The method will notify 371 * to all the backend populated listeners. 372 * @param backends the populated backends. 373 */ 374 public void backendPopulated(Set<BackendDescriptor> backends) 375 { 376 BackendPopulatedEvent ev = new BackendPopulatedEvent(backends); 377 for (BackendPopulatedListener listener : backendPopulatedListeners) 378 { 379 listener.backendPopulated(ev); 380 } 381 } 382 383 /** 384 * Informs that an index has been modified. The method will notify to all 385 * the index listeners that an index has been modified. 386 * @param modifiedIndex the modified index. 387 */ 388 private void indexModified(AbstractIndexDescriptor modifiedIndex) 389 { 390 IndexModifiedEvent ev = new IndexModifiedEvent(modifiedIndex); 391 for (IndexModifiedListener listener : indexListeners) 392 { 393 listener.indexModified(ev); 394 } 395 } 396 397 /** 398 * Updates the contents of the server descriptor with the provider reader. 399 * @param reader the configuration reader. 400 * @param desc the server descriptor. 401 */ 402 private void updateServerDescriptor(ConfigReader reader, ServerDescriptor desc) 403 { 404 desc.setExceptions(reader.getExceptions()); 405 desc.setAdministrativeUsers(reader.getAdministrativeUsers()); 406 desc.setBackends(reader.getBackends()); 407 desc.setConnectionHandlers(reader.getConnectionHandlers()); 408 desc.setAdminConnector(reader.getAdminConnector()); 409 desc.setSchema(reader.getSchema()); 410 desc.setSchemaEnabled(reader.isSchemaEnabled()); 411 } 412 413 /** Regenerates the last found ServerDescriptor object. */ 414 public synchronized void regenerateDescriptor() 415 { 416 ServerDescriptor desc = new ServerDescriptor(); 417 desc.setIsLocal(isLocal); 418 if (isLocal) 419 { 420 desc.setOpenDSVersion(DynamicConstants.FULL_VERSION_STRING); 421 String installPath = Utilities.getInstallPathFromClasspath(); 422 desc.setInstallPath(installPath); 423 desc.setInstancePath(Utils.getInstancePathFromInstallPath(installPath)); 424 desc.setWindowsServiceEnabled(isWindows() && serviceState() == SERVICE_STATE_ENABLED); 425 } 426 else if (lastRemoteHostName != null) 427 { 428 desc.setHostname(lastRemoteHostName); 429 } 430 431 ConfigReader reader; 432 ServerStatus status = getStatus(desc); 433 if (status != null) 434 { 435 desc.setStatus(status); 436 if (status == ServerStatus.STOPPING) 437 { 438 StaticUtils.close(connWrapper); 439 connWrapper = null; 440 if (userDataCtx != null) 441 { 442 unregisterConnection(connectionPool, null); 443 StaticUtils.close(userDataCtx); 444 userDataCtx = null; 445 } 446 } 447 if (isLocal) 448 { 449 reader = newLocalConfigReader(); 450 } 451 else 452 { 453 reader = null; 454 } 455 desc.setAuthenticated(false); 456 } 457 else if (!isLocal || 458 Utilities.isServerRunning(new File(desc.getInstancePath()))) 459 { 460 desc.setStatus(ServerStatus.STARTED); 461 462 if (connWrapper == null && lastWorkingBindDN != null) 463 { 464 // Try with previous credentials. 465 try 466 { 467 if (isLocal) 468 { 469 connWrapper = Utilities.getAdminDirContext(this, lastWorkingBindDN, lastWorkingBindPwd); 470 } 471 else if (lastRemoteAdministrationURL != null) 472 { 473 connWrapper = new ConnectionWrapper( 474 lastRemoteAdministrationURL, LDAPS, lastWorkingBindDN, lastWorkingBindPwd, 475 getConnectTimeout(), getTrustManager()); 476 } 477 } 478 catch (ConfigReadException | NamingException cre) 479 { 480 // Ignore: we will ask the user for credentials. 481 } 482 } 483 484 if (connWrapper == null) 485 { 486 if (isLocal) 487 { 488 reader = newLocalConfigReader(); 489 } 490 else 491 { 492 reader = null; 493 desc.setStatus(ServerStatus.NOT_CONNECTED_TO_REMOTE); 494 } 495 } 496 else 497 { 498 Utilities.initializeConfigurationFramework(); 499 reader = newRemoteConfigReader(); 500 501 boolean connectionWorks = checkConnections(connWrapper.getLdapContext(), userDataCtx); 502 if (!connectionWorks) 503 { 504 if (isLocal) 505 { 506 reader = newLocalConfigReader(); 507 } 508 else 509 { 510 reader = null; 511 desc.setStatus(ServerStatus.NOT_CONNECTED_TO_REMOTE); 512 } 513 StaticUtils.close(connWrapper); 514 this.connWrapper = null; 515 unregisterConnection(connectionPool, connWrapper.getLdapContext()); 516 StaticUtils.close(userDataCtx); 517 userDataCtx = null; 518 } 519 } 520 521 if (reader != null) 522 { 523 desc.setAuthenticated(reader instanceof ConfigFromDirContext); 524 desc.setJavaVersion(reader.getJavaVersion()); 525 desc.setOpenConnections(reader.getOpenConnections()); 526 desc.setTaskEntries(reader.getTaskEntries()); 527 if (reader instanceof ConfigFromDirContext) 528 { 529 ConfigFromDirContext rCtx = (ConfigFromDirContext)reader; 530 desc.setRootMonitor(rCtx.getRootMonitor()); 531 desc.setEntryCachesMonitor(rCtx.getEntryCaches()); 532 desc.setJvmMemoryUsageMonitor(rCtx.getJvmMemoryUsage()); 533 desc.setSystemInformationMonitor(rCtx.getSystemInformation()); 534 desc.setWorkQueueMonitor(rCtx.getWorkQueue()); 535 desc.setOpenDSVersion(getFirstValueAsString(rCtx.getVersionMonitor(), "fullVersion")); 536 String installPath = getFirstValueAsString(rCtx.getSystemInformation(), "installPath"); 537 if (installPath != null) 538 { 539 desc.setInstallPath(installPath); 540 } 541 String instancePath = getFirstValueAsString(rCtx.getSystemInformation(), "instancePath"); 542 if (instancePath != null) 543 { 544 desc.setInstancePath(instancePath); 545 } 546 } 547 } 548 } 549 else 550 { 551 desc.setStatus(ServerStatus.STOPPED); 552 desc.setAuthenticated(false); 553 reader = newLocalConfigReader(); 554 } 555 if (reader != null) 556 { 557 updateServerDescriptor(reader, desc); 558 } 559 560 if (serverDesc == null || !serverDesc.equals(desc)) 561 { 562 serverDesc = desc; 563 ldapURL = getURL(serverDesc, ConnectionHandlerDescriptor.Protocol.LDAP); 564 ldapsURL = getURL(serverDesc, ConnectionHandlerDescriptor.Protocol.LDAPS); 565 adminConnectorURL = getAdminConnectorURL(serverDesc); 566 if (serverDesc.isLocal()) 567 { 568 localAdminConnectorURL = adminConnectorURL; 569 } 570 startTLSURL = getURL(serverDesc, ConnectionHandlerDescriptor.Protocol.LDAP_STARTTLS); 571 ConfigurationChangeEvent ev = new ConfigurationChangeEvent(this, desc); 572 for (ConfigChangeListener listener : configListeners) 573 { 574 listener.configurationChanged(ev); 575 } 576 } 577 } 578 579 private ConfigReader newRemoteConfigReader() 580 { 581 ConfigFromDirContext reader = new ConfigFromDirContext(); 582 reader.setIsLocal(isLocal); 583 reader.readConfiguration(connWrapper); 584 return reader; 585 } 586 587 private ConfigReader newLocalConfigReader() 588 { 589 ConfigFromFile reader = new ConfigFromFile(); 590 reader.readConfiguration(); 591 return reader; 592 } 593 594 private ServerStatus getStatus(ServerDescriptor desc) 595 { 596 ServerStatus status = null; 597 for (Task task : getTasks()) 598 { 599 if (task.getType() == Type.START_SERVER 600 && task.getState() == State.RUNNING 601 && isRunningOnServer(desc, task)) 602 { 603 status = ServerStatus.STARTING; 604 } 605 else if (task.getType() == Type.STOP_SERVER && task.getState() == State.RUNNING 606 && isRunningOnServer(desc, task)) 607 { 608 status = ServerStatus.STOPPING; 609 } 610 } 611 return status; 612 } 613 614 private void unregisterConnection(LDAPConnectionPool connectionPool, InitialLdapContext userDataCtx) 615 { 616 if (connectionPool.isConnectionRegistered(userDataCtx)) 617 { 618 try 619 { 620 connectionPool.unregisterConnection(userDataCtx); 621 } 622 catch (Throwable t) 623 { 624 } 625 } 626 } 627 628 /** 629 * Adds a configuration change listener. 630 * @param listener the listener. 631 */ 632 public void addConfigChangeListener(ConfigChangeListener listener) 633 { 634 configListeners.add(listener); 635 } 636 637 /** 638 * Removes a configuration change listener. 639 * @param listener the listener. 640 * @return <CODE>true</CODE> if the listener is found and <CODE>false</CODE> 641 * otherwise. 642 */ 643 public boolean removeConfigChangeListener(ConfigChangeListener listener) 644 { 645 return configListeners.remove(listener); 646 } 647 648 /** 649 * Adds a backup creation listener. 650 * @param listener the listener. 651 */ 652 public void addBackupCreatedListener(BackupCreatedListener listener) 653 { 654 backupListeners.add(listener); 655 } 656 657 /** 658 * Removes a backup creation listener. 659 * @param listener the listener. 660 * @return <CODE>true</CODE> if the listener is found and <CODE>false</CODE> 661 * otherwise. 662 */ 663 public boolean removeBackupCreatedListener(BackupCreatedListener listener) 664 { 665 return backupListeners.remove(listener); 666 } 667 668 /** 669 * Adds a backend populated listener. 670 * @param listener the listener. 671 */ 672 public void addBackendPopulatedListener(BackendPopulatedListener listener) 673 { 674 backendPopulatedListeners.add(listener); 675 } 676 677 /** 678 * Removes a backend populated listener. 679 * @param listener the listener. 680 * @return <CODE>true</CODE> if the listener is found and <CODE>false</CODE> 681 * otherwise. 682 */ 683 public boolean removeBackendPopulatedListener( 684 BackendPopulatedListener listener) 685 { 686 return backendPopulatedListeners.remove(listener); 687 } 688 689 /** 690 * Adds an index modification listener. 691 * @param listener the listener. 692 */ 693 public void addIndexModifiedListener(IndexModifiedListener listener) 694 { 695 indexListeners.add(listener); 696 } 697 698 /** 699 * Removes an index modification listener. 700 * @param listener the listener. 701 * @return <CODE>true</CODE> if the listener is found and <CODE>false</CODE> 702 * otherwise. 703 */ 704 public boolean removeIndexModifiedListener(IndexModifiedListener listener) 705 { 706 return indexListeners.remove(listener); 707 } 708 709 /** 710 * Starts pooling the server configuration. The period of the pooling is 711 * specified as a parameter. This method is asynchronous and it will start 712 * the pooling in another thread. 713 */ 714 public synchronized void startPooling() 715 { 716 if (poolingThread != null) 717 { 718 return; 719 } 720 pooling = true; 721 stopPooling = false; 722 723 poolingThread = new Thread(new Runnable() 724 { 725 @Override 726 public void run() 727 { 728 try 729 { 730 while (!stopPooling) 731 { 732 cleanupTasks(); 733 regenerateDescriptor(); 734 Thread.sleep(poolingPeriod); 735 } 736 } 737 catch (Throwable t) 738 { 739 } 740 pooling = false; 741 } 742 }); 743 poolingThread.start(); 744 } 745 746 /** 747 * Stops pooling the server. This method is synchronous, it does not return 748 * until the pooling is actually stopped. 749 */ 750 public synchronized void stopPooling() 751 { 752 stopPooling = true; 753 while (poolingThread != null && pooling) 754 { 755 try 756 { 757 poolingThread.interrupt(); 758 Thread.sleep(100); 759 } 760 catch (Throwable t) 761 { 762 // do nothing; 763 } 764 } 765 poolingThread = null; 766 pooling = false; 767 } 768 769 /** 770 * Returns the trust manager to be used by this ControlPanelInfo (and in 771 * general by the control panel). 772 * @return the trust manager to be used by this ControlPanelInfo. 773 */ 774 public ApplicationTrustManager getTrustManager() 775 { 776 return trustManager; 777 } 778 779 /** 780 * Sets the trust manager to be used by this ControlPanelInfo (and in 781 * general by the control panel). 782 * @param trustManager the trust manager to be used by this ControlPanelInfo. 783 */ 784 public void setTrustManager(ApplicationTrustManager trustManager) 785 { 786 this.trustManager = trustManager; 787 connectionPool.setTrustManager(trustManager); 788 } 789 790 /** 791 * Returns the timeout to establish the connection in milliseconds. 792 * @return the timeout to establish the connection in milliseconds. 793 */ 794 public int getConnectTimeout() 795 { 796 return connectTimeout; 797 } 798 799 /** 800 * Sets the timeout to establish the connection in milliseconds. 801 * Use {@code 0} to express no timeout. 802 * @param connectTimeout the timeout to establish the connection in 803 * milliseconds. 804 * Use {@code 0} to express no timeout. 805 */ 806 public void setConnectTimeout(int connectTimeout) 807 { 808 this.connectTimeout = connectTimeout; 809 connectionPool.setConnectTimeout(connectTimeout); 810 } 811 812 /** 813 * Returns the connection policy to be used by this ControlPanelInfo (and in 814 * general by the control panel). 815 * @return the connection policy to be used by this ControlPanelInfo. 816 */ 817 public ConnectionProtocolPolicy getConnectionPolicy() 818 { 819 return connectionPolicy; 820 } 821 822 /** 823 * Sets the connection policy to be used by this ControlPanelInfo (and in 824 * general by the control panel). 825 * @param connectionPolicy the connection policy to be used by this 826 * ControlPanelInfo. 827 */ 828 public void setConnectionPolicy(ConnectionProtocolPolicy connectionPolicy) 829 { 830 this.connectionPolicy = connectionPolicy; 831 } 832 833 /** 834 * Gets the LDAPS URL based in what is read in the configuration. It 835 * returns <CODE>null</CODE> if no LDAPS URL was found. 836 * @return the LDAPS URL to be used to connect to the server. 837 */ 838 public String getLDAPSURL() 839 { 840 return ldapsURL; 841 } 842 843 /** 844 * Gets the Administration Connector URL based in what is read in the 845 * configuration. It returns <CODE>null</CODE> if no Administration 846 * Connector URL was found. 847 * @return the Administration Connector URL to be used to connect 848 * to the server. 849 */ 850 public String getAdminConnectorURL() 851 { 852 if (isLocal) 853 { 854 // If the user set isLocal to true, we want to return the 855 // localAdminConnectorURL (in particular if regenerateDescriptor has not 856 // been called). 857 return localAdminConnectorURL; 858 } 859 return adminConnectorURL; 860 } 861 862 /** 863 * Gets the Administration Connector URL based in what is read in the local 864 * configuration. It returns <CODE>null</CODE> if no Administration 865 * Connector URL was found. 866 * @return the Administration Connector URL to be used to connect 867 * to the local server. 868 */ 869 public String getLocalAdminConnectorURL() 870 { 871 return localAdminConnectorURL; 872 } 873 874 /** 875 * Gets the LDAP URL based in what is read in the configuration. It 876 * returns <CODE>null</CODE> if no LDAP URL was found. 877 * @return the LDAP URL to be used to connect to the server. 878 */ 879 public String getLDAPURL() 880 { 881 return ldapURL; 882 } 883 884 /** 885 * Gets the Start TLS URL based in what is read in the configuration. It 886 * returns <CODE>null</CODE> if no Start TLS URL is found. 887 * @return the Start TLS URL to be used to connect to the server. 888 */ 889 public String getStartTLSURL() 890 { 891 return startTLSURL; 892 } 893 894 /** 895 * Returns the LDAP URL to be used to connect to a given ServerDescriptor 896 * using a certain protocol. It returns <CODE>null</CODE> if URL for the 897 * protocol is not found. 898 * @param server the server descriptor. 899 * @param protocol the protocol to be used. 900 * @return the LDAP URL to be used to connect to a given ServerDescriptor 901 * using a certain protocol. 902 */ 903 private static String getURL(ServerDescriptor server, 904 ConnectionHandlerDescriptor.Protocol protocol) 905 { 906 String sProtocol = toString(protocol); 907 908 String url = null; 909 for (ConnectionHandlerDescriptor desc : server.getConnectionHandlers()) 910 { 911 if (desc.getState() == ConnectionHandlerDescriptor.State.ENABLED 912 && desc.getProtocol() == protocol) 913 { 914 int port = desc.getPort(); 915 if (port > 0) 916 { 917 if (server.isLocal()) 918 { 919 SortedSet<InetAddress> addresses = desc.getAddresses(); 920 if (addresses.isEmpty()) 921 { 922 url = sProtocol +"://localhost:"+port; 923 } 924 else 925 { 926 InetAddress address = addresses.first(); 927 url = sProtocol + "://" + getHostNameForLdapUrl(address.getHostAddress()) + ":" + port; 928 } 929 } 930 else 931 { 932 url = sProtocol + "://" + getHostNameForLdapUrl(server.getHostname()) + ":" + port; 933 } 934 } 935 } 936 } 937 return url; 938 } 939 940 private static String toString(ConnectionHandlerDescriptor.Protocol protocol) 941 { 942 switch (protocol) 943 { 944 case LDAP: 945 return "ldap"; 946 case LDAPS: 947 return "ldaps"; 948 case LDAP_STARTTLS: 949 return "ldap"; 950 case JMX: 951 return "jmx"; 952 case JMXS: 953 return "jmxs"; 954 default: 955 return null; 956 } 957 } 958 959 /** 960 * Returns the Administration Connector URL. 961 * It returns <CODE>null</CODE> if URL for the 962 * protocol is not found. 963 * @param server the server descriptor. 964 * @return the Administration Connector URL. 965 */ 966 private static String getAdminConnectorURL(ServerDescriptor server) { 967 ConnectionHandlerDescriptor desc = server.getAdminConnector(); 968 if (desc != null) 969 { 970 int port = desc.getPort(); 971 if (port > 0) { 972 SortedSet<InetAddress> addresses = desc.getAddresses(); 973 if (!addresses.isEmpty()) 974 { 975 String hostAddr = addresses.first().getHostAddress(); 976 return getLDAPUrl(hostAddr, port, true); 977 } 978 else 979 { 980 return getLDAPUrl("localhost", port, true); 981 } 982 } 983 } 984 return null; 985 } 986 987 /** 988 * Tells whether we must connect to the server using Start TLS. 989 * @return <CODE>true</CODE> if we must connect to the server using Start TLS 990 * and <CODE>false</CODE> otherwise. 991 */ 992 public boolean connectUsingStartTLS() 993 { 994 return startTLSURL != null && startTLSURL.equals(getURLToConnect()); 995 } 996 997 /** 998 * Tells whether we must connect to the server using LDAPS. 999 * @return <CODE>true</CODE> if we must connect to the server using LDAPS 1000 * and <CODE>false</CODE> otherwise. 1001 */ 1002 public boolean connectUsingLDAPS() 1003 { 1004 return ldapsURL != null && ldapsURL.equals(getURLToConnect()); 1005 } 1006 1007 /** 1008 * Returns the URL that must be used to connect to the server based on the 1009 * available enabled connection handlers in the server and the connection 1010 * policy. 1011 * @return the URL that must be used to connect to the server. 1012 */ 1013 public String getURLToConnect() 1014 { 1015 switch (getConnectionPolicy()) 1016 { 1017 case USE_STARTTLS: 1018 return startTLSURL; 1019 case USE_LDAP: 1020 return ldapURL; 1021 case USE_LDAPS: 1022 return ldapsURL; 1023 case USE_ADMIN: 1024 return getAdminConnectorURL(); 1025 case USE_MOST_SECURE_AVAILABLE: 1026 String url1 = ldapsURL; 1027 if (url1 == null) 1028 { 1029 url1 = startTLSURL; 1030 } 1031 if (url1 == null) 1032 { 1033 url1 = ldapURL; 1034 } 1035 return url1; 1036 case USE_LESS_SECURE_AVAILABLE: 1037 String url2 = ldapURL; 1038 if (url2 == null) 1039 { 1040 url2 = startTLSURL; 1041 } 1042 if (url2 == null) 1043 { 1044 url2 = ldapsURL; 1045 } 1046 return url2; 1047 default: 1048 throw new RuntimeException("Unknown policy: "+getConnectionPolicy()); 1049 } 1050 } 1051 1052 /** 1053 * Returns {@code true} if the configuration must be deregistered and {@code false} otherwise. 1054 * This is required when we update the configuration, in these cases {@code cn=config} 1055 * must the deregistered and after that register again. 1056 * @return {@code true} if the configuration must be deregistered and {@code false} otherwise. 1057 */ 1058 public boolean mustDeregisterConfig() 1059 { 1060 return mustDeregisterConfig; 1061 } 1062 1063 /** 1064 * Sets whether the configuration must be deregistered or not. 1065 * @param mustDeregisterConfig whether the configuration must be deregistered 1066 * or not. 1067 */ 1068 public void setMustDeregisterConfig(boolean mustDeregisterConfig) 1069 { 1070 ControlPanelInfo.mustDeregisterConfig = mustDeregisterConfig; 1071 } 1072 1073 /** 1074 * Sets whether the server is local or not. 1075 * @param isLocal whether the server is local or not. 1076 */ 1077 public void setIsLocal(boolean isLocal) 1078 { 1079 this.isLocal = isLocal; 1080 } 1081 1082 /** 1083 * Returns <CODE>true</CODE> if we are trying to manage the local host and 1084 * <CODE>false</CODE> otherwise. 1085 * @return <CODE>true</CODE> if we are trying to manage the local host and 1086 * <CODE>false</CODE> otherwise. 1087 */ 1088 public boolean isLocal() 1089 { 1090 return isLocal; 1091 } 1092 1093 /** 1094 * Returns the connection pool to be used by the LDAP entry browsers. 1095 * @return the connection pool to be used by the LDAP entry browsers. 1096 */ 1097 public LDAPConnectionPool getConnectionPool() 1098 { 1099 return connectionPool; 1100 } 1101 1102 /** 1103 * Returns the icon pool to be used by the LDAP entry browsers. 1104 * @return the icon pool to be used by the LDAP entry browsers. 1105 */ 1106 public IconPool getIconPool() 1107 { 1108 return iconPool; 1109 } 1110 1111 /** 1112 * Returns the pooling period in miliseconds. 1113 * @return the pooling period in miliseconds. 1114 */ 1115 public long getPoolingPeriod() 1116 { 1117 return poolingPeriod; 1118 } 1119 1120 /** 1121 * Sets the pooling period in miliseconds. 1122 * @param poolingPeriod the pooling time in miliseconds. 1123 */ 1124 public void setPoolingPeriod(long poolingPeriod) 1125 { 1126 this.poolingPeriod = poolingPeriod; 1127 } 1128 1129 /** Cleans the tasks that are over. */ 1130 private void cleanupTasks() 1131 { 1132 Set<Task> toClean = new HashSet<>(); 1133 for (Task task : tasks) 1134 { 1135 if (task.getState() == Task.State.FINISHED_SUCCESSFULLY || 1136 task.getState() == Task.State.FINISHED_WITH_ERROR) 1137 { 1138 toClean.add(task); 1139 } 1140 } 1141 for (Task task : toClean) 1142 { 1143 unregisterTask(task); 1144 } 1145 } 1146 1147 /** 1148 * Returns whether the provided task is running on the provided server or not. 1149 * The code takes into account that the server object might not be fully 1150 * initialized (but at least it contains the host name and the instance 1151 * path if it is local). 1152 * @param server the server. 1153 * @param task the task to be analyzed. 1154 * @return <CODE>true</CODE> if the provided task is running on the provided 1155 * server and <CODE>false</CODE> otherwise. 1156 */ 1157 private boolean isRunningOnServer(ServerDescriptor server, Task task) 1158 { 1159 if (server.isLocal() && task.getServer().isLocal()) 1160 { 1161 return true; 1162 } 1163 1164 String host1 = server.getHostname(); 1165 String host2 = task.getServer().getHostname(); 1166 boolean isRunningOnServer = host1 != null ? host1.equalsIgnoreCase(host2) : host2 == null; 1167 if (!isRunningOnServer) 1168 { 1169 return false; 1170 } 1171 1172 if (server.isLocal()) 1173 { 1174 // Compare paths 1175 String path1 = server.getInstancePath(); 1176 String path2 = task.getServer().getInstancePath(); 1177 return Objects.equals(path1, path2); 1178 } 1179 1180 // At this point we only have connection information about the new server. 1181 // Use the dir context which corresponds to the server to compare things. 1182 1183 // Compare administration port; 1184 int adminPort1 = -1; 1185 int adminPort2 = -1; 1186 if (server.getAdminConnector() != null) 1187 { 1188 adminPort1 = server.getAdminConnector().getPort(); 1189 } 1190 1191 if (getConnection() != null) 1192 { 1193 adminPort2 = getConnection().getHostPort().getPort(); 1194 } 1195 return adminPort1 == adminPort2; 1196 } 1197 1198 private boolean checkConnections(InitialLdapContext ctx, InitialLdapContext userCtx) 1199 { 1200 // Check the connection 1201 int nMaxErrors = 5; 1202 for (int i=0; i< nMaxErrors; i++) 1203 { 1204 try 1205 { 1206 Utilities.pingDirContext(ctx); 1207 if (userCtx != null) 1208 { 1209 Utilities.pingDirContext(userCtx); 1210 } 1211 return true; 1212 } 1213 catch (NamingException ne) 1214 { 1215 try 1216 { 1217 Thread.sleep(400); 1218 } 1219 catch (Throwable t) 1220 { 1221 } 1222 } 1223 } 1224 return false; 1225 } 1226 1227 /** 1228 * Initialize the new configuration framework if needed. 1229 * 1230 * @throws org.opends.server.config.ConfigException 1231 * If error occurred during the initialization 1232 */ 1233 public void initializeConfigurationFramework() throws org.opends.server.config.ConfigException 1234 { 1235 if (!ConfigurationFramework.getInstance().isInitialized()) 1236 { 1237 try 1238 { 1239 ConfigurationFramework.getInstance().initialize(); 1240 } 1241 catch (ConfigException ce) 1242 { 1243 throw new org.opends.server.config.ConfigException(ce.getMessageObject(), ce); 1244 } 1245 } 1246 } 1247}