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 }