001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    package com.chemaxon.calculations.util;
011    
012    import com.google.common.base.Optional;
013    import com.google.common.base.Preconditions;
014    import java.io.BufferedInputStream;
015    import java.io.BufferedOutputStream;
016    import java.io.FileInputStream;
017    import java.io.FileNotFoundException;
018    import java.io.FileOutputStream;
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.io.ObjectInputStream;
022    import java.io.ObjectOutputStream;
023    import java.io.PrintStream;
024    import java.io.UnsupportedEncodingException;
025    import org.apache.commons.io.IOUtils;
026    import org.apache.commons.io.LineIterator;
027    import org.apache.commons.io.input.CloseShieldInputStream;
028    import org.apache.commons.io.output.CloseShieldOutputStream;
029    import org.apache.commons.io.output.NullOutputStream;
030    
031    /**
032     * Command line related utilities.
033     *
034     * @author Gabor Imre
035     */
036    public final class CmdlineUtils {
037    
038        /**
039         * UTF-8 encoding String literal.
040         */
041        public static final String UTF8ENCODING = "UTF-8";
042    
043        /**
044         * No constructor exposed.
045         */
046        private CmdlineUtils() {}
047    
048        /**
049         * Create InputStream from not nullable location.
050         *
051         * @param location  File name or "-" for stdin.
052         * @return Input stream representing given location. Returned input stream should be closed after usage. If stdin
053         *               requested it is wrapped in a {@link CloseShieldInputStream}
054         * @throws FileNotFoundException thrown by {@link FileInputStream#FileInputStream(java.lang.String)}
055         */
056        public static InputStream inputStreamFromLocation(String location) throws FileNotFoundException {
057            Preconditions.checkNotNull(location);
058    
059            InputStream ret;
060            if ("-".equals(location)) {
061                ret = new CloseShieldInputStream(System.in);
062            } else {
063                ret = new BufferedInputStream(new FileInputStream(location));
064            }
065            return ret;
066        }
067    
068    
069        /**
070         * Create ObjectInputStream from a not nullable location.
071         *
072         * @param location  File name or "-" for stdin
073         * @return <code>ObjectInputStream</code> to be used
074         * @throws IOException  re-thrown
075         */
076        public static ObjectInputStream objectInputStreamFromLocation(String location) throws IOException {
077            Preconditions.checkNotNull(location);
078    
079            ObjectInputStream ret;
080            if ("-".equals(location)) {
081                ret = new ObjectInputStream(new CloseShieldInputStream(System.in));
082            } else {
083                ret = new ObjectInputStream(new BufferedInputStream(new FileInputStream(location)));
084            }
085            return ret;
086        }
087    
088        /**
089         * Create a {@link LineIterator} from a not nullable location.
090         *
091         * <p>
092         * Note that the returned instance must be closed by calling {@link LineIterator#close()} or
093         * {@link LineIterator#closeQuietly(org.apache.commons.io.LineIterator)}, preferably in a <code>finally</code>
094         * block</p>
095         *
096         * @param location File name or "-" for stdin
097         * @return {@link LineIterator} for the given location
098         * @throws IOException re-thrown
099         */
100        public static LineIterator lineIteratorFromLocation(String location) throws IOException {
101            Preconditions.checkNotNull(location);
102            final InputStream is = inputStreamFromLocation(location);
103            return IOUtils.lineIterator(is, UTF8ENCODING);
104        }
105    
106    
107        /**
108         * Create in input stream from nullable location.
109         *
110         * <p>The returned {@link InputStream} should be closed in a proper <code>finally</code> block by invoking its
111         * {@link InputStream#close()} method. If stdin used then a {@link CloseShieldInputStream} is returned which is safe
112         * to close.</p>
113         *
114         * @param location  File name or "-" for stdin
115         * @return Input stream representing given location
116         * @throws FileNotFoundException thrown by {@link FileInputStream#FileInputStream(java.lang.String)}
117         */
118        public static Optional<InputStream> inputStreamFromNullableLocation(String location) throws FileNotFoundException {
119            if (location == null) {
120                return Optional.<InputStream>absent();
121            }
122            return Optional.of(inputStreamFromLocation(location));
123        }
124    
125        /**
126         * Create in object input stream from nullable location.
127         *
128         * <p>The returned {@link Object} should be closed in a proper <code>finally</code> block by invoking its
129         * {@link ObjectInputStream#close()} method. If stdin used then a {@link CloseShieldInputStream} is used which is
130         * safe to close.</p>
131         *
132         * @param location  File name or "-" for stdin
133         * @return ObjectInputStream representing given location
134         * @throws IOException re-thrown
135         */
136        public static Optional<ObjectInputStream> objectInputStreamFromNullableLocation(String location) throws
137                IOException {
138            if (location == null) {
139                return Optional.<ObjectInputStream>absent();
140            }
141            return Optional.of(objectInputStreamFromLocation(location));
142        }
143    
144    
145        /**
146         * PrintStream from a location.
147         *
148         * @param location  File name or "-" for stdout, "-2" for stderr. Location "/dev/null" is considered as a
149         *                  {@link NullOutputStream}. Note that NullOutputStream is available both in apache commons io and
150         *                  in Guava, however Guava version is marked with <code>Beta</code>, so apache version is used.
151         * @return          UTF-8 encoded PrintStream for given location which is safe and should be closed explicitly
152         * @throws FileNotFoundException thrown by {@link FileOutputStream#FileOutputStream(java.lang.String)}
153         */
154        public static PrintStream printStreamFromLocation(String location) throws FileNotFoundException {
155            Preconditions.checkNotNull(location);
156            final PrintStream ret;
157            try {
158                if ("-".equals(location)) {
159                    ret = new PrintStream(new CloseShieldOutputStream(System.out), false, UTF8ENCODING);
160                } else if ("-2".equals(location)) {
161                    ret = new PrintStream(new CloseShieldOutputStream(System.err), false, UTF8ENCODING);
162                } else if ("/dev/null".equals(location)) {
163                    // Specifying encoding with a NullOuputStream might be suprizing
164                    // This or using a FindBugs annotation can silence a "DM_DEFAULT_ENCODING" warning
165                    ret = new PrintStream(new NullOutputStream(), false, UTF8ENCODING);
166                } else {
167                    ret = new PrintStream(new BufferedOutputStream(new FileOutputStream(location)), false, UTF8ENCODING);
168                }
169            } catch (UnsupportedEncodingException ex) {
170                // This should not happen
171                throw new AssertionError(ex);
172            }
173            return ret;
174        }
175    
176        /**
177         * ObjectOutputStream from a location.
178         *
179         * @param location  File name or "-" for stdout, "-2" for stderr. Location "/dev/null" is considered as a
180         *                  {@link NullOutputStream}. Note that NullOutputStream is available both in apache commons io and
181         *                  in Guava, however Guava version is marked with <code>Beta</code>, so apache version is used.
182         * @return          ObjectOutputStream for given location which is safe and should be closed explicitly
183         * @throws IOException thrown by underlying streams
184         */
185        public static ObjectOutputStream objectOutputStreamFromLocation(String location) throws IOException {
186            Preconditions.checkNotNull(location);
187            final ObjectOutputStream ret;
188            if ("-".equals(location)) {
189                ret = new ObjectOutputStream(new CloseShieldOutputStream(System.out));
190            } else if ("-2".equals(location)) {
191                ret = new ObjectOutputStream(new CloseShieldOutputStream(System.err));
192            } else if ("/dev/null".equals(location)) {
193                ret = new ObjectOutputStream(new NullOutputStream());
194            } else {
195                ret = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(location)));
196            }
197            return ret;
198        }
199    
200    
201        /**
202         * Read the contents of a location into a String.
203         *
204         * @param location     Location passed to {@link #inputStreamFromLocation(java.lang.String)}
205         * @return             Contents read by {@link IOUtils#toString(java.io.InputStream, java.lang.String)}
206         * @throws IllegalArgumentException When something goes wrong
207         */
208        public static String stringFromLocation(String location) throws IllegalArgumentException {
209            try {
210                final InputStream is = inputStreamFromLocation(location);
211                try {
212                    return IOUtils.toString(is, UTF8ENCODING);
213                } finally {
214                    is.close();
215                }
216            } catch (IOException ex) {
217                throw new IllegalArgumentException(ex);
218            }
219        }
220    
221    
222        /**
223         * PrintStream from a nullable location.
224         *
225         * @param location  File name or "-" for stdout, "-2" for stderr
226         * @return          UTF-8 encoded PrintStream for given location which is safe and should be closed explicitly when
227         *                  not null given
228         * @throws FileNotFoundException thrown by {@link FileOutputStream#FileOutputStream(java.lang.String)}
229         */
230        public static Optional<PrintStream> printStreamFromNullableLocation(String location) throws FileNotFoundException {
231            if (location == null) {
232                return Optional.<PrintStream>absent();
233            }
234            return Optional.of(printStreamFromLocation(location));
235        }
236    
237        /**
238         * ObjectOutputStream from a nullable location.
239         *
240         * @param location  File name or "-" for stdout, "-2" for stderr
241         * @return          ObjectOutputStream for given location which is safe and should be closed explicitly when
242         *                  not null given
243         * @throws IOException re-thrown
244         */
245        public static Optional<ObjectOutputStream> objectOutputStreamFromNullableLocation(String location) throws
246                IOException {
247            if (location == null) {
248                return Optional.<ObjectOutputStream>absent();
249            }
250            return Optional.of(objectOutputStreamFromLocation(location));
251        }
252    
253    
254        /**
255         * Read the contents of a location when it is not null.
256         *
257         * @param location  A location or null
258         * @return          Contents
259         */
260        public static Optional<String> stringFromNullableLocation(String location) {
261            if (location == null) {
262                return Optional.<String>absent();
263            } else {
264                return Optional.of(stringFromLocation(location));
265            }
266        }
267    
268    
269    }