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