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
018package org.apache.commons.exec.environment;
019
020import java.io.BufferedReader;
021import java.io.IOException;
022import java.util.Comparator;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.TreeMap;
026
027import org.apache.commons.exec.CommandLine;
028import org.apache.commons.exec.OS;
029
030/**
031 * Helper class to determine the environment variable
032 * for the OS. Depending on the JDK the environment
033 * variables can be either retrieved directly from the
034 * JVM or requires starting a process to get them running
035 * an OS command line.
036 *
037 * @version $Id: DefaultProcessingEnvironment.java 1636056 2014-11-01 21:12:52Z ggregory $
038 */
039public class DefaultProcessingEnvironment {
040
041    /** the line separator of the system */
042//    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
043
044    /** the environment variables of the process */
045    protected Map<String, String> procEnvironment;
046
047    /**
048     * Find the list of environment variables for this process.
049     *
050     * @return a map containing the environment variables
051     * @throws IOException obtaining the environment variables failed
052     */
053    public synchronized Map<String, String> getProcEnvironment() throws IOException {
054
055        if (procEnvironment == null) {
056            procEnvironment = this.createProcEnvironment();
057        }
058
059        // create a copy of the map just in case that
060        // anyone is going to modifiy it, e.g. removing
061        // or setting an evironment variable
062        final Map<String, String> copy = createEnvironmentMap();
063        copy.putAll(procEnvironment);
064        return copy;
065    }
066
067    /**
068     * Find the list of environment variables for this process.
069     *
070     * @return a amp containing the environment variables
071     * @throws IOException the operation failed
072     */
073    protected Map<String, String> createProcEnvironment() throws IOException {
074        if (procEnvironment == null) {
075            final Map<String, String> env = System.getenv();
076            procEnvironment = createEnvironmentMap();
077            procEnvironment.putAll(env);
078        }
079
080// No longer needed
081//        if (procEnvironment == null) {
082//            procEnvironment = createEnvironmentMap();
083//            final BufferedReader in = runProcEnvCommand();
084//
085//            String var = null;
086//            String line;
087//            while ((line = in.readLine()) != null) {
088//                if (line.indexOf('=') == -1) {
089//                    // Chunk part of previous env var (UNIX env vars can
090//                    // contain embedded new lines).
091//                    if (var == null) {
092//                        var = LINE_SEPARATOR + line;
093//                    } else {
094//                        var += LINE_SEPARATOR + line;
095//                    }
096//                } else {
097//                    // New env var...append the previous one if we have it.
098//                    if (var != null) {
099//                        EnvironmentUtils.addVariableToEnvironment(procEnvironment, var);
100//                    }
101//                    var = line;
102//                }
103//            }
104//            // Since we "look ahead" before adding, there's one last env var.
105//            if (var != null) {
106//                EnvironmentUtils.addVariableToEnvironment(procEnvironment, var);
107//            }
108//        }
109        return procEnvironment;
110    }
111
112    /**
113     * Start a process to list the environment variables.
114     *
115     * @return a reader containing the output of the process
116     * @throws IOException starting the process failed
117     * @deprecated No longer needed
118     */
119    @Deprecated
120    protected BufferedReader runProcEnvCommand() throws IOException {
121//        final ByteArrayOutputStream out = new ByteArrayOutputStream();
122//        final Executor exe = new DefaultExecutor();
123//        exe.setStreamHandler(new PumpStreamHandler(out));
124//        // ignore the exit value - Just try to use what we got
125//        exe.execute(getProcEnvCommand());
126//        return new BufferedReader(new StringReader(toString(out)));
127        return null;
128    }
129
130    /**
131     * Determine the OS specific command line to get a list of environment
132     * variables.
133     *
134     * @return the command line
135     * @deprecated No longer needed
136     */
137    @Deprecated
138    protected CommandLine getProcEnvCommand() {
139//        String executable;
140//        String[] arguments = null;
141//        if (OS.isFamilyOS2()) {
142//            // OS/2 - use same mechanism as Windows 2000
143//            executable = "cmd";
144//
145//            arguments = new String[] {"/c", "set"};
146//        } else if (OS.isFamilyWindows()) {
147//            // Determine if we're running under XP/2000/NT or 98/95
148//            if (OS.isFamilyWin9x()) {
149//                executable = "command.com";
150//                // Windows 98/95
151//            } else {
152//                executable = "cmd";
153//                // Windows XP/2000/NT/2003
154//            }
155//            arguments = new String[] {"/c", "set"};
156//        } else if (OS.isFamilyZOS() || OS.isFamilyUnix()) {
157//            // On most systems one could use: /bin/sh -c env
158//
159//            // Some systems have /bin/env, others /usr/bin/env, just try
160//            if (new File("/bin/env").canRead()) {
161//                executable = "/bin/env";
162//            } else if (new File("/usr/bin/env").canRead()) {
163//                executable = "/usr/bin/env";
164//            } else {
165//                // rely on PATH
166//                executable = "env";
167//            }
168//        } else if (OS.isFamilyNetware() || OS.isFamilyOS400()) {
169//            // rely on PATH
170//            executable = "env";
171//        } else {
172//            // MAC OS 9 and previous
173//            // TODO: I have no idea how to get it, someone must fix it
174//            executable = null;
175//        }
176        final CommandLine commandLine = null;
177//        if (executable != null) {
178//            commandLine = new CommandLine(executable);
179//            commandLine.addArguments(arguments);
180//        }
181        return commandLine;
182    }
183
184//    /**
185//     * ByteArrayOutputStream#toString doesn't seem to work reliably on OS/390,
186//     * at least not the way we use it in the execution context.
187//     *
188//     * @param bos
189//     *            the output stream that one wants to read
190//     * @return the output stream as a string, read with special encodings in the
191//     *         case of z/os and os/400
192//     */
193//    private String toString(final ByteArrayOutputStream bos) {
194//        if (OS.isFamilyZOS()) {
195//            try {
196//                return bos.toString("Cp1047");
197//            } catch (final java.io.UnsupportedEncodingException e) {
198//                // noop default encoding used
199//            }
200//        } else if (OS.isFamilyOS400()) {
201//            try {
202//                return bos.toString("Cp500");
203//            } catch (final java.io.UnsupportedEncodingException e) {
204//                // noop default encoding used
205//            }
206//        }
207//        return bos.toString();
208//    }
209
210    /**
211     * Creates a map that obeys the casing rules of the current platform for key
212     * lookup. E.g. on a Windows platform, the map keys will be
213     * case-insensitive.
214     *
215     * @return The map for storage of environment variables, never
216     *         {@code null}.
217     */
218    private Map<String, String> createEnvironmentMap() {
219        if (OS.isFamilyWindows()) {
220            return new TreeMap<String, String>(new Comparator<String>() {
221                public int compare(final String key0, final String key1) {
222                    return key0.compareToIgnoreCase(key1);
223                }
224            });
225        }
226        return new HashMap<String, String>();
227    }
228
229}