View Javadoc
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    *      http://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  
18  package org.apache.commons.exec.launcher;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.PrintWriter;
23  import java.nio.charset.Charset;
24  import java.nio.file.Files;
25  import java.nio.file.Path;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  import java.util.Set;
29  
30  import org.apache.commons.exec.CommandLine;
31  import org.apache.commons.exec.util.StringUtils;
32  
33  /**
34   * 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
35   * interpreter and the Java VM implementation.
36   */
37  public class VmsCommandLauncher extends Java13CommandLauncher {
38  
39      /**
40       * Writes the command into a temporary DCL script and returns the corresponding File object. The script will be deleted on exit.
41       */
42      private File createCommandFile(final CommandLine cmd, final Map<String, String> env) throws IOException {
43          final Path path = Files.createTempFile("EXEC", ".TMP");
44          final File script = path.toFile();
45          script.deleteOnExit();
46          try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))) {
47              // add the environment as global symbols for the DCL script
48              if (env != null) {
49                  final Set<Entry<String, String>> entries = env.entrySet();
50                  for (final Entry<String, String> entry : entries) {
51                      writer.print("$ ");
52                      writer.print(entry.getKey());
53                      writer.print(" == "); // define as global symbol
54                      writer.println('\"');
55                      String value = entry.getValue();
56                      // Any embedded " values need to be doubled
57                      if (value.indexOf('\"') > 0) {
58                          final StringBuilder sb = new StringBuilder();
59                          for (int i = 0; i < value.length(); i++) {
60                              final char c = value.charAt(i);
61                              if (c == '\"') {
62                                  sb.append('\"');
63                              }
64                              sb.append(c);
65                          }
66                          value = sb.toString();
67                      }
68                      writer.print(value);
69                      writer.println('\"');
70                  }
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     /**
103      * Launches the given command in a new process.
104      */
105     @Override
106     public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
107         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
108     }
109 
110     /**
111      * 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
112      * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
113      */
114     @Override
115     public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
116         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
117     }
118 
119     /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
120     @Override
121     public boolean isFailure(final int exitValue) {
122         // even exit value signals failure
123         return exitValue % 2 == 0;
124     }
125 }