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}