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-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027
028package org.opends.guitools.controlpanel.ui;
029
030import static org.opends.messages.AdminToolMessages.*;
031
032import java.awt.Component;
033import java.awt.Dimension;
034import java.awt.GridBagConstraints;
035import java.awt.event.ActionEvent;
036import java.awt.event.ActionListener;
037import java.util.ArrayList;
038import java.util.Collection;
039import java.util.HashSet;
040import java.util.LinkedHashSet;
041import java.util.Set;
042
043import javax.swing.Box;
044import javax.swing.JButton;
045import javax.swing.JEditorPane;
046import javax.swing.JLabel;
047import javax.swing.SwingUtilities;
048
049import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
050import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
051import org.opends.guitools.controlpanel.task.Task;
052import org.opends.guitools.controlpanel.util.Utilities;
053import org.forgerock.i18n.LocalizableMessage;
054import org.opends.server.tools.ConfigureWindowsService;
055
056/**
057 * The panel that displays the Windows Service panel configuration for the
058 * server.
059 *
060 */
061public class WindowsServicePanel extends StatusGenericPanel
062{
063  private static final long serialVersionUID = 6415350296295459469L;
064  private JLabel lState;
065  private JButton bEnable;
066  private JButton bDisable;
067
068  private boolean previousLocal = true;
069
070  private boolean isWindowsServiceEnabled;
071
072  /**
073   * Default constructor.
074   *
075   */
076  public WindowsServicePanel()
077  {
078    super();
079    createLayout();
080  }
081
082  /** {@inheritDoc} */
083  public LocalizableMessage getTitle()
084  {
085    return INFO_CTRL_PANEL_WINDOWS_SERVICE_TITLE.get();
086  }
087
088  /**
089   * Creates the layout of the panel (but the contents are not populated here).
090   */
091  private void createLayout()
092  {
093    GridBagConstraints gbc = new GridBagConstraints();
094    gbc.anchor = GridBagConstraints.WEST;
095    gbc.weightx = 0.0;
096    gbc.gridx = 0;
097    gbc.gridy = 0;
098    gbc.gridwidth = 4;
099    gbc.weightx = 1.0;
100    gbc.fill = GridBagConstraints.BOTH;
101
102    String text = INFO_CTRL_PANEL_WINDOWS_SERVICE_PANEL_TEXT.get().toString();
103
104    JEditorPane pane = Utilities.makeHtmlPane(text,
105        ColorAndFontConstants.defaultFont);
106
107    Utilities.updatePreferredSize(pane, 100, text,
108        ColorAndFontConstants.defaultFont, false);
109    gbc.weighty = 0.0;
110    add(pane, gbc);
111
112    gbc.gridy = 1;
113    gbc.gridwidth = 1;
114    gbc.weightx = 0.0;
115    gbc.weighty = 0.0;
116    JLabel lWindowsService =Utilities.createPrimaryLabel(
117        INFO_CTRL_PANEL_WINDOWS_SERVICE_INTEGRATION_LABEL.get());
118    gbc.insets.top = 10;
119    add(lWindowsService, gbc);
120    lState = Utilities.createDefaultLabel();
121    lState.setText(isWindowsServiceEnabled ?
122        INFO_ENABLED_LABEL.get().toString() :
123          INFO_DISABLED_LABEL.get().toString());
124    gbc.insets.left = 10;
125    gbc.gridx = 1;
126    add(lState, gbc);
127
128    bEnable = Utilities.createButton(
129        INFO_CTRL_PANEL_ENABLE_WINDOWS_SERVICE_BUTTON.get());
130    bDisable = Utilities.createButton(
131        INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON.get());
132    bEnable.setOpaque(false);
133    bDisable.setOpaque(false);
134    int maxWidth = Math.max(bEnable.getPreferredSize().width,
135        bDisable.getPreferredSize().width);
136    int maxHeight = Math.max(bEnable.getPreferredSize().height,
137        bDisable.getPreferredSize().height);
138    bEnable.setPreferredSize(new Dimension(maxWidth, maxHeight));
139    bDisable.setPreferredSize(new Dimension(maxWidth, maxHeight));
140
141    ActionListener listener = new ActionListener()
142    {
143      /** {@inheritDoc} */
144      public void actionPerformed(ActionEvent ev)
145      {
146        updateWindowsService();
147      }
148    };
149    bEnable.addActionListener(listener);
150    bDisable.addActionListener(listener);
151
152    gbc.gridx = 2;
153    add(bEnable, gbc);
154    add(bDisable, gbc);
155
156    gbc.weightx = 1.0;
157    gbc.gridx = 3;
158    add(Box.createHorizontalGlue(), gbc);
159
160    bEnable.setVisible(!isWindowsServiceEnabled);
161    bDisable.setVisible(isWindowsServiceEnabled);
162    addBottomGlue(gbc);
163  }
164
165  /** {@inheritDoc} */
166  public GenericDialog.ButtonType getButtonType()
167  {
168    return GenericDialog.ButtonType.CLOSE;
169  }
170
171  /** {@inheritDoc} */
172  public Component getPreferredFocusComponent()
173  {
174    if (!isWindowsServiceEnabled)
175    {
176      return bEnable;
177    }
178    else
179    {
180      return bDisable;
181    }
182  }
183
184  /** {@inheritDoc} */
185  public void configurationChanged(ConfigurationChangeEvent ev)
186  {
187    boolean previousValue = isWindowsServiceEnabled;
188    isWindowsServiceEnabled = ev.getNewDescriptor().isWindowsServiceEnabled();
189
190    final boolean isLocal = ev.getNewDescriptor().isLocal();
191    if (isLocal != previousLocal || isWindowsServiceEnabled != previousValue)
192    {
193      previousLocal = isLocal;
194      SwingUtilities.invokeLater(new Runnable()
195      {
196        /** {@inheritDoc} */
197        public void run()
198        {
199          lState.setText(isWindowsServiceEnabled ?
200              INFO_ENABLED_LABEL.get().toString() :
201                INFO_DISABLED_LABEL.get().toString());
202          bEnable.setVisible(!isWindowsServiceEnabled);
203          bDisable.setVisible(isWindowsServiceEnabled);
204
205          if (!isLocal)
206          {
207            displayErrorMessage(INFO_CTRL_PANEL_SERVER_REMOTE_SUMMARY.get(),
208            INFO_CTRL_PANEL_SERVER_MUST_BE_LOCAL_WINDOWS_SERVICE_SUMMARY.get());
209            packParentDialog();
210          }
211          else
212          {
213            displayMainPanel();
214          }
215        }
216      });
217    }
218  }
219
220  /** {@inheritDoc} */
221  public void okClicked()
222  {
223    // NO ok button
224  }
225
226  private void updateWindowsService()
227  {
228    LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>();
229    ProgressDialog progressDialog = new ProgressDialog(
230        Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(),
231        getInfo());
232    WindowsServiceTask newTask = new WindowsServiceTask(getInfo(),
233        progressDialog, !isWindowsServiceEnabled);
234    for (Task task : getInfo().getTasks())
235    {
236      task.canLaunch(newTask, errors);
237    }
238    if (errors.isEmpty())
239    {
240      if (isWindowsServiceEnabled)
241      {
242        launchOperation(newTask,
243            INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY.get(),
244            INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY.get(),
245            INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS.get(),
246            ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY.get(),
247            null,
248            ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS,
249            progressDialog);
250      }
251      else
252      {
253        launchOperation(newTask,
254            INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY.get(),
255            INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY.get(),
256            INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS.get(),
257            ERR_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_ERROR_SUMMARY.get(),
258            null,
259            ERR_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_ERROR_DETAILS,
260            progressDialog);
261      }
262      progressDialog.setVisible(true);
263    }
264    else
265    {
266      displayErrorDialog(errors);
267    }
268  }
269
270  /**
271   * The task in charge of updating the windows service configuration.
272   *
273   */
274  protected class WindowsServiceTask extends Task
275  {
276    Set<String> backendSet;
277    private boolean enableService;
278    /**
279     * The constructor of the task.
280     * @param info the control panel info.
281     * @param dlg the progress dialog that shows the progress of the task.
282     * @param enableService whether the windows service must be enabled or
283     * disabled.
284     */
285    public WindowsServiceTask(ControlPanelInfo info, ProgressDialog dlg,
286        boolean enableService)
287    {
288      super(info, dlg);
289      this.enableService = enableService;
290      backendSet = new HashSet<>();
291    }
292
293    /** {@inheritDoc} */
294    public Type getType()
295    {
296      if (enableService)
297      {
298        return Type.ENABLE_WINDOWS_SERVICE;
299      }
300      else
301      {
302        return Type.DISABLE_WINDOWS_SERVICE;
303      }
304    }
305
306    /** {@inheritDoc} */
307    public LocalizableMessage getTaskDescription()
308    {
309      if (enableService)
310      {
311        return INFO_CTRL_PANEL_ENABLE_WINDOWS_SERVICE_TASK_DESCRIPTION.get();
312      }
313      else
314      {
315        return INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_TASK_DESCRIPTION.get();
316      }
317    }
318
319    /** {@inheritDoc} */
320    public boolean canLaunch(Task taskToBeLaunched,
321        Collection<LocalizableMessage> incompatibilityReasons)
322    {
323      Type type = taskToBeLaunched.getType();
324      if (state == State.RUNNING
325          && runningOnSameServer(taskToBeLaunched)
326          && (type == Type.ENABLE_WINDOWS_SERVICE
327              || type == Type.DISABLE_WINDOWS_SERVICE))
328      {
329        incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
330        return false;
331      }
332      return true;
333    }
334
335    /** {@inheritDoc} */
336    public void runTask()
337    {
338      state = State.RUNNING;
339      lastException = null;
340      try
341      {
342        if (enableService)
343        {
344          returnCode = ConfigureWindowsService.enableService(outPrintStream, errorPrintStream);
345          if (returnCode != ConfigureWindowsService.SERVICE_ALREADY_ENABLED &&
346              returnCode != ConfigureWindowsService.SERVICE_ENABLE_SUCCESS)
347          {
348            state = State.FINISHED_WITH_ERROR;
349          }
350          else
351          {
352            state = State.FINISHED_SUCCESSFULLY;
353          }
354        }
355        else
356        {
357          returnCode = ConfigureWindowsService.disableService(outPrintStream, errorPrintStream);
358          if (returnCode != ConfigureWindowsService.SERVICE_ALREADY_DISABLED
359              && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS)
360          {
361            state = State.FINISHED_WITH_ERROR;
362          }
363          else
364          {
365            state = State.FINISHED_SUCCESSFULLY;
366          }
367        }
368      }
369      catch (Throwable t)
370      {
371        lastException = t;
372        state = State.FINISHED_WITH_ERROR;
373      }
374    }
375
376    /** {@inheritDoc} */
377    public Set<String> getBackends()
378    {
379      return backendSet;
380    }
381
382    /** {@inheritDoc} */
383    protected ArrayList<String> getCommandLineArguments()
384    {
385      ArrayList<String> args = new ArrayList<>();
386
387      if (enableService)
388      {
389        args.add("--enableService");
390      }
391      else
392      {
393        args.add("--disableService");
394      }
395
396      return args;
397    }
398
399    /** {@inheritDoc} */
400    protected String getCommandLinePath()
401    {
402      return getCommandLinePath("windows-service");
403    }
404  }
405}