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