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