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 }