VmsCommandLauncher.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */

  17. package org.apache.commons.exec.launcher;

  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.io.PrintWriter;
  21. import java.nio.charset.Charset;
  22. import java.nio.file.Files;
  23. import java.nio.file.Path;
  24. import java.util.Map;
  25. import java.util.Map.Entry;
  26. import java.util.Set;

  27. import org.apache.commons.exec.CommandLine;
  28. import org.apache.commons.exec.util.StringUtils;

  29. /**
  30.  * A command launcher for VMS that writes the command to a temporary DCL script before launching commands. This is due to limitations of both the DCL
  31.  * interpreter and the Java VM implementation.
  32.  */
  33. public class VmsCommandLauncher extends Java13CommandLauncher {

  34.     /**
  35.      * Constructs a new instance.
  36.      */
  37.     public VmsCommandLauncher() {
  38.         // empty
  39.     }

  40.     /**
  41.      * Writes the command into a temporary DCL script and returns the corresponding File object. The script will be deleted on exit.
  42.      */
  43.     File createCommandFile(final CommandLine cmd, final Map<String, String> env) throws IOException {
  44.         final Path path = Files.createTempFile("EXEC", ".TMP");
  45.         final File script = path.toFile();
  46.         script.deleteOnExit();
  47.         try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))) {
  48.             // add the environment as global symbols for the DCL script
  49.             if (env != null) {
  50.                 final Set<Entry<String, String>> entries = env.entrySet();
  51.                 for (final Entry<String, String> entry : entries) {
  52.                     writer.print("$ ");
  53.                     writer.print(entry.getKey());
  54.                     writer.print(" == "); // define as global symbol
  55.                     writer.println('\"');
  56.                     String value = entry.getValue();
  57.                     // Any embedded " values need to be doubled
  58.                     if (value.indexOf('\"') > 0) {
  59.                         final StringBuilder sb = new StringBuilder();
  60.                         for (int i = 0; i < value.length(); i++) {
  61.                             final char c = value.charAt(i);
  62.                             if (c == '\"') {
  63.                                 sb.append('\"');
  64.                             }
  65.                             sb.append(c);
  66.                         }
  67.                         value = sb.toString();
  68.                     }
  69.                     writer.print(value);
  70.                     writer.println('\"');
  71.                 }
  72.             }

  73.             final String command = cmd.getExecutable();
  74.             if (cmd.isFile()) {// We assume it is it a script file
  75.                 writer.print("$ @");
  76.                 // This is a bit crude, but seems to work
  77.                 final String[] parts = StringUtils.split(command, "/");
  78.                 writer.print(parts[0]); // device
  79.                 writer.print(":[");
  80.                 writer.print(parts[1]); // top level directory
  81.                 final int lastPart = parts.length - 1;
  82.                 for (int i = 2; i < lastPart; i++) {
  83.                     writer.print(".");
  84.                     writer.print(parts[i]);
  85.                 }
  86.                 writer.print("]");
  87.                 writer.print(parts[lastPart]);
  88.             } else {
  89.                 writer.print("$ ");
  90.                 writer.print(command);
  91.             }
  92.             final String[] args = cmd.getArguments();
  93.             for (final String arg : args) {
  94.                 writer.println(" -");
  95.                 writer.print(arg);
  96.             }
  97.             writer.println();
  98.         }
  99.         return script;
  100.     }

  101.     /**
  102.      * Launches the given command in a new process.
  103.      */
  104.     @Override
  105.     public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
  106.         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
  107.     }

  108.     /**
  109.      * Launches the given command in a new process, in the given working directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this method only works if
  110.      * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
  111.      */
  112.     @Override
  113.     public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
  114.         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
  115.     }

  116.     /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
  117.     @Override
  118.     public boolean isFailure(final int exitValue) {
  119.         // even exit value signals failure
  120.         return exitValue % 2 == 0;
  121.     }
  122. }