001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.commons.exec.launcher; 021 022import java.io.File; 023import java.io.IOException; 024import java.io.PrintWriter; 025import java.nio.charset.Charset; 026import java.nio.file.Files; 027import java.nio.file.Path; 028import java.util.Map; 029import java.util.Map.Entry; 030import java.util.Set; 031 032import org.apache.commons.exec.CommandLine; 033import org.apache.commons.exec.util.StringUtils; 034 035/** 036 * 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 037 * interpreter and the Java VM implementation. 038 */ 039public class VmsCommandLauncher extends Java13CommandLauncher { 040 041 /** 042 * Constructs a new instance. 043 */ 044 public VmsCommandLauncher() { 045 // empty 046 } 047 048 /** 049 * Writes the command into a temporary DCL script and returns the corresponding File object. The script will be deleted on exit. 050 */ 051 File createCommandFile(final CommandLine cmd, final Map<String, String> env) throws IOException { 052 final Path path = Files.createTempFile("EXEC", ".TMP"); 053 final File script = path.toFile(); 054 script.deleteOnExit(); 055 try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(path, Charset.defaultCharset()))) { 056 // add the environment as global symbols for the DCL script 057 if (env != null) { 058 final Set<Entry<String, String>> entries = env.entrySet(); 059 for (final Entry<String, String> entry : entries) { 060 writer.print("$ "); 061 writer.print(entry.getKey()); 062 writer.print(" == "); // define as global symbol 063 writer.println('\"'); 064 String value = entry.getValue(); 065 // Any embedded " values need to be doubled 066 if (value.indexOf('\"') > 0) { 067 final StringBuilder sb = new StringBuilder(); 068 for (int i = 0; i < value.length(); i++) { 069 final char c = value.charAt(i); 070 if (c == '\"') { 071 sb.append('\"'); 072 } 073 sb.append(c); 074 } 075 value = sb.toString(); 076 } 077 writer.print(value); 078 writer.println('\"'); 079 } 080 } 081 final String command = cmd.getExecutable(); 082 if (cmd.isFile()) { 083 // We assume it is it a script file 084 writer.print("$ @"); 085 // This is a bit crude, but seems to work 086 final String[] parts = StringUtils.split(command, "/"); 087 writer.print(parts[0]); // device 088 writer.print(":["); 089 writer.print(parts[1]); // top level directory 090 final int lastPart = parts.length - 1; 091 for (int i = 2; i < lastPart; i++) { 092 writer.print("."); 093 writer.print(parts[i]); 094 } 095 writer.print("]"); 096 writer.print(parts[lastPart]); 097 } else { 098 writer.print("$ "); 099 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}