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 2011-2015 ForgeRock AS.
016 */
017package org.opends.quicksetup;
018
019import java.net.*;
020import java.util.*;
021import java.util.concurrent.CountDownLatch;
022import java.util.concurrent.TimeUnit;
023
024import org.forgerock.opendj.config.ManagedObjectDefinition;
025import org.forgerock.opendj.server.config.client.BackendCfgClient;
026import org.forgerock.opendj.server.config.server.BackendCfg;
027import org.opends.admin.ads.ServerDescriptor;
028import org.opends.admin.ads.SuffixDescriptor;
029import org.opends.quicksetup.installer.AuthenticationData;
030import org.opends.quicksetup.installer.DataReplicationOptions;
031import org.opends.quicksetup.installer.NewSuffixOptions;
032import org.opends.quicksetup.installer.SuffixesToReplicateOptions;
033import org.opends.quicksetup.util.Utils;
034import org.opends.server.util.CollectionUtils;
035
036import com.forgerock.opendj.cli.CliConstants;
037
038/**
039 * This class is used to provide a data model for the different parameters
040 * that the user can provide in the installation wizard.
041 */
042public class UserData
043{
044  private String serverLocation;
045  private String hostName;
046  private int serverPort;
047  private int adminConnectorPort;
048  private String directoryManagerDn;
049  private String directoryManagerPwd;
050  private String globalAdministratorUID;
051  private String globalAdministratorPassword;
052  private SecurityOptions securityOptions;
053  private int serverJMXPort = -1;
054
055  private boolean startServer;
056  private boolean stopServer;
057  private boolean enableWindowsService;
058  private boolean createAdministrator;
059  private boolean quiet;
060  private boolean verbose;
061  private final boolean interactive;
062  private boolean forceOnError;
063
064  private ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType;
065  private NewSuffixOptions newSuffixOptions;
066  private DataReplicationOptions replicationOptions;
067  private SuffixesToReplicateOptions suffixesToReplicateOptions;
068  private final Map<ServerDescriptor, AuthenticationData> remoteWithNoReplicationPort;
069
070  private Map<String, JavaArguments> hmJavaArguments;
071  private Map<String, JavaArguments> hmDefaultJavaArguments;
072
073  private static String defaultHostName;
074
075  private int connectTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT;
076
077  /**
078   * The script name to be used to get and set the java arguments for the
079   * server runtime.
080   */
081  public final static String SERVER_SCRIPT_NAME = "start-ds";
082  /**
083   * The script name to be used to get and set the java arguments for the
084   * (off-line) import.
085   */
086  public final static String IMPORT_SCRIPT_NAME = "import-ldif.offline";
087
088  /**
089   * Creates a user data object with default values.
090   */
091  public UserData() {
092    interactive = true;
093    startServer = true;
094    enableWindowsService = false;
095    forceOnError = true;
096    verbose = false;
097
098    LinkedList<String> baseDn = CollectionUtils.newLinkedList("dc=example,dc=com");
099    NewSuffixOptions defaultNewSuffixOptions = NewSuffixOptions.createEmpty(baseDn);
100    setNewSuffixOptions(defaultNewSuffixOptions);
101
102    // See what we can propose as port
103    int defaultLdapPort = getDefaultPort();
104    if (defaultLdapPort != -1)
105    {
106      setServerPort(defaultLdapPort);
107    }
108
109//  See what we can propose as port
110    int defaultAdminPort = getDefaultAdminConnectorPort();
111    if (defaultAdminPort != -1)
112    {
113      setAdminConnectorPort(defaultAdminPort);
114    }
115
116    setHostName(getDefaultHostName());
117
118    setDirectoryManagerDn(Constants.DIRECTORY_MANAGER_DN);
119
120    setNewSuffixOptions(defaultNewSuffixOptions);
121    DataReplicationOptions repl = DataReplicationOptions.createStandalone();
122    setReplicationOptions(repl);
123    setGlobalAdministratorUID(Constants.GLOBAL_ADMIN_UID);
124
125    SuffixesToReplicateOptions suffixes =
126      new SuffixesToReplicateOptions(
127          SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES,
128          new HashSet<SuffixDescriptor>(),
129          new HashSet<SuffixDescriptor>());
130    setSuffixesToReplicateOptions(suffixes);
131    SecurityOptions sec = SecurityOptions.createNoCertificateOptions();
132    sec.setSslPort(getDefaultSslPort(defaultLdapPort));
133    setSecurityOptions(sec);
134
135    remoteWithNoReplicationPort = new HashMap<>();
136
137    createDefaultJavaArguments();
138  }
139
140  /**
141   * Sets the location of the server (installation path).
142   * @param serverLocation the new server location (installation path).
143   */
144  public void setServerLocation(String serverLocation)
145  {
146    this.serverLocation = serverLocation;
147  }
148
149  /**
150   * Returns the location of the server (installation path).
151   * @return the location of the server (installation path).
152   */
153  public String getServerLocation()
154  {
155    return serverLocation;
156  }
157
158  /**
159   * Sets the host name.
160   * @param hostName the server host name.
161   */
162  public void setHostName(String hostName)
163  {
164    this.hostName = hostName;
165  }
166
167  /**
168   * Returns the server host name.
169   * @return the server host name.
170   */
171  public String getHostName()
172  {
173    return hostName;
174  }
175
176  /**
177   * Sets the server LDAP port.
178   * @param serverPort the new server LDAP port.
179   */
180  public void setServerPort(int serverPort)
181  {
182    this.serverPort = serverPort;
183  }
184
185  /**
186   * Returns the server LDAP port.
187   * @return the server LDAP port.
188   */
189  public int getServerPort()
190  {
191    return serverPort;
192  }
193
194  /**
195   * Sets the admin connector port.
196   * @param adminConnectorPort the new admin connector port.
197   */
198  public void setAdminConnectorPort(int adminConnectorPort)
199  {
200    this.adminConnectorPort = adminConnectorPort;
201  }
202
203  /**
204   * Returns the admin connector port.
205   * @return the admin connector port.
206   */
207  public int getAdminConnectorPort()
208  {
209    return adminConnectorPort;
210  }
211
212  /**
213   * Sets the server JMX port.
214   * @param serverJMXPort the new server JMX port.
215   */
216  public void setServerJMXPort(int serverJMXPort)
217  {
218    this.serverJMXPort = serverJMXPort;
219  }
220
221  /**
222   * Returns the server JMX port.
223   * @return the server JMX port.
224   */
225  public int getServerJMXPort()
226  {
227    return serverJMXPort;
228  }
229
230  /**
231   * Returns the Directory Manager DN.
232   * @return the Directory Manager DN.
233   */
234  public String getDirectoryManagerDn()
235  {
236    return directoryManagerDn;
237  }
238
239  /**
240   * Sets the new Directory Manager DN.
241   * @param directoryManagerDn the new Directory Manager DN.
242   */
243  public void setDirectoryManagerDn(String directoryManagerDn)
244  {
245    this.directoryManagerDn = directoryManagerDn;
246  }
247
248  /**
249   * Returns the Directory Manager password.
250   * @return the Directory Manager password.
251   */
252  public String getDirectoryManagerPwd()
253  {
254    return directoryManagerPwd;
255  }
256
257  /**
258   * Sets the new Directory Manager password.
259   * @param directoryManagerPwd the new Directory Manager password.
260   */
261  public void setDirectoryManagerPwd(String directoryManagerPwd)
262  {
263    this.directoryManagerPwd = directoryManagerPwd;
264  }
265
266  /**
267   * Returns <CODE>true</CODE> if the server must be started once the
268   * installation is finished, <CODE>false</CODE> if not.
269   * @return <CODE>true</CODE> if the server must be started once the
270   * installation is finished, <CODE>false</CODE> if not.
271   */
272  public boolean getStartServer()
273  {
274    return startServer;
275  }
276
277  /**
278   * Sets whether we want to start the server once the installation is finished
279   * or not.
280   * @param startServer the boolean indicating whether to start the server or
281   * not.
282   */
283  public void setStartServer(boolean startServer)
284  {
285    this.startServer = startServer;
286  }
287
288  /**
289   * Sets whether to stop the server or not.
290   * @param stopServer stop the server or not.
291   */
292  public void setStopServer(boolean stopServer)
293  {
294    this.stopServer = stopServer;
295  }
296
297  /**
298   * Returns whether the user wants to stop the server or not.
299   * @return <CODE>true</CODE> if the user wants to stop the server and <CODE>\
300   * false</CODE> otherwise.
301   */
302  public boolean getStopServer()
303  {
304    return stopServer;
305  }
306
307  /**
308   * Returns <CODE>true</CODE> if the windows service must be enabled during
309   * installation, <CODE>false</CODE> if not.
310   * @return <CODE>true</CODE> if the windows service must be enabled during
311   * installation, <CODE>false</CODE> if not.
312   */
313  public boolean getEnableWindowsService()
314  {
315    return enableWindowsService;
316  }
317
318  /**
319   * Sets whether we want to enable windows service during installation or not.
320   * @param enableWindowsService the boolean indicating whether we want to
321   * enable windows service during installation or not.
322   */
323  public void setEnableWindowsService(boolean enableWindowsService)
324  {
325    this.enableWindowsService = enableWindowsService;
326  }
327
328  /**
329   * Returns the new userRoot backend type.
330   *
331   * @return the new userRoot backend type.
332   */
333  public ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> getBackendType()
334  {
335    return backendType;
336  }
337
338  /**
339   * Sets the new userRoot backend type.
340   *
341   * @param backendType
342   *          The new backend type. This string must be compatible with
343   *          dsconfig tool.
344   */
345  public void setBackendType(ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType)
346  {
347    this.backendType = backendType;
348  }
349
350  /**
351   * Returns the NewSuffixOptions object representing the data in the New Suffix
352   * Data Options panel.
353   * @return the NewSuffixOptions object representing the data in the New Suffix
354   * Data Options panel.
355   */
356  public NewSuffixOptions getNewSuffixOptions()
357  {
358    return newSuffixOptions;
359  }
360
361  /**
362   * Sets the NewSuffixOptions object representing the data in the New Suffix
363   * Data Options panel.
364   * @param newSuffixOptions the NewSuffixOptions object representing the data
365   * in the New Suffix Data Options panel.
366   */
367  public void setNewSuffixOptions(NewSuffixOptions newSuffixOptions)
368  {
369    this.newSuffixOptions = newSuffixOptions;
370  }
371
372  /**
373   * Returns the DataReplicationOptions object representing the data in the
374   * Data Replication panel.
375   * @return the DataReplicationOptions object representing the data in the
376   * Data Replication panel.
377   */
378  public DataReplicationOptions getReplicationOptions()
379  {
380    return replicationOptions;
381  }
382
383  /**
384   * Sets the DataReplicationOptions object representing the data in the
385   * Data Replication panel.
386   * @param replicationOptions the DataReplicationOptions object
387   * representing the data in the Data Replication panel.
388   */
389  public void setReplicationOptions(
390      DataReplicationOptions replicationOptions)
391  {
392    this.replicationOptions = replicationOptions;
393  }
394
395  /**
396   * Returns whether must create a global administrator or not.
397   * @return <CODE>true</CODE> if we must create a global administrator and
398   * <CODE>false</CODE> otherwise.
399   */
400  public boolean mustCreateAdministrator()
401  {
402    return createAdministrator;
403  }
404
405  /**
406   * Sets whether must create a global administrator or not.
407   * @param createAdministrator whether we must create a global administrator or
408   * not.
409   */
410  public void createAdministrator(boolean createAdministrator)
411  {
412    this.createAdministrator = createAdministrator;
413  }
414
415  /**
416   * Returns the UID of the global administrator.
417   * @return the UID of the global administrator.
418   */
419  public String getGlobalAdministratorUID()
420  {
421    return globalAdministratorUID;
422  }
423
424  /**
425   * Sets the UID of the global administrator.
426   * @param globalAdministratorUID the UID of the global administrator.
427   */
428  public void setGlobalAdministratorUID(String globalAdministratorUID)
429  {
430    this.globalAdministratorUID = globalAdministratorUID;
431  }
432
433  /**
434   * Returns the password of the global administrator.
435   * @return the password of the global administrator.
436   */
437  public String getGlobalAdministratorPassword()
438  {
439    return globalAdministratorPassword;
440  }
441
442  /**
443   * Sets the password of the global administrator.
444   * @param globalAdministratorPwd the password of the global administrator.
445   */
446  public void setGlobalAdministratorPassword(String globalAdministratorPwd)
447  {
448    this.globalAdministratorPassword = globalAdministratorPwd;
449  }
450
451  /**
452   * Sets the suffixes to replicate options.
453   * @param suffixesToReplicateOptions the suffixes to replicate options
454   * object.
455   */
456  public void setSuffixesToReplicateOptions(
457      SuffixesToReplicateOptions suffixesToReplicateOptions)
458  {
459    this.suffixesToReplicateOptions = suffixesToReplicateOptions;
460  }
461
462  /**
463   * Returns the suffixes to replicate options.
464   * @return the suffixes to replicate options.
465   */
466  public SuffixesToReplicateOptions getSuffixesToReplicateOptions()
467  {
468    return suffixesToReplicateOptions;
469  }
470
471  /**
472   * Returns the SecurityOptions representing the SSL/StartTLS configuration
473   * chosen by the user.
474   * @return the SecurityOptions representing the SSL/StartTLS configuration
475   * chosen by the user.
476   */
477  public SecurityOptions getSecurityOptions()
478  {
479    return securityOptions;
480  }
481
482  /**
483   * Sets the SecurityOptions representing the SSL/StartTLS configuration
484   * chosen by the user.
485   * @param securityOptions the SecurityOptions representing the SSL/StartTLS
486   * configuration chosen by the user.
487   */
488  public void setSecurityOptions(SecurityOptions securityOptions)
489  {
490    this.securityOptions = securityOptions;
491  }
492
493  /**
494   * Sets whether or not this session should print messages to the
495   * console if in CLI mode.
496   * @param quiet where true indicates this session should be quiet
497   */
498  public void setQuiet(boolean quiet) {
499    this.quiet = quiet;
500  }
501
502  /**
503   * Indicates whether or not the user has requested quiet mode.
504   * <p>
505   * Quiet mode in the CLI means that nothing is written to output including
506   * prompts for information and whether or not to continue an operation
507   * experiencing errors.
508   *
509   * @return boolean where true indicates this session should be quiet.
510   */
511  public boolean isQuiet() {
512    return this.quiet;
513  }
514
515  /**
516   * Sets whether or not this session should be verbose.
517   * @param verbose where true indicates this session should be verbose
518   */
519  public void setVerbose(boolean verbose) {
520    this.verbose = verbose;
521  }
522
523  /**
524   * Indicates whether or not the user has requested verbose mode.
525   *
526   * @return boolean where true indicates this session should be verbose.
527   */
528  public boolean isVerbose() {
529    return this.verbose;
530  }
531
532  /**
533   * Sets whether or not we must continue when there is a non critical error.
534   * @param forceOnError where true indicates to continue uninstall if there is
535   * a non critical error.
536   */
537  public void setForceOnError(boolean forceOnError) {
538    this.forceOnError = forceOnError;
539  }
540
541  /**
542   * Indicates whether or not the user has requested to continue when a non
543   * critical error occurs.
544   *
545   * @return boolean where true indicates to continue uninstall if there is a
546   * non critical error.
547   */
548  public boolean isForceOnError() {
549    return this.forceOnError;
550  }
551
552  /**
553   * Indicates whether or not the user has requested interactive mode.
554   * <p>
555   * Interactive mode in the CLI means that the CLI will prompt the user
556   * for more information if it is required.  Interactivity does NOT
557   * affect prompts to the user regarding actions like continuing an operation
558   * that is experiencing errors.
559   *
560   * @return boolean where true indicates this session should be interactive
561   */
562  public boolean isInteractive() {
563    return this.interactive;
564  }
565
566  /**
567   * Provides the port that will be proposed to the user in the second page of
568   * the installation wizard. It will check whether we can use ports of type
569   * X389 and if not it will return -1.
570   *
571   * @return the free port of type x389 if it is available and we can use and -1
572   * if not.
573   */
574  public static int getDefaultPort()
575  {
576    return getDefaultPort(389);
577  }
578
579  /**
580   * Provides the administration port that will be proposed to the user in the
581   * second page of the installation wizard. It will check whether we can use
582   * ports of type X444 and if not it will return -1.
583   *
584   * @return the free port of type x444 if it is available and we can use and -1
585   * if not.
586   */
587  public static int getDefaultAdminConnectorPort()
588  {
589    return getDefaultPort(4444);
590  }
591
592  /**
593   * Provides the port that will be proposed to the user in the security dialog
594   *  of the installation wizard. It will check whether we can use ports of type
595   * X636 and if not it will return -1.
596   * @param defaultLdapPort the default port used for LDAP.
597   *
598   * @return the free port of type X636 if it is available and we can use and -1
599   * if not.
600   */
601  public static int getDefaultSslPort(int defaultLdapPort)
602  {
603    int port = defaultLdapPort - 389 + 636;
604    // Try first with the correlated port of the default LDAP port.
605    if (Utils.canUseAsPort(port))
606    {
607      return port;
608    }
609
610    return getDefaultPort(636);
611  }
612
613  private static int getDefaultPort(int basePort)
614  {
615    for (int i = 0; i < 10000; i += 1000)
616    {
617      int port = i + basePort;
618      if (Utils.canUseAsPort(port))
619      {
620        return port;
621      }
622    }
623    return -1;
624  }
625
626  /**
627   * Provides the port that will be used by default for JMX.
628   *
629   * @param forbiddenPorts an array of ports that we cannot use.
630   * @return the port X689 if it is available and we can use and -1 if not.
631   */
632  public static int getDefaultJMXPort(int[] forbiddenPorts)
633  {
634    int defaultJMXPort = -1;
635
636    for (int i=0;i<65000 && defaultJMXPort == -1;i+=1000)
637    {
638      int port = i + CliConstants.DEFAULT_JMX_PORT;
639      boolean isForbidden = false;
640      if (forbiddenPorts != null)
641      {
642        for (int j=0; j<forbiddenPorts.length && !isForbidden; j++)
643        {
644          isForbidden = forbiddenPorts[j] == port;
645        }
646      }
647      if (!isForbidden && Utils.canUseAsPort(port))
648      {
649        defaultJMXPort = port;
650      }
651    }
652    return defaultJMXPort;
653  }
654
655  /**
656   * Provides the default host name that will be proposed to the user for the
657   * local host.
658   * @return the default host name that will be proposed to the user for the
659   * local host.
660   */
661  public static String getDefaultHostName()
662  {
663    if (defaultHostName == null)
664    {
665      // Run a thread in the background in order to avoid blocking the
666      // application if reverse DNS lookups take a long time.
667      final CountDownLatch latch = new CountDownLatch(1);
668      Thread t = new Thread(new Runnable()
669      {
670        /**
671         * Search for a host name of the form host.example.com on each
672         * interface, except the loop back. Prefer interfaces of the form ethX.
673         */
674        @Override
675        public void run()
676        {
677          try
678          {
679            SortedMap<String, String> hostNames = new TreeMap<>();
680            Enumeration<NetworkInterface> i = NetworkInterface
681                .getNetworkInterfaces();
682            while (i.hasMoreElements())
683            {
684              NetworkInterface n = i.nextElement();
685
686              // Skip loop back interface.
687              if (n.isLoopback())
688              {
689                continue;
690              }
691
692              // Check each interface address (IPv4 and IPv6).
693              String ipv4HostName = null;
694              String ipv6HostName = null;
695              Enumeration<InetAddress> j = n.getInetAddresses();
696              while (j.hasMoreElements())
697              {
698                InetAddress address = j.nextElement();
699                String hostAddress = address.getHostAddress();
700                String hostName = address.getCanonicalHostName();
701
702                // Ignore hostnames which are IP addresses.
703                if (!hostAddress.equals(hostName))
704                {
705                  if (address instanceof Inet4Address)
706                  {
707                    ipv4HostName = hostName;
708                  }
709                  else if (address instanceof Inet6Address)
710                  {
711                    ipv6HostName = hostName;
712                  }
713                }
714              }
715
716              // Remember the host name if it looks fully qualified.
717              String fqHostName = null;
718              if (ipv4HostName != null && ipv4HostName.contains("."))
719              {
720                fqHostName = ipv4HostName;
721              }
722              else if (ipv6HostName != null && ipv6HostName.contains("."))
723              {
724                fqHostName = ipv6HostName;
725              }
726
727              if (fqHostName != null)
728              {
729                hostNames.put(n.getName(), fqHostName);
730
731                // This looks like a fully qualified name on a ethX interface,
732                // so
733                // use that and break out.
734                if (n.getName().startsWith("eth"))
735                {
736                  defaultHostName = fqHostName;
737                  break;
738                }
739              }
740            }
741
742            if (defaultHostName == null && !hostNames.isEmpty())
743            {
744              // No ethX host name, so try any other host name that was found.
745              defaultHostName = hostNames.values().iterator().next();
746            }
747          }
748          catch (Exception e)
749          {
750            // Ignore - we'll default to the loopback address later.
751          }
752
753          latch.countDown();
754        }
755      });
756
757      try
758      {
759        t.setDaemon(true);
760        t.start();
761        latch.await(1, TimeUnit.SECONDS);
762      }
763      catch (Exception e)
764      {
765        // Ignore - we'll default to the loopback address later.
766      }
767
768      if (defaultHostName == null)
769      {
770        // No host names found, so use the loop back.
771        try
772        {
773          defaultHostName = InetAddress.getLocalHost().getHostName();
774        }
775        catch (Exception e)
776        {
777          // Not much we can do here.
778          defaultHostName = "localhost";
779        }
780      }
781    }
782    return defaultHostName;
783  }
784
785  /**
786   * Returns a Map containing as key a ServerDescriptor and as value an Integer
787   * corresponding to the Replication Port chosen by the user.
788   *
789   * Only the servers that have no replication port appear on this map.
790   * @return a Map containing as key a ServerDescriptor and as value an
791   * AuthenticationData corresponding to the Replication Port chosen by the
792   * user.
793   */
794  public Map<ServerDescriptor, AuthenticationData> getRemoteWithNoReplicationPort()
795  {
796    return new HashMap<>(remoteWithNoReplicationPort);
797  }
798
799  /**
800   * Sets a the Replication Ports chosen by the user in the remote servers.
801   * @param remoteWithNoReplicationPort the Map containing as key a
802   * ServerDescriptor and as value an AuthenticationData corresponding to the
803   * Replication Port chosen by the user.
804   */
805  public void setRemoteWithNoReplicationPort(
806      Map<ServerDescriptor, AuthenticationData> remoteWithNoReplicationPort)
807  {
808    this.remoteWithNoReplicationPort.clear();
809    this.remoteWithNoReplicationPort.putAll(remoteWithNoReplicationPort);
810  }
811
812  /**
813   * Returns the different script names for which there are java arguments.
814   * @return the different script names for which there are java arguments.
815   */
816  public Set<String> getScriptNamesForJavaArguments()
817  {
818    return hmJavaArguments.keySet();
819  }
820
821  /**
822   * Returns the java arguments associated with a script name.  Returns
823   * <CODE>null</CODE> if no java arguments are defined.
824   * @param scriptName the script name.
825   * @return the java arguments associated with a script name.
826   */
827  public JavaArguments getJavaArguments(String scriptName)
828  {
829    return hmJavaArguments.get(scriptName);
830  }
831
832  /**
833   * Returns the default java arguments associated with a script name.  Returns
834   * <CODE>null</CODE> if no java arguments are defined.
835   * @param scriptName the script name.
836   * @return the default java arguments associated with a script name.
837   */
838  public JavaArguments getDefaultJavaArguments(String scriptName)
839  {
840    return hmDefaultJavaArguments.get(scriptName);
841  }
842
843  /**
844   * Sets the java arguments associated with a script name.
845   * @param scriptName the script name.
846   * @param args the java arguments associated with a script name.
847   */
848  public void setJavaArguments(String scriptName, JavaArguments args)
849  {
850    hmJavaArguments.put(scriptName, args);
851  }
852
853
854
855  private void createDefaultJavaArguments()
856  {
857    hmJavaArguments = new HashMap<>();
858    int maxMemoryMb = 256;
859    int minMemoryMb = 128;
860    final int maxMemoryBytes = maxMemoryMb * 1024 * 1024;
861    // If the current max memory is bigger than the max heap we want to set,
862    // assume that the JVM ergonomics are going to be able to allocate enough
863    // memory.
864    long currentMaxMemoryBytes = Runtime.getRuntime().maxMemory();
865    if (currentMaxMemoryBytes > maxMemoryBytes)
866    {
867      maxMemoryMb = -1;
868      minMemoryMb = -1;
869    }
870    for (String clientScript : getClientScripts())
871    {
872      JavaArguments javaArgument = new JavaArguments();
873      javaArgument.setInitialMemory(8);
874      javaArgument.setAdditionalArguments(new String[] {"-client"});
875      hmJavaArguments.put(clientScript, javaArgument);
876    }
877    for (String serverScript : getServerScripts())
878    {
879      JavaArguments javaArgument = new JavaArguments();
880      javaArgument.setInitialMemory(minMemoryMb);
881      javaArgument.setMaxMemory(maxMemoryMb);
882      javaArgument.setAdditionalArguments(new String[] {"-server"});
883      hmJavaArguments.put(serverScript, javaArgument);
884    }
885
886    JavaArguments controlPanelJavaArgument = new JavaArguments();
887    controlPanelJavaArgument.setInitialMemory(64);
888    controlPanelJavaArgument.setMaxMemory(128);
889    controlPanelJavaArgument.setAdditionalArguments(new String[] {"-client"});
890    hmJavaArguments.put("control-panel", controlPanelJavaArgument);
891
892    hmDefaultJavaArguments = new HashMap<>(hmJavaArguments);
893  }
894
895  private String[] getClientScripts()
896  {
897    return new String[] {
898      "backup.online", "base64", "create-rc-script", "dsconfig",
899      "dsreplication", "export-ldif.online",
900      "import-ldif.online", "ldapcompare", "ldapdelete",
901      "ldapmodify", "ldappasswordmodify", "ldapsearch", "list-backends",
902      "manage-account", "manage-tasks", "restore.online", "stop-ds",
903      "status", "uninstall", "setup"
904    };
905  }
906
907  private String[] getServerScripts()
908  {
909    return new String[]
910    {
911        "backup.offline", "dsreplication.offline",
912        "encode-password", "export-ldif.offline",
913        IMPORT_SCRIPT_NAME, "ldif-diff", "ldifmodify", "ldifsearch",
914        "make-ldif", "rebuild-index", "restore.offline", SERVER_SCRIPT_NAME,
915        "upgrade", "verify-index", "backendstat"
916    };
917  }
918
919  /**
920   * Sets the timeout to be used to establish a connection.
921   * @param connectTimeout the timeout to be used to establish a connection.
922   */
923  public void setConnectTimeout(int connectTimeout)
924  {
925    this.connectTimeout = connectTimeout;
926  }
927
928  /**
929   * Returns the timeout to be used to connect in milliseconds.
930   * @return the timeout to be used to connect in milliseconds.  Returns
931   * {@code 0} if there is no timeout.
932   */
933  public int getConnectTimeout()
934  {
935    return connectTimeout;
936  }
937}