View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.exec.launcher;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.PrintWriter;
25  import java.nio.charset.Charset;
26  import java.nio.file.Files;
27  import java.nio.file.Path;
28  import java.util.Map;
29  import java.util.Map.Entry;
30  import java.util.Set;
31  
32  import org.apache.commons.exec.CommandLine;
33  import org.apache.commons.exec.util.StringUtils;
34  
35  /**
36   * 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
37   * interpreter and the Java VM implementation.
38   */
39  public class VmsCommandLauncher extends Java13CommandLauncher {
40  
41      /**
42       * Constructs a new instance.
43       */
44      public VmsCommandLauncher() {
45          // empty
46      }
47  
48      /**
49       * Writes the command into a temporary DCL script and returns the corresponding File object. The script will be deleted on exit.
50       */
51      File createCommandFile(final CommandLine cmd, final Map<String, String> env) throws IOException {
52          final Path path = Files.createTempFile("EXEC", ".TMP");
53          final File script = path.toFile();
54          script.deleteOnExit();
55          try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))) {
56              // add the environment as global symbols for the DCL script
57              if (env != null) {
58                  final Set<Entry<String, String>> entries = env.entrySet();
59                  for (final Entry<String, String> entry : entries) {
60                      writer.print("$ ");
61                      writer.print(entry.getKey());
62                      writer.print(" == "); // define as global symbol
63                      writer.println('\"');
64                      String value = entry.getValue();
65                      // Any embedded " values need to be doubled
66                      if (value.indexOf('\"') > 0) {
67                          final StringBuilder sb = new StringBuilder();
68                          for (int i = 0; i < value.length(); i++) {
69                              final char c = value.charAt(i);
70                              if (c == '\"') {
71                                  sb.append('\"');
72                              }
73                              sb.append(c);
74                          }
75                          value = sb.toString();
76                      }
77                      writer.print(value);
78                      writer.println('\"');
79                  }
80              }
81              final String command = cmd.getExecutable();
82              if (cmd.isFile()) {
83                  // We assume it is it a script file
84                  writer.print("$ @");
85                  // This is a bit crude, but seems to work
86                  final String[] parts = StringUtils.split(command, "/");
87                  writer.print(parts[0]); // device
88                  writer.print(":[");
89                  writer.print(parts[1]); // top level directory
90                  final int lastPart = parts.length - 1;
91                  for (int i = 2; i < lastPart; i++) {
92                      writer.print(".");
93                      writer.print(parts[i]);
94                  }
95                  writer.print("]");
96                  writer.print(parts[lastPart]);
97              } else {
98                  writer.print("$ ");
99                  writer.print(command);
100             }
101             final String[] args = cmd.getArguments();
102             for (final String arg : args) {
103                 writer.println(" -");
104                 writer.print(arg);
105             }
106             writer.println();
107         }
108         return script;
109     }
110 
111     /**
112      * Launches the given command in a new process.
113      */
114     @Override
115     public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
116         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
117     }
118 
119     /**
120      * 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
121      * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
122      */
123     @Override
124     public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
125         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
126     }
127 
128     /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
129     @Override
130     public boolean isFailure(final int exitValue) {
131         // even exit value signals failure
132         return exitValue % 2 == 0;
133     }
134 }