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