001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.ui;
028
029import static org.opends.messages.AdminToolMessages.*;
030import static org.opends.server.util.CollectionUtils.*;
031
032import static com.forgerock.opendj.util.OperatingSystem.isWindows;
033
034import java.awt.Component;
035import java.awt.GridBagConstraints;
036import java.awt.GridBagLayout;
037import java.awt.event.ActionEvent;
038import java.awt.event.ActionListener;
039import java.io.BufferedReader;
040import java.io.BufferedWriter;
041import java.io.File;
042import java.io.FileReader;
043import java.io.FileWriter;
044import java.io.IOException;
045import java.util.ArrayList;
046import java.util.Collection;
047import java.util.Comparator;
048import java.util.HashSet;
049import java.util.List;
050import java.util.Properties;
051import java.util.Set;
052import java.util.TreeSet;
053
054import javax.swing.ButtonGroup;
055import javax.swing.JButton;
056import javax.swing.JCheckBox;
057import javax.swing.JComponent;
058import javax.swing.JEditorPane;
059import javax.swing.JLabel;
060import javax.swing.JPanel;
061import javax.swing.JRadioButton;
062import javax.swing.JScrollPane;
063import javax.swing.JSeparator;
064import javax.swing.JTable;
065import javax.swing.JTextField;
066import javax.swing.SwingUtilities;
067
068import org.forgerock.i18n.LocalizableMessage;
069import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
070import org.opends.guitools.controlpanel.datamodel.SortableTableModel;
071import org.opends.guitools.controlpanel.event.BrowseActionListener;
072import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
073import org.opends.guitools.controlpanel.task.Task;
074import org.opends.guitools.controlpanel.ui.components.LabelWithHelpIcon;
075import org.opends.guitools.controlpanel.ui.renderer.AttributeCellEditor;
076import org.opends.guitools.controlpanel.ui.renderer.LDAPEntryTableCellRenderer;
077import org.opends.guitools.controlpanel.util.BackgroundTask;
078import org.opends.guitools.controlpanel.util.Utilities;
079import org.opends.quicksetup.Installation;
080import org.opends.quicksetup.util.Utils;
081import org.opends.server.tools.JavaPropertiesTool;
082import org.opends.server.types.OpenDsException;
083import org.opends.server.util.SetupUtils;
084import org.opends.server.util.StaticUtils;
085
086/**
087 * The panel where the user can specify the java arguments and java home to be
088 * used in the command-lines.
089 */
090public class JavaPropertiesPanel extends StatusGenericPanel
091{
092  private static final long serialVersionUID = -7886215660289880597L;
093  private JTextField javaHome;
094  private JRadioButton useOpenDSJavaHome;
095  private JRadioButton useSpecifiedJavaHome;
096  private JButton browse;
097  private JLabel lJavaHome;
098
099  private JRadioButton useOpenDSJavaArgs;
100  private JRadioButton useSpecifiedJavaArgs;
101  private JLabel lJavaArgs;
102  private JTable argumentsTable;
103  private JavaArgumentsTableModel argumentsTableModel;
104  private JScrollPane argumentsScroll;
105
106  private AttributeCellEditor editor;
107
108  private JEditorPane lInitContents;
109
110  private JCheckBox showAll;
111
112  private Set<JavaArgumentsDescriptor> readJavaArguments = new HashSet<>();
113  private Set<JavaArgumentsDescriptor> currentJavaArguments = new HashSet<>();
114  private Set<String> allScriptNames = newHashSet(
115        "start-ds", "import-ldif.offline", "backup.online", "base64",
116        "create-rc-script", "dsconfig", "dsreplication",
117        "export-ldif.online", "import-ldif.online", "ldapcompare",
118        "ldapdelete", "ldapmodify", "ldappasswordmodify", "ldapsearch",
119        "list-backends", "manage-account", "manage-tasks", "restore.online",
120        "stop-ds", "status", "control-panel", "uninstall", "setup",
121        "backup.offline", "encode-password", "export-ldif.offline",
122        "ldif-diff", "ldifmodify", "ldifsearch", "make-ldif",
123        "rebuild-index", "restore.offline", "upgrade",
124        "verify-index", "dbtest"
125      );
126  private Set<String> relevantScriptNames = newHashSet(
127        "start-ds", "import-ldif.offline", "backup.offline",
128        "export-ldif.offline",
129        "ldif-diff", "make-ldif", "rebuild-index", "restore.offline",
130        "verify-index", "dbtest"
131      );
132
133  private String readJavaHome;
134  private boolean readUseOpenDSJavaHome;
135  private boolean readUseOpenDSJavaArgs;
136
137  private boolean initialized;
138
139  private boolean previousLocal = true;
140
141  private LocalizableMessage READING_JAVA_SETTINGS =
142    INFO_CTRL_PANEL_READING_JAVA_SETTINGS_SUMMARY.get();
143
144  JComponent[] comps;
145
146  /**
147   * Default constructor.
148   *
149   */
150  public JavaPropertiesPanel()
151  {
152    super();
153    createLayout();
154  }
155
156  /** {@inheritDoc} */
157  @Override
158  public LocalizableMessage getTitle()
159  {
160    return INFO_CTRL_PANEL_JAVA_PROPERTIES_TITLE.get();
161  }
162
163  /** {@inheritDoc} */
164  @Override
165  public Component getPreferredFocusComponent()
166  {
167    return javaHome;
168  }
169
170  /** {@inheritDoc} */
171  @Override
172  public boolean requiresScroll()
173  {
174    return false;
175  }
176
177  /** {@inheritDoc} */
178  @Override
179  public void setInfo(ControlPanelInfo info)
180  {
181    super.setInfo(info);
182    if (editor != null)
183    {
184      editor.setInfo(info);
185    }
186  }
187
188  /**
189   * Creates the layout of the panel (but the contents are not populated here).
190   */
191  private void createLayout()
192  {
193    GridBagConstraints gbc = new GridBagConstraints();
194
195    lJavaHome = Utilities.createPrimaryLabel(
196        INFO_CTRL_PANEL_JAVA_HOME_LABEL.get());
197    useOpenDSJavaHome = Utilities.createRadioButton(LocalizableMessage.EMPTY);
198    useOpenDSJavaHome.setOpaque(false);
199    useOpenDSJavaHome.getAccessibleContext().setAccessibleName(
200        INFO_CTRL_PANEL_USE_OPENDS_JAVA_HOME.get()+" "+
201        INFO_CTRL_PANEL_USE_OPENDS_JAVA_HOME_HELP.get());
202    lJavaHome.setLabelFor(useOpenDSJavaHome);
203    gbc.gridx = 0;
204    gbc.gridy = 0;
205    gbc.weightx = 0.0;
206    gbc.anchor = GridBagConstraints.WEST;
207    gbc.gridwidth = 1;
208    add(lJavaHome, gbc);
209    gbc.insets.left = 10;
210    gbc.gridx ++;
211    add(useOpenDSJavaHome, gbc);
212    gbc.gridwidth = 3;
213    gbc.gridx ++;
214    LabelWithHelpIcon useOpenDSJavaHomeLabel =
215      new LabelWithHelpIcon(INFO_CTRL_PANEL_USE_OPENDS_JAVA_HOME.get(),
216          INFO_CTRL_PANEL_USE_OPENDS_JAVA_HOME_HELP.get());
217    gbc.insets.left = 0;
218    add(useOpenDSJavaHomeLabel, gbc);
219
220    gbc.gridx = 1;
221    gbc.gridy ++;
222    gbc.fill = GridBagConstraints.HORIZONTAL;
223    gbc.weightx = 0.0;
224    gbc.insets.top = 10;
225    gbc.gridwidth = 1;
226    useSpecifiedJavaHome = Utilities.createRadioButton(LocalizableMessage.EMPTY);
227    useSpecifiedJavaHome.setOpaque(false);
228    useSpecifiedJavaHome.getAccessibleContext().setAccessibleName(
229        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_HOME.get() +
230        " "+INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_HOME_HELP.get());
231    useOpenDSJavaHomeLabel.setLabelFor(useSpecifiedJavaHome);
232    LabelWithHelpIcon useSpecifiedJavaHomeLabel = new LabelWithHelpIcon(
233        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_HOME.get(),
234        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_HOME_HELP.get());
235    gbc.insets.left = 10;
236    add(useSpecifiedJavaHome, gbc);
237    gbc.gridx ++;
238    gbc.insets.left = 0;
239    add(useSpecifiedJavaHomeLabel, gbc);
240    gbc.gridx ++;
241    javaHome = Utilities.createTextField();
242    useSpecifiedJavaHomeLabel.setLabelFor(javaHome);
243    gbc.weightx = 1.0;
244    gbc.insets.left = 5;
245    add(javaHome, gbc);
246    gbc.weightx = 0.0;
247    browse = Utilities.createButton(INFO_CTRL_PANEL_BROWSE_BUTTON_LABEL.get());
248    browse.addActionListener(
249        new BrowseActionListener(javaHome,
250            BrowseActionListener.BrowseType.LOCATION_DIRECTORY,  this));
251    browse.setOpaque(false);
252    gbc.gridx ++;
253    add(browse, gbc);
254
255    ButtonGroup group = new ButtonGroup();
256    group.add(useSpecifiedJavaHome);
257    group.add(useOpenDSJavaHome);
258
259    gbc.insets.top = 10;
260    gbc.insets.left = 0;
261    gbc.gridx = 0;
262    gbc.gridwidth = 5;
263    gbc.gridy ++;
264    add(new JSeparator(), gbc);
265
266    gbc.gridy ++;
267    JPanel p = new JPanel(new GridBagLayout());
268    p.setOpaque(false);
269    gbc.weightx = 1.0;
270    gbc.weighty = 1.0;
271    gbc.fill = GridBagConstraints.BOTH;
272    add(p, gbc);
273
274    gbc.insets.top = 10;
275    gbc.weightx = 0.0;
276    gbc.weighty = 0.0;
277    gbc.gridx = 0;
278    gbc.gridy = 0;
279
280    lJavaArgs = Utilities.createPrimaryLabel(
281        INFO_CTRL_PANEL_JAVA_ARGUMENTS_LABEL.get());
282    useSpecifiedJavaArgs = Utilities.createRadioButton(LocalizableMessage.EMPTY);
283    useSpecifiedJavaArgs.getAccessibleContext().setAccessibleName(
284        INFO_CTRL_PANEL_USE_OPENDS_JAVA_ARGS.get() +
285        " "+INFO_CTRL_PANEL_USE_OPENDS_JAVA_ARGS_HELP.get());
286    useSpecifiedJavaArgs.setOpaque(false);
287    useOpenDSJavaArgs = Utilities.createRadioButton(LocalizableMessage.EMPTY);
288    useOpenDSJavaArgs.setOpaque(false);
289    lJavaArgs.setLabelFor(useOpenDSJavaArgs);
290    gbc.gridx = 0;
291    gbc.gridy = 0;
292    gbc.gridwidth = 1;
293    gbc.fill = GridBagConstraints.HORIZONTAL;
294    gbc.weightx = 0.0;
295    gbc.insets.top = 10;
296    p.add(lJavaArgs, gbc);
297    gbc.insets.left = 10;
298    gbc.gridx ++;
299    gbc.gridwidth = 1;
300    p.add(useOpenDSJavaArgs, gbc);
301    gbc.gridx ++;
302    LabelWithHelpIcon useOpenDSJavaArgsLabel = new LabelWithHelpIcon(
303        INFO_CTRL_PANEL_USE_OPENDS_JAVA_ARGS.get(),
304        INFO_CTRL_PANEL_USE_OPENDS_JAVA_ARGS_HELP.get());
305    gbc.insets.left = 0;
306    p.add(useOpenDSJavaArgsLabel, gbc);
307
308    gbc.gridx = 1;
309    gbc.gridy ++;
310    gbc.insets.top = 10;
311    gbc.insets.left = 10;
312    p.add(useSpecifiedJavaArgs, gbc);
313    useOpenDSJavaArgsLabel.setLabelFor(useSpecifiedJavaArgs);
314    useSpecifiedJavaArgs.getAccessibleContext().setAccessibleName(
315        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_ARGS.get() +
316        " "+INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_ARGS_HELP.get());
317
318    gbc.gridx ++;
319    LabelWithHelpIcon useSpecifiedJavaArgsLabel = new LabelWithHelpIcon(
320        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_ARGS.get(),
321        INFO_CTRL_PANEL_USE_SPECIFIED_OPENDS_JAVA_ARGS_HELP.get());
322    gbc.insets.left = 0;
323    p.add(useSpecifiedJavaArgsLabel, gbc);
324
325    group = new ButtonGroup();
326    group.add(useSpecifiedJavaArgs);
327    group.add(useOpenDSJavaArgs);
328    useSpecifiedJavaArgsLabel.setLabelFor(useOpenDSJavaArgs);
329
330    argumentsTableModel = new JavaArgumentsTableModel();
331    LDAPEntryTableCellRenderer renderer = new LDAPEntryTableCellRenderer();
332    argumentsTable = Utilities.createSortableTable(argumentsTableModel,
333        renderer);
334    editor = new AttributeCellEditor();
335    if (getInfo() != null)
336    {
337      editor.setInfo(getInfo());
338    }
339    argumentsTable.getColumnModel().getColumn(1).setCellEditor(editor);
340    renderer.setTable(argumentsTable);
341
342    gbc.weightx = 1.0;
343    gbc.weighty = 1.0;
344    gbc.gridx = 1;
345    gbc.insets.top = 10;
346    gbc.gridy ++;
347    gbc.fill = GridBagConstraints.BOTH;
348    gbc.gridwidth = 2;
349    argumentsScroll = Utilities.createScrollPane(argumentsTable);
350    p.add(argumentsScroll, gbc);
351    lInitContents = Utilities.makePlainTextPane(
352        READING_JAVA_SETTINGS.toString(),
353        ColorAndFontConstants.defaultFont);
354    gbc.fill = GridBagConstraints.NONE;
355    gbc.anchor = GridBagConstraints.CENTER;
356    p.add(lInitContents, gbc);
357    lInitContents.setVisible(false);
358    gbc.weightx = 0.0;
359    gbc.weighty = 0.0;
360    gbc.fill = GridBagConstraints.HORIZONTAL;
361    gbc.weightx = 1.0;
362    gbc.anchor = GridBagConstraints.WEST;
363
364    showAll =
365      Utilities.createCheckBox(INFO_CTRL_PANEL_DISPLAY_ALL_COMMAND_LINES.get());
366    showAll.addActionListener(new ActionListener()
367    {
368      @Override
369      public void actionPerformed(ActionEvent ev)
370      {
371        editor.stopCellEditing();
372        currentJavaArguments = getCurrentJavaArguments();
373        argumentsTableModel.setData(filterJavaArguments(currentJavaArguments));
374        Utilities.updateTableSizes(argumentsTable, 7);
375      }
376    });
377
378    gbc.gridy ++;
379    gbc.insets.top = 5;
380    p.add(showAll, gbc);
381
382    JLabel inlineHelp = Utilities.createInlineHelpLabel(
383        INFO_CTRL_PANEL_ONLINE_COMMAND_HELP.get());
384    gbc.insets.top = 3;
385    gbc.gridy ++;
386    p.add(inlineHelp, gbc);
387
388    inlineHelp = Utilities.createInlineHelpLabel(
389        INFO_CTRL_PANEL_OFFLINE_COMMAND_HELP.get());
390    gbc.gridy ++;
391    p.add(inlineHelp, gbc);
392
393    // Just to create space.
394    Set<JavaArgumentsDescriptor> fakeArguments = new HashSet<>();
395    fakeArguments.add(
396        new JavaArgumentsDescriptor("start-ds", "-server -XM256j"));
397    fakeArguments.add(
398        new JavaArgumentsDescriptor("stop-ds", "-client"));
399    fakeArguments.add(
400        new JavaArgumentsDescriptor("import-ds.online", "-server"));
401    fakeArguments.add(
402        new JavaArgumentsDescriptor("import-ds.offline", "-server"));
403    fakeArguments.add(
404        new JavaArgumentsDescriptor("export-ds.online", "-server"));
405
406    argumentsTableModel.setData(fakeArguments);
407    Utilities.updateTableSizes(argumentsTable, 7);
408
409    comps = new JComponent[] {
410        javaHome, useOpenDSJavaHome, useSpecifiedJavaHome, browse,
411        useOpenDSJavaArgs, useSpecifiedJavaArgs, showAll
412    };
413  }
414
415  /** {@inheritDoc} */
416  @Override
417  public void configurationChanged(ConfigurationChangeEvent ev)
418  {
419    final boolean isLocal = ev.getNewDescriptor().isLocal();
420    if (isLocal != previousLocal)
421    {
422      previousLocal = isLocal;
423      SwingUtilities.invokeLater(new Runnable()
424      {
425        /** {@inheritDoc} */
426        @Override
427        public void run()
428        {
429          if (!isLocal)
430          {
431            displayErrorMessage(INFO_CTRL_PANEL_SERVER_REMOTE_SUMMARY.get(),
432            INFO_CTRL_PANEL_SERVER_MUST_BE_LOCAL_JAVA_PROPERTIES_SUMMARY.get());
433            setEnabledOK(false);
434          }
435          else
436          {
437            displayMainPanel();
438            setEnabledOK(true);
439          }
440        }
441      });
442    }
443  }
444
445  /** {@inheritDoc} */
446  @Override
447  public void toBeDisplayed(boolean visible)
448  {
449    boolean isLocal = true;
450    if (getInfo() != null)
451    {
452      isLocal = getInfo().getServerDescriptor().isLocal();
453    }
454    if (visible && isLocal && (!initialized || !updatedByUser()))
455    {
456      initialized = true;
457      initContents();
458    }
459  }
460
461  /**
462   * Returns the names of all the command-line that can be displayed by this
463   * panel.
464   * @return the names of all the command-line that can be displayed by this
465   * panel.
466   */
467  protected Set<String> getAllCommandLineNames()
468  {
469    return allScriptNames;
470  }
471
472  /**
473   * Returns the names of the most important command-line to be displayed by
474   * this panel.
475   * @return the names of the most important command-line to be displayed by
476   * this panel.
477   */
478  protected Set<String> getRelevantCommandLineNames()
479  {
480    return relevantScriptNames;
481  }
482
483
484
485  /**
486   * Returns <CODE>true</CODE> if the user updated the contents and
487   * <CODE>false</CODE> otherwise.
488   * @return <CODE>true</CODE> if the user updated the contents and
489   * <CODE>false</CODE> otherwise.
490   */
491  private boolean updatedByUser()
492  {
493    return !javaHome.getText().equals(readJavaHome)
494        || useOpenDSJavaHome.isSelected() != readUseOpenDSJavaHome
495        || useOpenDSJavaArgs.isSelected() != readUseOpenDSJavaArgs
496        || !readJavaArguments.equals(getCurrentJavaArguments());
497  }
498
499  /**
500   * Returns the java arguments specified by the user.
501   * @return the java arguments specified by the user.
502   */
503  private Set<JavaArgumentsDescriptor> getCurrentJavaArguments()
504  {
505    HashSet<JavaArgumentsDescriptor> args = new HashSet<>(currentJavaArguments);
506
507    HashSet<JavaArgumentsDescriptor> tableArgs = new HashSet<>();
508    for (int i=0; i<argumentsTableModel.getRowCount(); i++)
509    {
510      tableArgs.add(argumentsTableModel.getJavaArguments(i));
511    }
512    for (JavaArgumentsDescriptor arg : tableArgs)
513    {
514      JavaArgumentsDescriptor foundJavaArgument = null;
515      for (JavaArgumentsDescriptor arg1 : args)
516      {
517        if (arg1.getCommandName().equals(arg.getCommandName()))
518        {
519          foundJavaArgument = arg1;
520          break;
521        }
522      }
523      if (foundJavaArgument != null)
524      {
525        args.remove(foundJavaArgument);
526      }
527      args.add(arg);
528    }
529    return args;
530  }
531
532
533  /**
534   * Filters the provided list of java arguments depending on the showing
535   * options (basically whether the 'Show All Command-lines' is selected or
536   * not).
537   * @param args the list of java arguments.
538   * @return a list of filtered java arguments (the ones that must be displayed
539   * in the table).
540   */
541  private Set<JavaArgumentsDescriptor> filterJavaArguments(
542      Set<JavaArgumentsDescriptor> args)
543  {
544    if (showAll.isSelected())
545    {
546      return args;
547    }
548    else
549    {
550      Set<JavaArgumentsDescriptor> filteredArgs = new HashSet<>();
551      for (String relevantName : getRelevantCommandLineNames())
552      {
553        for (JavaArgumentsDescriptor arg : args)
554        {
555          if (arg.getCommandName().equals(relevantName))
556          {
557            filteredArgs.add(arg);
558            break;
559          }
560        }
561      }
562      return filteredArgs;
563    }
564  }
565
566  /**
567   * Inits the contents of the table in the background.
568   *
569   */
570  private void initContents()
571  {
572    disableComponents();
573
574    BackgroundTask<Void> worker = new BackgroundTask<Void>()
575    {
576      /** {@inheritDoc} */
577      @Override
578      public Void processBackgroundTask() throws Throwable
579      {
580        String propertiesFile = getPropertiesFile();
581        Properties properties = new Properties();
582        BufferedReader reader = null;
583        try
584        {
585          reader = new BufferedReader(new FileReader(propertiesFile));
586          JavaPropertiesTool.updateProperties(reader, properties);
587        }
588        catch (Throwable t)
589        {
590        }
591        finally
592        {
593          StaticUtils.close(reader);
594        }
595
596        String v = properties.getProperty("overwrite-env-java-home");
597        readUseOpenDSJavaHome = v == null || "false".equalsIgnoreCase(v.trim());
598        v = properties.getProperty("overwrite-env-java-args");
599        readUseOpenDSJavaArgs = v == null || "false".equalsIgnoreCase(v.trim());
600
601        readJavaHome = properties.getProperty("default.java-home");
602        if (readJavaHome == null)
603        {
604          for (String script : getAllCommandLineNames())
605          {
606            readJavaHome = properties.getProperty(script+".java-home");
607            if (readJavaHome != null)
608            {
609              break;
610            }
611          }
612        }
613
614        readJavaArguments.clear();
615        for (String script : getAllCommandLineNames())
616        {
617          v = properties.getProperty(script+".java-args");
618          if (v != null)
619          {
620            readJavaArguments.add(new JavaArgumentsDescriptor(script, v));
621          }
622          else
623          {
624            readJavaArguments.add(new JavaArgumentsDescriptor(script, ""));
625          }
626        }
627
628        return null;
629      }
630
631      /** {@inheritDoc} */
632      @Override
633      public void backgroundTaskCompleted(Void returnValue, Throwable t)
634      {
635        if (t == null)
636        {
637          updateContentsOfPanelWithReadValues();
638          Utilities.updateTableSizes(argumentsTable, 7);
639        }
640        else
641        {
642          String arg;
643          if (t instanceof OpenDsException)
644          {
645            arg = ((OpenDsException)t).getMessageObject().toString();
646          }
647          else
648          {
649            arg = t.toString();
650          }
651          LocalizableMessage title =
652            ERR_CTRL_PANEL_ERR_READING_JAVA_SETTINGS_SUMMARY.get();
653          LocalizableMessage details =
654            ERR_CTRL_PANEL_READING_JAVA_SETTINGS_DETAILS.get(arg);
655          updateErrorPane(errorPane, title,
656              ColorAndFontConstants.errorTitleFont, details,
657              errorPane.getFont());
658          packParentDialog();
659          errorPane.setVisible(true);
660        }
661        enableComponents();
662      }
663    };
664    worker.startBackgroundTask();
665  }
666
667  /**
668   * Disables all the components.  This is used when we are reading the
669   * java settings in the background.
670   *
671   */
672  private void disableComponents()
673  {
674    setEnabledOK(false);
675    lInitContents.setVisible(true);
676    argumentsScroll.setVisible(false);
677    for (JComponent comp : comps)
678    {
679      comp.setEnabled(false);
680    }
681  }
682
683  /**
684   * Enables all the components.  This is used when we are reading the
685   * java settings in the background.
686   *
687   */
688  private void enableComponents()
689  {
690    for (JComponent comp : comps)
691    {
692      comp.setEnabled(true);
693    }
694    lInitContents.setVisible(false);
695    argumentsScroll.setVisible(true);
696    setEnabledOK(true);
697  }
698
699  /** {@inheritDoc} */
700  @Override
701  public void cancelClicked()
702  {
703    updateContentsOfPanelWithReadValues();
704    super.cancelClicked();
705  }
706
707  /** {@inheritDoc} */
708  @Override
709  public void okClicked()
710  {
711    editor.stopCellEditing();
712
713    final ArrayList<LocalizableMessage> javaHomeErrors = new ArrayList<>();
714    String f = javaHome.getText().trim();
715    if (f.length() > 0)
716    {
717      File file = new File(f);
718      if (!file.exists())
719      {
720        javaHomeErrors.add(ERR_CTRL_PANEL_JAVA_PATH_DOES_NOT_EXIST.get(f));
721      }
722      else if (!file.isDirectory())
723      {
724        javaHomeErrors.add(ERR_CTRL_PANEL_JAVA_PATH_NOT_A_DIRECTORY.get(f));
725      }
726      else
727      {
728        File javaFile = getJavaFile(file);
729        if (!javaFile.exists())
730        {
731          javaHomeErrors.add(ERR_CTRL_PANEL_JAVA_BINARY_NOT_FOUND.get(javaFile));
732        }
733      }
734    }
735    if (javaHomeErrors.isEmpty())
736    {
737      final Set<String> providedArguments = new HashSet<>();
738      for (JavaArgumentsDescriptor cmd : getCurrentJavaArguments())
739      {
740        String args = cmd.getJavaArguments().trim();
741        if (args.length() > 0)
742        {
743          providedArguments.add(args);
744        }
745      }
746
747      disableComponents();
748      lInitContents.setText(
749          INFO_CTRL_PANEL_CHECKING_JAVA_OPTIONS_SUMMARY.get().toString());
750      BackgroundTask<List<LocalizableMessage>> worker =
751        new BackgroundTask<List<LocalizableMessage>>()
752      {
753        private boolean isConfirmation = false;
754        @Override
755        public List<LocalizableMessage> processBackgroundTask() throws Throwable
756        {
757          String[] jvms;
758          String userJVM = javaHome.getText();
759          ArrayList<LocalizableMessage> errorMessages = new ArrayList<>();
760          ArrayList<LocalizableMessage> confirmationMessages = new ArrayList<>();
761          String defaultJVM = System.getenv(SetupUtils.OPENDJ_JAVA_HOME);
762          if (defaultJVM == null)
763          {
764            defaultJVM = System.getProperty("java.home");
765          }
766          if (useSpecifiedJavaHome.isSelected())
767          {
768            jvms = new String[]{userJVM};
769          }
770          else if (userJVM != null && userJVM.trim().length() > 0)
771          {
772            jvms = new String[]{defaultJVM, userJVM};
773          }
774          else
775          {
776            jvms = new String[]{defaultJVM};
777          }
778          for (String jvm : jvms)
779          {
780            Set<String> notWorkingArgs = new HashSet<>();
781
782            String installPath = getInfo().getServerDescriptor().
783            getInstallPath();
784            if (!Utils.supportsOption("", jvm, installPath))
785            {
786              if (jvm == userJVM && !useSpecifiedJavaHome.isSelected())
787              {
788                errorMessages.add(
789                    ERR_CTRL_PANEL_NOT_WORKING_FALLBACK_JVM_DETAILS.get(jvm));
790              }
791              else
792              {
793                errorMessages.add(
794                    ERR_CTRL_PANEL_NOT_WORKING_JVM_DETAILS.get(jvm));
795              }
796            }
797            else
798            {
799              for (String arg : providedArguments)
800              {
801                if (!Utils.supportsOption(arg, jvm, installPath))
802                {
803                  notWorkingArgs.add(arg);
804                }
805              }
806            }
807            if (!notWorkingArgs.isEmpty())
808            {
809              File javaFile = getJavaFile(new File(jvm));
810              LocalizableMessage confirmationMessage;
811              if (useSpecifiedJavaArgs.isSelected())
812              {
813                confirmationMessage =
814                  INFO_CTRL_PANEL_CONFIRM_NOT_WORKING_ARGUMENTS_DETAILS.get(
815                    javaFile,
816                    Utilities.getStringFromCollection(notWorkingArgs, "<br>-"));
817              }
818              else
819              {
820                confirmationMessage =
821             INFO_CTRL_PANEL_CONFIRM_NOT_WORKING_FALLBACK_ARGUMENTS_DETAILS.get(
822                    javaFile,
823                    Utilities.getStringFromCollection(notWorkingArgs, "<br>-"));
824              }
825              confirmationMessages.add(confirmationMessage);
826            }
827          }
828          isConfirmation = errorMessages.isEmpty();
829          if (!errorMessages.isEmpty())
830          {
831            return errorMessages;
832          }
833          else
834          {
835            return confirmationMessages;
836          }
837        }
838
839        /** {@inheritDoc} */
840        @Override
841        public void backgroundTaskCompleted(List<LocalizableMessage> returnValue,
842            Throwable t)
843        {
844          if (t == null)
845          {
846            boolean confirm = false;
847            if (isConfirmation && !returnValue.isEmpty())
848            {
849              confirm = displayConfirmationDialog(
850                  INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
851                  returnValue.iterator().next());
852            }
853            else if (!isConfirmation && !returnValue.isEmpty())
854            {
855              displayErrorDialog(returnValue);
856            }
857            else
858            {
859              confirm = true;
860            }
861
862            if (confirm)
863            {
864              launchTask();
865            }
866          }
867          else
868          {
869            String arg;
870            if (t instanceof OpenDsException)
871            {
872              arg = ((OpenDsException)t).getMessageObject().toString();
873            }
874            else
875            {
876              arg = t.toString();
877            }
878            LocalizableMessage title =
879              ERR_CTRL_PANEL_ERROR_CHECKING_JAVA_SETTINGS_SUMMARY.get();
880            LocalizableMessage details =
881              ERR_CTRL_PANEL_ERROR_CHECKING_JAVA_SETTINGS_DETAILS.get(arg);
882            updateErrorPane(errorPane, title,
883                ColorAndFontConstants.errorTitleFont, details,
884                errorPane.getFont());
885            packParentDialog();
886            errorPane.setVisible(true);
887          }
888          enableComponents();
889          lInitContents.setText(READING_JAVA_SETTINGS.toString());
890        }
891      };
892      worker.startBackgroundTask();
893      return;
894    }
895    else
896    {
897      if (useSpecifiedJavaHome.isSelected())
898      {
899        displayErrorDialog(javaHomeErrors);
900      }
901      else
902      {
903        ArrayList<String> s = new ArrayList<>();
904        for (LocalizableMessage msg : javaHomeErrors)
905        {
906          s.add(msg.toString());
907        }
908        ArrayList<LocalizableMessage> msgs = new ArrayList<>();
909        LocalizableMessage msg = ERR_CTRL_PANEL_GENERIC_ERROR_FALLBACK_JAVAHOME.get(
910            f, Utilities.getStringFromCollection(s, "<br>-"));
911        msgs.add(msg);
912        displayErrorDialog(msgs);
913      }
914    }
915  }
916
917  /**
918   * Returns the java binary (the executable) for a given java home.
919   * @param javaHome the java home.
920   * @return the java binary (the executable) for the provided java home.
921   */
922  private File getJavaFile(File javaHome)
923  {
924    File javaFile = new File(javaHome, "bin");
925    if (isWindows())
926    {
927      javaFile = new File(javaFile, "java.exe");
928    }
929    else
930    {
931      javaFile = new File(javaFile, "java");
932    }
933    return javaFile;
934  }
935
936  private void launchTask()
937  {
938    ArrayList<LocalizableMessage> errors = new ArrayList<>();
939    ProgressDialog dlg = new ProgressDialog(
940        Utilities.createFrame(),
941        Utilities.getParentDialog(this),
942        INFO_CTRL_PANEL_JAVA_PROPERTIES_TITLE.get(), getInfo());
943    JavaPropertiesTask newTask = new JavaPropertiesTask(getInfo(), dlg);
944    for (Task task : getInfo().getTasks())
945    {
946      task.canLaunch(newTask, errors);
947    }
948    if (errors.isEmpty())
949    {
950      launchOperation(newTask,
951          INFO_CTRL_PANEL_UPDATING_JAVA_SETTINGS_SUMMARY.get(),
952          INFO_CTRL_PANEL_UPDATING_JAVA_SETTINGS_COMPLETE.get(),
953          INFO_CTRL_PANEL_UPDATING_JAVA_SETTINGS_SUCCESSFUL.get(),
954          ERR_CTRL_PANEL_UPDATING_JAVA_SETTINGS_ERROR_SUMMARY.get(),
955          ERR_CTRL_PANEL_UPDATING_JAVA_SETTINGS_ERROR_DETAILS.get(),
956          ERR_CTRL_PANEL_UPDATING_JAVA_SETTINGS_ERROR_CODE,
957          dlg);
958      dlg.setVisible(true);
959      Utilities.getParentDialog(this).setVisible(false);
960      readJavaHome = javaHome.getText();
961      readUseOpenDSJavaHome = useOpenDSJavaHome.isSelected();
962      readUseOpenDSJavaArgs = useOpenDSJavaArgs.isSelected();
963      readJavaArguments = getCurrentJavaArguments();
964    }
965    else
966    {
967      displayErrorDialog(errors);
968    }
969  }
970
971  /**
972   * Returns the file containing the java properties.
973   * @return the file containing the java properties.
974   */
975  private String getPropertiesFile()
976  {
977    String installPath = getInfo().getServerDescriptor().getInstancePath();
978    return Utils.getPath(
979      Utilities.getInstanceRootDirectory(installPath).getAbsolutePath(),
980      Installation.RELATIVE_JAVA_PROPERTIES_FILE);
981  }
982
983  private void updateContentsOfPanelWithReadValues()
984  {
985    if (readJavaHome != null)
986    {
987      javaHome.setText(readJavaHome);
988    }
989    else
990    {
991      javaHome.setText("");
992    }
993    useOpenDSJavaHome.setSelected(readUseOpenDSJavaHome);
994    useSpecifiedJavaHome.setSelected(!readUseOpenDSJavaHome);
995    useOpenDSJavaArgs.setSelected(readUseOpenDSJavaArgs);
996    useSpecifiedJavaArgs.setSelected(!readUseOpenDSJavaArgs);
997    currentJavaArguments.clear();
998    currentJavaArguments.addAll(readJavaArguments);
999    argumentsTableModel.setData(
1000        filterJavaArguments(currentJavaArguments));
1001  }
1002
1003  /**
1004   * Class containing the command-name and the associated java
1005   * arguments.
1006   *
1007   */
1008  private class JavaArgumentsDescriptor
1009  {
1010    private String commandName;
1011    private String javaArguments;
1012    private int hashCode;
1013    private String toString;
1014    /**
1015     * Constructor of the arguments descriptor.
1016     * @param commandName the command-line name.
1017     * @param javaArguments the java arguments.
1018     */
1019    public JavaArgumentsDescriptor(String commandName, String javaArguments)
1020    {
1021      this.commandName = commandName;
1022      this.javaArguments = javaArguments;
1023      hashCode = commandName.hashCode() + javaArguments.hashCode();
1024      toString = commandName+ ": " +javaArguments;
1025    }
1026
1027    /**
1028     * Returns the command-line name.
1029     * @return the command-line name.
1030     */
1031    public String getCommandName()
1032    {
1033      return commandName;
1034    }
1035    /**
1036     * Returns the java arguments associated with the command-line.
1037     * @return the java arguments associated with the command-line.
1038     */
1039    public String getJavaArguments()
1040    {
1041      return javaArguments;
1042    }
1043
1044    /** {@inheritDoc} */
1045    @Override
1046    public int hashCode()
1047    {
1048      return hashCode;
1049    }
1050
1051    /** {@inheritDoc} */
1052    @Override
1053    public String toString()
1054    {
1055      return toString;
1056    }
1057
1058    /** {@inheritDoc} */
1059    @Override
1060    public boolean equals(Object o)
1061    {
1062      if (o == this)
1063      {
1064        return true;
1065      }
1066      if (!(o instanceof JavaArgumentsDescriptor))
1067      {
1068        return false;
1069      }
1070      JavaArgumentsDescriptor desc = (JavaArgumentsDescriptor)o;
1071      return commandName.equals(desc.getCommandName())
1072          && javaArguments.equals(desc.getJavaArguments());
1073    }
1074  }
1075
1076  /**
1077   * The table model used to display the java arguments.
1078   */
1079  protected class JavaArgumentsTableModel extends SortableTableModel
1080  implements Comparator<JavaArgumentsDescriptor>
1081  {
1082    private static final long serialVersionUID = 8288418995255677560L;
1083    private Set<JavaArgumentsDescriptor> data = new HashSet<>();
1084    private ArrayList<String[]> dataArray = new ArrayList<>();
1085    private ArrayList<JavaArgumentsDescriptor> argsArray = new ArrayList<>();
1086    private final String[] COLUMN_NAMES = new String[] {
1087        getHeader(INFO_CTRL_PANEL_COMMAND_LINE_NAME_COLUMN.get(), 40),
1088        getHeader(INFO_CTRL_PANEL_JAVA_ARGUMENTS_COLUMN.get(), 40)};
1089    private int sortColumn;
1090    private boolean sortAscending = true;
1091
1092    /**
1093     * Sets the data for this table model.
1094     * @param newData the data for this table model.
1095     */
1096    public void setData(Set<JavaArgumentsDescriptor> newData)
1097    {
1098      if (!newData.equals(data))
1099      {
1100        data.clear();
1101        data.addAll(newData);
1102        updateDataArray();
1103        fireTableDataChanged();
1104      }
1105    }
1106
1107    /**
1108     * Compares two java argument descriptors.
1109     * @param desc1 the first java argument descriptor.
1110     * @param desc2 the second java argument descriptor.
1111     * @return 1 if in terms of comparison the first element goes higher than
1112     * the second one.  Returns 0 if both elements are equal in terms of
1113     * comparison.  Returns -1 if the second element goes higher than the first
1114     * one.
1115     */
1116    @Override
1117    public int compare(JavaArgumentsDescriptor desc1,
1118        JavaArgumentsDescriptor desc2)
1119    {
1120      int result;
1121      int[] possibleResults = {
1122          desc1.getCommandName().compareTo(desc2.getCommandName()),
1123          desc1.getJavaArguments().compareTo(desc2.getJavaArguments())};
1124      result = possibleResults[sortColumn];
1125      if (result == 0)
1126      {
1127        for (int i : possibleResults)
1128        {
1129          if (i != 0)
1130          {
1131            result = i;
1132            break;
1133          }
1134        }
1135      }
1136      if (!sortAscending)
1137      {
1138        result = -result;
1139      }
1140      return result;
1141    }
1142
1143    /**
1144     * Updates the table model contents and sorts its contents depending on the
1145     * sort options set by the user.
1146     */
1147    @Override
1148    public void forceResort()
1149    {
1150      updateDataArray();
1151      fireTableDataChanged();
1152    }
1153
1154
1155
1156    /** {@inheritDoc} */
1157    @Override
1158    public int getColumnCount()
1159    {
1160      return COLUMN_NAMES.length;
1161    }
1162
1163    /** {@inheritDoc} */
1164    @Override
1165    public int getRowCount()
1166    {
1167      return dataArray.size();
1168    }
1169
1170    /** {@inheritDoc} */
1171    @Override
1172    public Object getValueAt(int row, int col)
1173    {
1174      return dataArray.get(row)[col];
1175    }
1176
1177    /** {@inheritDoc} */
1178    @Override
1179    public String getColumnName(int col) {
1180      return COLUMN_NAMES[col];
1181    }
1182
1183    /**
1184     * Returns the java argument descriptor in the provided row.
1185     * @param row the row number.
1186     * @return the java argument descriptor in the provided row.
1187     */
1188    public JavaArgumentsDescriptor getJavaArguments(int row)
1189    {
1190      return argsArray.get(row);
1191    }
1192
1193
1194    /**
1195     * Returns whether the sort is ascending or descending.
1196     * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE>
1197     * otherwise.
1198     */
1199    @Override
1200    public boolean isSortAscending()
1201    {
1202      return sortAscending;
1203    }
1204
1205    /**
1206     * Sets whether to sort ascending of descending.
1207     * @param sortAscending whether to sort ascending or descending.
1208     */
1209    @Override
1210    public void setSortAscending(boolean sortAscending)
1211    {
1212      this.sortAscending = sortAscending;
1213    }
1214
1215    /**
1216     * Returns the column index used to sort.
1217     * @return the column index used to sort.
1218     */
1219    @Override
1220    public int getSortColumn()
1221    {
1222      return sortColumn;
1223    }
1224
1225    /**
1226     * Sets the column index used to sort.
1227     * @param sortColumn column index used to sort..
1228     */
1229    @Override
1230    public void setSortColumn(int sortColumn)
1231    {
1232      this.sortColumn = sortColumn;
1233    }
1234
1235    /** {@inheritDoc} */
1236    @Override
1237    public boolean isCellEditable(int row, int col) {
1238      return col != 0;
1239    }
1240
1241    /** {@inheritDoc} */
1242    @Override
1243    public void setValueAt(Object value, int row, int col)
1244    {
1245      dataArray.get(row)[col] = (String)value;
1246      JavaArgumentsDescriptor currentArg = argsArray.get(row);
1247      JavaArgumentsDescriptor newArg =
1248        new JavaArgumentsDescriptor(currentArg.getCommandName(), (String)value);
1249      argsArray.set(row, newArg);
1250      data.remove(currentArg);
1251      data.add(newArg);
1252      fireTableCellUpdated(row, col);
1253    }
1254
1255    private void updateDataArray()
1256    {
1257      TreeSet<JavaArgumentsDescriptor> sortedSet = new TreeSet<>(this);
1258      sortedSet.addAll(data);
1259      dataArray.clear();
1260      argsArray.clear();
1261      for (JavaArgumentsDescriptor arg : sortedSet)
1262      {
1263        String[] s = getLine(arg);
1264        dataArray.add(s);
1265        argsArray.add(arg);
1266      }
1267    }
1268
1269    /**
1270     * Returns an array of String with the String representation of the cells
1271     * in the table.
1272     * @param desc the java argument descriptor for which we want to get the
1273     * cells.
1274     * @return an array of String with the String representation of the cells
1275     * in the table.
1276     */
1277    protected String[] getLine(JavaArgumentsDescriptor desc)
1278    {
1279      String cmd = desc.getCommandName();
1280      if (cmd.equalsIgnoreCase("start-ds"))
1281      {
1282        cmd = INFO_CTRL_PANEL_SERVER_RUNTIME_CELL.get(
1283            desc.getCommandName()).toString();
1284      }
1285      else if (cmd.endsWith(".online"))
1286      {
1287        int index = cmd.lastIndexOf(".online");
1288        cmd = INFO_CTRL_PANEL_ONLINE_COMMAND_LINE_CELL.get(
1289            cmd.substring(0, index)).toString();
1290      }
1291      else if (desc.getCommandName().endsWith(".offline"))
1292      {
1293        int index = cmd.lastIndexOf(".offline");
1294        cmd = INFO_CTRL_PANEL_OFFLINE_COMMAND_LINE_CELL.get(
1295            cmd.substring(0, index)).toString();
1296      }
1297      return new String[] {cmd, desc.getJavaArguments()};
1298    }
1299  }
1300
1301  /**
1302   * The task in charge of updating the java properties.
1303   *
1304   */
1305  protected class JavaPropertiesTask extends Task
1306  {
1307    private Set<String> backendSet;
1308    private String defaultJavaHome;
1309    private boolean overwriteOpenDSJavaHome;
1310    private boolean overwriteOpenDSJavaArgs;
1311    Set<JavaArgumentsDescriptor> arguments = new HashSet<>();
1312
1313    /**
1314     * The constructor of the task.
1315     * @param info the control panel info.
1316     * @param dlg the progress dialog that shows the progress of the task.
1317     */
1318    public JavaPropertiesTask(ControlPanelInfo info, ProgressDialog dlg)
1319    {
1320      super(info, dlg);
1321      backendSet = new HashSet<>();
1322      defaultJavaHome = javaHome.getText().trim();
1323      overwriteOpenDSJavaHome = useSpecifiedJavaHome.isSelected();
1324      overwriteOpenDSJavaArgs = useSpecifiedJavaArgs.isSelected();
1325      arguments = getCurrentJavaArguments();
1326    }
1327
1328    /** {@inheritDoc} */
1329    @Override
1330    public Type getType()
1331    {
1332      return Type.JAVA_SETTINGS_UPDATE;
1333    }
1334
1335    /** {@inheritDoc} */
1336    @Override
1337    public Set<String> getBackends()
1338    {
1339      return backendSet;
1340    }
1341
1342    /** {@inheritDoc} */
1343    @Override
1344    public LocalizableMessage getTaskDescription()
1345    {
1346      return INFO_CTRL_PANEL_UPDATE_JAVA_SETTINGS_TASK_DESCRIPTION.get();
1347    }
1348
1349    /** {@inheritDoc} */
1350    @Override
1351    public boolean canLaunch(Task taskToBeLaunched,
1352        Collection<LocalizableMessage> incompatibilityReasons)
1353    {
1354      if (!isServerRunning()
1355          && state == State.RUNNING
1356          && runningOnSameServer(taskToBeLaunched))
1357      {
1358        // All the operations are incompatible if they apply to this
1359        // backend for safety.  This is a short operation so the limitation
1360        // has not a lot of impact.
1361        Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends());
1362        backends.retainAll(getBackends());
1363        if (!backends.isEmpty())
1364        {
1365          incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
1366          return false;
1367        }
1368      }
1369      return true;
1370    }
1371
1372    /** {@inheritDoc} */
1373    @Override
1374    protected String getCommandLinePath()
1375    {
1376      return null;
1377    }
1378
1379    /** {@inheritDoc} */
1380    @Override
1381    protected ArrayList<String> getCommandLineArguments()
1382    {
1383      return new ArrayList<>();
1384    }
1385
1386    /** {@inheritDoc} */
1387    @Override
1388    public void runTask()
1389    {
1390      state = State.RUNNING;
1391      lastException = null;
1392
1393      try
1394      {
1395        returnCode = updateJavaSettings();
1396        if (returnCode == 0)
1397        {
1398          state = State.FINISHED_SUCCESSFULLY;
1399        }
1400        else
1401        {
1402          state = State.FINISHED_WITH_ERROR;
1403        }
1404      }
1405      catch (Throwable t)
1406      {
1407        lastException = t;
1408        state = State.FINISHED_WITH_ERROR;
1409      }
1410    }
1411
1412    private int updateJavaSettings() throws IOException
1413    {
1414      final String propertiesFile = getPropertiesFile();
1415      ArrayList<String> commentLines = new ArrayList<>();
1416      BufferedReader reader = null;
1417      try
1418      {
1419        reader = new BufferedReader(new FileReader(propertiesFile));
1420        String line;
1421        while ((line = reader.readLine()) != null)
1422        {
1423          String trimmedLine = line.trim();
1424          if (trimmedLine.startsWith("#") || trimmedLine.length() == 0)
1425          {
1426            commentLines.add(line);
1427          }
1428          else
1429          {
1430            break;
1431          }
1432        }
1433      }
1434      catch (IOException ioe)
1435      {
1436        // Not critical.
1437      }
1438      finally
1439      {
1440        StaticUtils.close(reader);
1441      }
1442
1443      BufferedWriter writer = null;
1444      try
1445      {
1446        writer = new BufferedWriter(new FileWriter(propertiesFile, false));
1447        for (String comment : commentLines)
1448        {
1449          writer.write(comment);
1450          writer.newLine();
1451        }
1452        writer.newLine();
1453        writer.write("overwrite-env-java-home="+overwriteOpenDSJavaHome);
1454        writer.newLine();
1455        writer.write("overwrite-env-java-args="+overwriteOpenDSJavaArgs);
1456        writer.newLine();
1457        writer.newLine();
1458        if (defaultJavaHome != null && defaultJavaHome.length() > 0)
1459        {
1460          writer.write("default.java-home="+defaultJavaHome);
1461          writer.newLine();
1462          writer.newLine();
1463        }
1464        for (JavaArgumentsDescriptor desc : arguments)
1465        {
1466          String args = desc.getJavaArguments();
1467          if (args.trim().length() > 0)
1468          {
1469            writer.newLine();
1470            writer.write(desc.getCommandName()+".java-args="+args);
1471          }
1472        }
1473      }
1474      finally
1475      {
1476        StaticUtils.close(writer);
1477      }
1478      SwingUtilities.invokeLater(new Runnable()
1479      {
1480        /** {@inheritDoc} */
1481        @Override
1482        public void run()
1483        {
1484          getProgressDialog().appendProgressHtml(Utilities.applyFont(
1485              INFO_CTRL_PANEL_EQUIVALENT_ACTION_TO_UPDATE_JAVA_PROPERTIES.get(
1486                  propertiesFile, getCommandLinePath("dsjavaproperties")).
1487                  toString(),
1488              ColorAndFontConstants.progressFont));
1489        }
1490      });
1491
1492      // Launch the script
1493      String[] args =
1494      {
1495          "--quiet"
1496      };
1497
1498      return JavaPropertiesTool.mainCLI(args);
1499    }
1500  }
1501}