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    *      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  
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       * Constructs a new instance.
41       */
42      public VmsCommandLauncher() {
43          // empty
44      }
45  
46      /**
47       * Writes the command into a temporary DCL script and returns the corresponding File object. The script will be deleted on exit.
48       */
49      File createCommandFile(final CommandLine cmd, final Map<String, String> env) throws IOException {
50          final Path path = Files.createTempFile("EXEC", ".TMP");
51          final File script = path.toFile();
52          script.deleteOnExit();
53          try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))) {
54              // add the environment as global symbols for the DCL script
55              if (env != null) {
56                  final Set<Entry<String, String>> entries = env.entrySet();
57                  for (final Entry<String, String> entry : entries) {
58                      writer.print("$ ");
59                      writer.print(entry.getKey());
60                      writer.print(" == "); // define as global symbol
61                      writer.println('\"');
62                      String value = entry.getValue();
63                      // Any embedded " values need to be doubled
64                      if (value.indexOf('\"') > 0) {
65                          final StringBuilder sb = new StringBuilder();
66                          for (int i = 0; i < value.length(); i++) {
67                              final char c = value.charAt(i);
68                              if (c == '\"') {
69                                  sb.append('\"');
70                              }
71                              sb.append(c);
72                          }
73                          value = sb.toString();
74                      }
75                      writer.print(value);
76                      writer.println('\"');
77                  }
78              }
79  
80              final String command = cmd.getExecutable();
81              if (cmd.isFile()) {// We assume it is it a script file
82                  writer.print("$ @");
83                  // This is a bit crude, but seems to work
84                  final String[] parts = StringUtils.split(command, "/");
85                  writer.print(parts[0]); // device
86                  writer.print(":[");
87                  writer.print(parts[1]); // top level directory
88                  final int lastPart = parts.length - 1;
89                  for (int i = 2; i < lastPart; i++) {
90                      writer.print(".");
91                      writer.print(parts[i]);
92                  }
93                  writer.print("]");
94                  writer.print(parts[lastPart]);
95              } else {
96                  writer.print("$ ");
97                  writer.print(command);
98              }
99              final String[] args = cmd.getArguments();
100             for (final String arg : args) {
101                 writer.println(" -");
102                 writer.print(arg);
103             }
104             writer.println();
105         }
106         return script;
107     }
108 
109     /**
110      * Launches the given command in a new process.
111      */
112     @Override
113     public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
114         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
115     }
116 
117     /**
118      * 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
119      * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
120      */
121     @Override
122     public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
123         return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
124     }
125 
126     /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
127     @Override
128     public boolean isFailure(final int exitValue) {
129         // even exit value signals failure
130         return exitValue % 2 == 0;
131     }
132 }