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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.tools;
029    import org.opends.messages.Message;
030    
031    import java.io.BufferedReader;
032    import java.io.File;
033    import java.io.InputStreamReader;
034    import java.io.IOException;
035    import java.io.OutputStream;
036    import java.io.PrintStream;
037    
038    import org.opends.server.core.DirectoryServer;
039    import org.opends.server.types.NullOutputStream;
040    import org.opends.server.util.SetupUtils;
041    import org.opends.server.util.args.ArgumentException;
042    import org.opends.server.util.args.ArgumentParser;
043    import org.opends.server.util.args.BooleanArgument;
044    import org.opends.server.util.args.StringArgument;
045    
046    import static org.opends.messages.ToolMessages.*;
047    import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
048    import static org.opends.server.util.StaticUtils.*;
049    import static org.opends.server.tools.ToolConstants.*;
050    
051    /**
052      * This class is used to configure the Windows service for this instance on
053      * this machine.
054      * This tool allows to enable and disable OpenDS to run as a Windows service
055      * and allows to know if OpenDS is running as a Windows service or not.
056      *
057      * Some comments about Vista:
058      * In Vista, when we launch the subcommands that require administrator
059      * privileges (enable, disable and cleanup) we cannot use the administrator
060      * launcher binary directly from Java (see
061      * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6410605) so we use
062      * winlauncher.exe.
063      * When we launch subcommands that required administrator privileges
064      * we must launch a binary containing the manifest that specifies that we
065      * require administrator privileges (requireAdministrator value): if UAC is
066      * enabled, the user will be asked for confirmation.
067      * To minimize the number of confirmation that the user must provide when
068      * launching the state subcommand we will use a binary whose manifest does
069      * not contain the requireAdministrator value.
070      *
071      * See the files under src/build-tools/windows for more details.
072      */
073    public class ConfigureWindowsService
074    {
075      /**
076       * The fully-qualified name of this class.
077       */
078      private static final String CLASS_NAME =
079        "org.opends.server.tools.ConfigureWindowsService";
080    
081      private static final String DEBUG_OPTION = "--debug";
082      /**
083       * Option to be used when calling the launchers.
084       */
085      public static final String LAUNCHER_OPTION = "run";
086    
087      private static int ERROR = 1;
088    
089      /**
090       * Return codes for the method enableService.
091       */
092      /**
093       * The service was successfully enabled.
094       */
095      public static final int SERVICE_ENABLE_SUCCESS = 0;
096      /**
097       * The service was already enabled.
098       */
099      public static final int SERVICE_ALREADY_ENABLED = 1;
100      /**
101       * The service name was already in use.
102       */
103      public static final int SERVICE_NAME_ALREADY_IN_USE = 2;
104      /**
105       * An error occurred enabling the service.
106       */
107      public static final int SERVICE_ENABLE_ERROR = 3;
108    
109      /**
110       * Return codes for the method disableService.
111       */
112      /**
113       * The service was successfully disabled.
114       */
115      public static final int SERVICE_DISABLE_SUCCESS = 0;
116      /**
117       * The service was already disabled.
118       */
119      public static final int SERVICE_ALREADY_DISABLED = 1;
120      /**
121       * The service is marked for deletion.
122       */
123      public static final int SERVICE_MARKED_FOR_DELETION = 2;
124      /**
125       * An error occurred disabling the service.
126       */
127      public static final int SERVICE_DISABLE_ERROR = 3;
128    
129      /**
130       * Return codes for the method serviceState.
131       */
132      /**
133       * The service is enabled.
134       */
135      public static final int SERVICE_STATE_ENABLED = 0;
136      /**
137       * The service is disabled.
138       */
139      public static final int SERVICE_STATE_DISABLED = 1;
140      /**
141       * An error occurred checking the service state.
142       */
143      public static final int SERVICE_STATE_ERROR = 2;
144    
145      /**
146       * Return codes for the method cleanupService.
147       */
148      /**
149       * The service cleanup worked.
150       */
151      public static final int SERVICE_CLEANUP_SUCCESS = 0;
152      /**
153       * The service could not be found.
154       */
155      public static final int SERVICE_NOT_FOUND = 1;
156      /**
157       * An error occurred cleaning up the service.
158       */
159      public static final int SERVICE_CLEANUP_ERROR = 2;
160      /**
161       * The service is marked for deletion.
162       */
163      public static final int SERVICE_CLEANUP_MARKED_FOR_DELETION = 3;
164    
165    
166      /**
167       * Configures the Windows service for this instance on this machine.
168       * This tool allows to enable and disable OpenDS to run as a Windows service
169       * and allows to know if OpenDS is running as a Windows service or not.
170       *
171       * @param  args  The command-line arguments provided to this program.
172       */
173      public static void main(String[] args)
174      {
175        int result = configureWindowsService(args, System.out, System.err);
176    
177        System.exit(filterExitCode(result));
178      }
179    
180      /**
181       * Configures the Windows service for this instance on this machine.
182       * This tool allows to enable and disable OpenDS to run as a Windows service
183       * and allows to know if OpenDS is running as a Windows service or not.
184       *
185       * @param  args  The command-line arguments provided to this program.
186       * @param outStream the stream used to write the standard output.
187       * @param errStream the stream used to write the error output.
188       * @return the integer code describing if the operation could be completed or
189       * not.
190       */
191      public static int configureWindowsService(String[] args,
192          OutputStream outStream, OutputStream errStream)
193      {
194        int returnValue = 0;
195        PrintStream out;
196        if (outStream == null)
197        {
198          out = NullOutputStream.printStream();
199        }
200        else
201        {
202          out = new PrintStream(outStream);
203        }
204    
205        PrintStream err;
206        if (errStream == null)
207        {
208          err = NullOutputStream.printStream();
209        }
210        else
211        {
212          err = new PrintStream(errStream);
213        }
214    
215    //  Define all the arguments that may be used with this program.
216        Message toolDescription =
217            INFO_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION.get();
218        ArgumentParser argParser = new ArgumentParser(CLASS_NAME,
219            toolDescription, false);
220        BooleanArgument enableService = null;
221        BooleanArgument disableService = null;
222        BooleanArgument serviceState = null;
223        StringArgument cleanupService = null;
224        BooleanArgument showUsage = null;
225    
226        try
227        {
228          enableService = new BooleanArgument("enableservice", 'e', "enableService",
229              INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE.get());
230          argParser.addArgument(enableService);
231    
232          disableService = new BooleanArgument("disableservice", 'd',
233              "disableService",
234              INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE.get());
235          argParser.addArgument(disableService);
236    
237          serviceState = new BooleanArgument("servicestate", 's',
238              "serviceState",
239              INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE.get());
240          argParser.addArgument(serviceState);
241    
242          cleanupService = new StringArgument("cleanupservice", 'c',
243              "cleanupService", false, false, true,
244              INFO_SERVICE_NAME_PLACEHOLDER.get(), null, null,
245              INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_CLEANUP.get());
246          argParser.addArgument(cleanupService);
247    
248          showUsage = new BooleanArgument("showusage", OPTION_SHORT_HELP,
249              OPTION_LONG_HELP,
250              INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE.get());
251          argParser.addArgument(showUsage);
252          argParser.setUsageArgument(showUsage, out);
253        }
254        catch (ArgumentException ae)
255        {
256          Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
257    
258          err.println(wrapText(message, MAX_LINE_WIDTH));
259          returnValue = ERROR;
260        }
261    
262        // Parse the command-line arguments provided to this program.
263        if (returnValue == 0)
264        {
265          try
266          {
267            argParser.parseArguments(args);
268          }
269          catch (ArgumentException ae)
270          {
271            Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
272    
273            err.println(wrapText(message, MAX_LINE_WIDTH));
274            err.println(argParser.getUsage());
275            returnValue = ERROR;
276          }
277        }
278    
279        // If we should just display usage or version information,
280        // then it is already done
281        if ((returnValue == 0) && !argParser.usageOrVersionDisplayed())
282        {
283          /* Check that the user only asked for one argument */
284          int nArgs = 0;
285          if (enableService.isPresent())
286          {
287            nArgs++;
288          }
289          if (disableService.isPresent())
290          {
291            nArgs++;
292          }
293          if (serviceState.isPresent())
294          {
295            nArgs++;
296          }
297          if (cleanupService.isPresent())
298          {
299            nArgs++;
300          }
301          if (nArgs > 1)
302          {
303            Message message = ERR_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS.get();
304            err.println(wrapText(message, MAX_LINE_WIDTH));
305            err.println(argParser.getUsage());
306            returnValue = ERROR;
307          }
308          if (nArgs == 0)
309          {
310            Message message = ERR_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS.get();
311            err.println(wrapText(message, MAX_LINE_WIDTH));
312            err.println(argParser.getUsage());
313            returnValue = ERROR;
314          }
315        }
316    
317        if ((returnValue == 0) && !argParser.usageOrVersionDisplayed())
318        {
319          if (enableService.isPresent())
320          {
321            returnValue = enableService(out, err);
322          }
323          else if (disableService.isPresent())
324          {
325            returnValue = disableService(out, err);
326          }
327          else if (serviceState.isPresent())
328          {
329            returnValue = serviceState(out, err);
330          }
331          else
332          {
333            returnValue = cleanupService(cleanupService.getValue(), out, err);
334          }
335        }
336    
337        return returnValue;
338      }
339    
340      /**
341       * Returns the service name associated with OpenDS or null if no service name
342       * could be found.
343       * @return the service name associated with OpenDS or null if no service name
344       * could be found.
345       */
346      static String getServiceName()
347      {
348        String serviceName = null;
349        String serverRoot = getServerRoot();
350        String[] cmd = {
351            getBinaryFullPath(),
352            "state",
353            serverRoot
354        };
355        try
356        {
357          Process p = Runtime.getRuntime().exec(cmd);
358          BufferedReader stdout = new BufferedReader(
359              new InputStreamReader(p.getInputStream()));
360          boolean processDone = false;
361          String s;
362          while (!processDone)
363          {
364            try
365            {
366              p.exitValue();
367              processDone = true;
368            }
369            catch (Throwable t)
370            {
371            }
372            while ((s = stdout.readLine()) != null)
373            {
374              serviceName = s;
375              if (serviceName.trim().length() == 0)
376              {
377                serviceName = null;
378              }
379            }
380          }
381        }
382        catch (Throwable t)
383        {
384          serviceName = null;
385        }
386    
387        return serviceName;
388      }
389    
390      /**
391       * Enables OpenDS to run as a windows service.
392       * @param out the stream used to write the standard output.
393       * @param err the stream used to write the error output.
394       * @return <CODE>SERVICE_ENABLE_SUCCESS</CODE>,
395       * <CODE>SERVICE_ENABLE_ERROR</CODE>,
396       * <CODE>SERVICE_NAME_ALREADY_IN_USE</CODE> or
397       * <CODE>SERVICE_ALREADY_ENABLED</CODE> depending on whether the service could
398       * be enabled or not.
399       */
400      public static int enableService(PrintStream out, PrintStream err)
401      {
402        int returnValue;
403        Message msg;
404        String serverRoot = getServerRoot();
405    
406        String[] cmd;
407    
408        if (isVista())
409        {
410          cmd = new String[] {
411              getLauncherBinaryFullPath(),
412              LAUNCHER_OPTION,
413              getLauncherAdministratorBinaryFullPath(),
414              LAUNCHER_OPTION,
415              getBinaryFullPath(),
416              "create",
417              serverRoot,
418              INFO_WINDOWS_SERVICE_NAME.get().toString(),
419              INFO_WINDOWS_SERVICE_DESCRIPTION.get(serverRoot).toString(),
420              DEBUG_OPTION
421          };
422        }
423        else
424        {
425          cmd = new String[] {
426              getBinaryFullPath(),
427              "create",
428              serverRoot,
429              INFO_WINDOWS_SERVICE_NAME.get().toString(),
430              INFO_WINDOWS_SERVICE_DESCRIPTION.get(serverRoot).toString(),
431              DEBUG_OPTION
432          };
433        }
434    
435        try
436        {
437          int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
438          switch (resultCode)
439          {
440          case 0:
441            returnValue = SERVICE_ENABLE_SUCCESS;
442            msg = INFO_WINDOWS_SERVICE_SUCCESSULLY_ENABLED.get();
443            out.println(wrapText(msg, MAX_LINE_WIDTH));
444            break;
445          case 1:
446            returnValue = SERVICE_ALREADY_ENABLED;
447            msg = INFO_WINDOWS_SERVICE_ALREADY_ENABLED.get();
448            out.println(wrapText(msg, MAX_LINE_WIDTH));
449            break;
450          case 2:
451            returnValue = SERVICE_NAME_ALREADY_IN_USE;
452            msg = ERR_WINDOWS_SERVICE_NAME_ALREADY_IN_USE.get();
453            err.println(wrapText(msg, MAX_LINE_WIDTH));
454            break;
455          case 3:
456            returnValue = SERVICE_ENABLE_ERROR;
457            msg = ERR_WINDOWS_SERVICE_ENABLE_ERROR.get();
458            err.println(wrapText(msg, MAX_LINE_WIDTH));
459            break;
460          default:
461            returnValue = SERVICE_ENABLE_ERROR;
462            msg = ERR_WINDOWS_SERVICE_ENABLE_ERROR.get();
463            err.println(wrapText(msg, MAX_LINE_WIDTH));
464          }
465        }
466        catch (Throwable t)
467        {
468          err.println("Fucking throwable: "+t);
469          t.printStackTrace();
470          returnValue = SERVICE_ENABLE_ERROR;
471          msg = ERR_WINDOWS_SERVICE_ENABLE_ERROR.get();
472          err.println(wrapText(msg, MAX_LINE_WIDTH));
473        }
474        return returnValue;
475      }
476    
477      /**
478       * Disables OpenDS to run as a windows service.
479       * @param out the stream used to write the standard output.
480       * @param err the stream used to write the error output.
481       * @return <CODE>SERVICE_DISABLE_SUCCESS</CODE>,
482       * <CODE>SERVICE_DISABLE_ERROR</CODE>,
483       * <CODE>SERVICE_MARKED_FOR_DELETION</CODE> or
484       * <CODE>SERVICE_ALREADY_DISABLED</CODE> depending on whether the service
485       * could be disabled or not.
486       */
487      public static int disableService(PrintStream out, PrintStream err)
488      {
489        int returnValue;
490        Message msg;
491        String serverRoot = getServerRoot();
492        String[] cmd;
493        if (isVista())
494        {
495          cmd = new String[] {
496              getLauncherBinaryFullPath(),
497              LAUNCHER_OPTION,
498              getLauncherAdministratorBinaryFullPath(),
499              LAUNCHER_OPTION,
500              getBinaryFullPath(),
501              "remove",
502              serverRoot,
503              DEBUG_OPTION
504          };
505        }
506        else
507        {
508          cmd = new String[] {
509            getBinaryFullPath(),
510            "remove",
511            serverRoot,
512            DEBUG_OPTION
513            };
514        }
515        try
516        {
517          int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
518          switch (resultCode)
519          {
520          case 0:
521            returnValue = SERVICE_DISABLE_SUCCESS;
522            msg = INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED.get();
523            out.println(msg);
524            break;
525          case 1:
526            returnValue = SERVICE_ALREADY_DISABLED;
527            msg = INFO_WINDOWS_SERVICE_ALREADY_DISABLED.get();
528            out.println(msg);
529            break;
530          case 2:
531            returnValue = SERVICE_MARKED_FOR_DELETION;
532            msg = WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION.get();
533            out.println(msg);
534            break;
535          case 3:
536            returnValue = SERVICE_DISABLE_ERROR;
537            msg = ERR_WINDOWS_SERVICE_DISABLE_ERROR.get();
538            err.println(msg);
539            break;
540          default:
541            returnValue = SERVICE_DISABLE_ERROR;
542            msg = ERR_WINDOWS_SERVICE_DISABLE_ERROR.get();
543            err.println(msg);
544          }
545        }
546        catch (Throwable t)
547        {
548          t.printStackTrace();
549          returnValue = SERVICE_DISABLE_ERROR;
550          msg = ERR_WINDOWS_SERVICE_DISABLE_ERROR.get();
551          err.println(msg);
552        }
553        return returnValue;
554      }
555    
556      /**
557       * Cleans up a service for a given service name.
558       * @param serviceName the service name to be cleaned up.
559       * @param out the stream used to write the standard output.
560       * @param err the stream used to write the error output.
561       * @return <CODE>SERVICE_CLEANUP_SUCCESS</CODE>,
562       * <CODE>SERVICE_NOT_FOUND</CODE>,
563       * <CODE>SERVICE_MARKED_FOR_DELETION</CODE> or
564       * <CODE>SERVICE_CLEANUP_ERROR</CODE> depending on whether the service
565       * could be found or not.
566       */
567      public static int cleanupService(String serviceName, PrintStream out,
568          PrintStream err)
569      {
570        int returnValue;
571        Message msg;
572        String[] cmd;
573        if (isVista())
574        {
575          cmd = new String[] {
576              getLauncherBinaryFullPath(),
577              LAUNCHER_OPTION,
578              getLauncherAdministratorBinaryFullPath(),
579              LAUNCHER_OPTION,
580              getBinaryFullPath(),
581              "cleanup",
582              serviceName,
583              DEBUG_OPTION
584          };
585        }
586        else
587        {
588          cmd = new String[] {
589              getBinaryFullPath(),
590              "cleanup",
591              serviceName,
592              DEBUG_OPTION
593          };
594        }
595        try
596        {
597          int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
598          switch (resultCode)
599          {
600          case 0:
601            returnValue = SERVICE_CLEANUP_SUCCESS;
602            msg = INFO_WINDOWS_SERVICE_CLEANUP_SUCCESS.get(serviceName);
603            out.println(msg);
604            break;
605          case 1:
606            returnValue = SERVICE_NOT_FOUND;
607            msg = ERR_WINDOWS_SERVICE_CLEANUP_NOT_FOUND.get(serviceName);
608            err.println(msg);
609            break;
610          case 2:
611            returnValue = SERVICE_CLEANUP_MARKED_FOR_DELETION;
612            msg = WARN_WINDOWS_SERVICE_CLEANUP_MARKED_FOR_DELETION.get(serviceName);
613            out.println(msg);
614            break;
615          case 3:
616            returnValue = SERVICE_CLEANUP_ERROR;
617            msg = ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName);
618            err.println(msg);
619            break;
620          default:
621            returnValue = SERVICE_CLEANUP_ERROR;
622            msg = ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName);
623            err.println(msg);
624          }
625        }
626        catch (Throwable t)
627        {
628          returnValue = SERVICE_CLEANUP_ERROR;
629          msg = ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName);
630          err.println(msg);
631        }
632        return returnValue;
633      }
634    
635      /**
636        * Checks if OpenDS is enabled as a windows service and if it is
637        * write the serviceName in the output stream (if it is not null).
638        * @param out the stream used to write the standard output.
639        * @param err the stream used to write the error output.
640        * @return <CODE>SERVICE_STATE_ENABLED</CODE>,
641        * <CODE>SERVICE_STATE_DISABLED</CODE> or <CODE>SERVICE_STATE_ERROR</CODE>
642        * depending on the state of the service.
643        */
644      public static int serviceState(PrintStream out, PrintStream err)
645      {
646        int returnValue;
647        Message msg;
648        String serviceName = null;
649    
650        String serverRoot = getServerRoot();
651        String[] cmd = new String[] {
652            getBinaryFullPath(),
653            "state",
654            serverRoot,
655            DEBUG_OPTION
656        };
657    
658        try
659        {
660          int resultCode = -1;
661          ProcessBuilder pb = new ProcessBuilder(cmd);
662          Process process = pb.start();
663    
664          BufferedReader stdout =
665              new BufferedReader(new InputStreamReader(process.getInputStream()));
666    
667          boolean processDone = false;
668          String s;
669          while (!processDone)
670          {
671            try
672            {
673              resultCode = process.exitValue();
674              processDone = true;
675            }
676            catch (Throwable t)
677            {
678            }
679            while ((s = stdout.readLine()) != null)
680            {
681              if (s.trim().length() != 0)
682              {
683                serviceName = s;
684              }
685            }
686          }
687    
688          switch (resultCode)
689          {
690          case 0:
691            returnValue = SERVICE_STATE_ENABLED;
692            if (out != null)
693            {
694              msg = INFO_WINDOWS_SERVICE_ENABLED.get(serviceName);
695              out.println(msg);
696            }
697            break;
698          case 1:
699            returnValue = SERVICE_STATE_DISABLED;
700            if (out != null)
701            {
702              msg = INFO_WINDOWS_SERVICE_DISABLED.get();
703              out.println(msg);
704            }
705            break;
706          case 2:
707            returnValue = SERVICE_STATE_ERROR;
708            if (out != null)
709            {
710              msg = ERR_WINDOWS_SERVICE_STATE_ERROR.get();
711              out.println(msg);
712            }
713            break;
714          default:
715            returnValue = SERVICE_STATE_ERROR;
716            if (err != null)
717            {
718              msg = ERR_WINDOWS_SERVICE_STATE_ERROR.get();
719              err.println(msg);
720            }
721          }
722        }
723        catch (Throwable t)
724        {
725          returnValue = SERVICE_STATE_ERROR;
726          if (err != null)
727          {
728            msg = ERR_WINDOWS_SERVICE_STATE_ERROR.get();
729            err.println(wrapText(msg, MAX_LINE_WIDTH));
730          }
731        }
732        return returnValue;
733      }
734    
735      /**
736       * Returns the Directory Server installation path in a user friendly
737       * representation.
738       * @return the Directory Server installation path in a user friendly
739       * representation.
740       */
741      private static String getServerRoot()
742      {
743        String serverRoot = DirectoryServer.getServerRoot();
744        File f = new File(serverRoot);
745        try
746        {
747          /*
748           * Do a best effort to avoid having a relative representation (for
749           * instance to avoid having ../../../).
750           */
751          File canonical = f.getCanonicalFile();
752          f = canonical;
753        }
754        catch (IOException ioe)
755        {
756          /* This is a best effort to get the best possible representation of the
757           * file: reporting the error is not necessary.
758           */
759        }
760        serverRoot = f.toString();
761        if (serverRoot.endsWith(File.separator))
762        {
763          serverRoot = serverRoot.substring(0, serverRoot.length() - 1);
764        }
765        return serverRoot;
766      }
767    
768      /**
769       * Returns the full path of the executable used by this class to perform
770       * operations related to the service.  This binaries file has the asInvoker
771       * value in its manifest.
772       * @return the full path of the executable used by this class to perform
773       * operations related to the service.
774       */
775      private static String getBinaryFullPath()
776      {
777        return SetupUtils.getScriptPath(
778            getServerRoot()+"\\lib\\opends_service.exe");
779      }
780    
781      /**
782       * Returns the full path of the executable that has a manifest requiring
783       * administrator privileges used by this class to perform
784       * operations related to the service.
785       * @return the full path of the executable that has a manifest requiring
786       * administrator privileges used by this class to perform
787       * operations related to the service.
788       */
789      public static String getLauncherAdministratorBinaryFullPath()
790      {
791        return getServerRoot()+"\\lib\\launcher_administrator.exe";
792      }
793    
794      /**
795       * Returns the full path of the executable that has a manifest requiring
796       * administrator privileges used by this class to perform
797       * operations related to the service.
798       * @return the full path of the executable that has a manifest requiring
799       * administrator privileges used by this class to perform
800       * operations related to the service.
801       */
802      public static String getLauncherBinaryFullPath()
803      {
804        return getServerRoot()+"\\lib\\winlauncher.exe";
805      }
806    
807      /**
808       * Indicates whether the underlying operating system is Windows Vista.
809       *
810       * @return  {@code true} if the underlying operating system is Windows
811       *          Vista, or {@code false} if not.
812       */
813      private static boolean isVista()
814      {
815        return SetupUtils.isVista();
816      }
817    }