001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.process;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedInputStream;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.io.ObjectInputStream;
022    import java.io.ObjectOutputStream;
023    import java.io.ObjectStreamException;
024    import java.io.OutputStream;
025    import java.io.Serializable;
026    
027    /**
028     * @author Shuyang Zhou
029     */
030    public class ProcessExecutor {
031    
032            public static <T extends Serializable> T execute(
033                            ProcessCallable<T> processCallable, String classPath)
034                    throws ProcessException {
035    
036                    try {
037                            ProcessBuilder processBuilder = new ProcessBuilder(
038                                    "java", "-cp", classPath, ProcessExecutor.class.getName());
039    
040                            Process process = processBuilder.start();
041    
042                            _writeObject(process.getOutputStream(), processCallable, true);
043    
044                            int exitCode = process.waitFor();
045    
046                            if (exitCode != 0) {
047                                    throw new ProcessException(
048                                            "Subprocess terminated with exit code " + exitCode);
049                            }
050    
051                            InputStream errorInputStream = process.getErrorStream();
052    
053                            if (errorInputStream.available() > 0) {
054                                    ProcessException processException =
055                                            (ProcessException)_readObject(
056                                                    errorInputStream, System.err, true);
057    
058                                    if (processException != null) {
059                                            throw processException;
060                                    }
061                            }
062    
063                            return (T)_readObject(process.getInputStream(), System.out, true);
064                    }
065                    catch (Exception e) {
066                            throw new ProcessException(e);
067                    }
068            }
069    
070            public static void main(String[] arguments)
071                    throws ClassNotFoundException, IOException {
072    
073                    try {
074                            ProcessCallable<?> processCallable =
075                                    (ProcessCallable<?>)_readObject(System.in, null, false);
076    
077                            Object result = processCallable.call();
078    
079                            _writeObject(System.out, result, false);
080                    }
081                    catch (ProcessException pe) {
082                            _writeObject(System.err, pe, false);
083                    }
084            }
085    
086            private static Object _readObject(
087                            InputStream inputStream, OutputStream outputStream,
088                            boolean close)
089                    throws ClassNotFoundException, IOException {
090    
091                    if (outputStream != null) {
092                            inputStream = new UnsyncBufferedInputStream(inputStream);
093    
094                            // Mark ObjectInputStream's magic header
095    
096                            inputStream.mark(4);
097                    }
098    
099                    try {
100                            ObjectInputStream objectInputStream = new ObjectInputStream(
101                                    inputStream);
102    
103                            try {
104                                    return objectInputStream.readObject();
105                            }
106                            finally {
107                                    if (close) {
108                                            objectInputStream.close();
109                                    }
110                            }
111                    }
112                    catch (ObjectStreamException ose) {
113                            if (outputStream != null) {
114                                    inputStream.reset();
115    
116                                    int b = -1;
117    
118                                    while ((b = inputStream.read()) != -1) {
119                                            outputStream.write(b);
120                                    }
121    
122                                    outputStream.flush();
123    
124                                    return null;
125                            }
126                            else {
127                                    throw ose;
128                            }
129                    }
130            }
131    
132            private static void _writeObject(
133                            OutputStream outputStream, Object object, boolean close)
134                    throws IOException {
135    
136                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(
137                            outputStream);
138    
139                    try {
140                            objectOutputStream.writeObject(object);
141                    }
142                    finally {
143                            if (close) {
144                                    objectOutputStream.close();
145                            }
146                            else {
147                                    objectOutputStream.flush();
148                            }
149                    }
150            }
151    
152    }