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 * http://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 */ 018 019package org.apache.commons.exec.launcher; 020 021import java.io.File; 022import java.io.FileWriter; 023import java.io.IOException; 024import java.io.PrintWriter; 025import java.util.Map; 026import java.util.Map.Entry; 027import java.util.Set; 028 029import org.apache.commons.exec.CommandLine; 030import org.apache.commons.exec.util.StringUtils; 031 032/** 033 * A command launcher for VMS that writes the command to a temporary DCL script 034 * before launching commands. This is due to limitations of both the DCL 035 * interpreter and the Java VM implementation. 036 * 037 * @version $Id: VmsCommandLauncher.java 1636056 2014-11-01 21:12:52Z ggregory $ 038 */ 039public class VmsCommandLauncher extends Java13CommandLauncher { 040 041 /** 042 * Launches the given command in a new process. 043 */ 044 @Override 045 public Process exec(final CommandLine cmd, final Map<String, String> env) 046 throws IOException { 047 final CommandLine vmsCmd = new CommandLine( 048 createCommandFile(cmd, env).getPath() 049 ); 050 051 return super.exec(vmsCmd, env); 052 } 053 054 /** 055 * Launches the given command in a new process, in the given working 056 * directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this method 057 * only works if {@code workingDir} is null or the logical 058 * JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE. 059 */ 060 @Override 061 public Process exec(final CommandLine cmd, final Map<String, String> env, 062 final File workingDir) throws IOException { 063 final CommandLine vmsCmd = new CommandLine( 064 createCommandFile(cmd, env).getPath() 065 ); 066 067 return super.exec(vmsCmd, env, workingDir); 068 } 069 070 /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */ 071 @Override 072 public boolean isFailure(final int exitValue) { 073 // even exit value signals failure 074 return exitValue % 2 == 0; 075 } 076 077 /* 078 * Writes the command into a temporary DCL script and returns the 079 * corresponding File object. The script will be deleted on exit. 080 */ 081 private File createCommandFile(final CommandLine cmd, final Map<String, String> env) 082 throws IOException { 083 final File script = File.createTempFile("EXEC", ".TMP"); 084 script.deleteOnExit(); 085 PrintWriter out = null; 086 try { 087 out = new PrintWriter(new FileWriter(script.getAbsolutePath(),true)); 088 089 // add the environment as global symbols for the DCL script 090 if (env != null) { 091 final Set<Entry<String, String>> entries = env.entrySet(); 092 093 for (final Entry<String, String> entry : entries) { 094 out.print("$ "); 095 out.print(entry.getKey()); 096 out.print(" == "); // define as global symbol 097 out.println('\"'); 098 String value = entry.getValue(); 099 // Any embedded " values need to be doubled 100 if (value.indexOf('\"') > 0) { 101 final StringBuilder sb = new StringBuilder(); 102 for (int i = 0; i < value.length(); i++) { 103 final char c = value.charAt(i); 104 if (c == '\"') { 105 sb.append('\"'); 106 } 107 sb.append(c); 108 } 109 value=sb.toString(); 110 } 111 out.print(value); 112 out.println('\"'); 113 } 114 } 115 116 final String command = cmd.getExecutable(); 117 if (cmd.isFile()) {// We assume it is it a script file 118 out.print("$ @"); 119 // This is a bit crude, but seems to work 120 final String parts[] = StringUtils.split(command,"/"); 121 out.print(parts[0]); // device 122 out.print(":["); 123 out.print(parts[1]); // top level directory 124 final int lastPart = parts.length-1; 125 for (int i=2; i< lastPart; i++) { 126 out.print("."); 127 out.print(parts[i]); 128 } 129 out.print("]"); 130 out.print(parts[lastPart]); 131 } else { 132 out.print("$ "); 133 out.print(command); 134 } 135 final String[] args = cmd.getArguments(); 136 for (final String arg : args) { 137 out.println(" -"); 138 out.print(arg); 139 } 140 out.println(); 141 } finally { 142 if (out != null) { 143 out.close(); 144 } 145 } 146 return script; 147 } 148}