001/*
002 * $Id: AddeThread.java,v 1.7 2011/03/24 16:06:34 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030package edu.wisc.ssec.mcidasv.servermanager;
031
032import java.io.InputStream;
033import java.io.InputStreamReader;
034
035import org.bushe.swing.event.EventBus;
036
037import edu.wisc.ssec.mcidasv.Constants;
038import edu.wisc.ssec.mcidasv.McIDASV;
039
040/**
041 * Thread that actually execs mcservl
042 */
043public class AddeThread extends Thread {
044
045    public enum McservEvent { ACTIVE, DIED, STARTED, STOPPED };
046
047    /** */
048    Process proc;
049
050    /** */
051    private final EntryStore entryStore;
052
053    public AddeThread(final EntryStore entryStore) {
054        this.entryStore = entryStore;
055    }
056
057    public void run() {
058        StringBuffer err = new StringBuffer();
059        String[] cmds = entryStore.getAddeCommands();
060        String[] env = (McIDASV.isWindows()) ? entryStore.getWindowsAddeEnv() : entryStore.getUnixAddeEnv();
061        try {
062            //start ADDE binary with "-p PORT" and set environment appropriately
063            proc = Runtime.getRuntime().exec(cmds, env);
064
065            //create thread for reading inputStream (process' stdout)
066            StreamReaderThread outThread = new StreamReaderThread(proc.getInputStream(), new StringBuffer());
067
068            //create thread for reading errorStream (process' stderr)
069            StreamReaderThread errThread = new StreamReaderThread(proc.getErrorStream(), err);
070
071            //start both threads
072            outThread.start();
073            errThread.start();
074
075            //wait for process to end
076            int result = proc.waitFor();
077
078            //finish reading whatever's left in the buffers
079            outThread.join();
080            errThread.join();
081
082            if (result != 0) {
083                entryStore.stopLocalServer(entryStore.getRestarting());
084                String errString = err.toString();
085
086                // If the server couldn't start for a known reason, try again on another port
087                //  Retry up to 10 times
088                if ((result==35584 || errString.indexOf("Error binding to port") >= 0) &&
089                        Integer.parseInt(EntryStore.getLocalPort()) < Integer.parseInt(Constants.LOCAL_ADDE_PORT) + 10) {
090                    EntryStore.setLocalPort(EntryStore.nextLocalPort());
091                    entryStore.startLocalServer(entryStore.getRestarting());
092                }
093            }
094        } catch (InterruptedException e) {
095            McservEvent type = McservEvent.DIED;
096            if (entryStore.getRestarting()) {
097                type = McservEvent.STARTED;
098            }
099            EventBus.publish(type);
100        } catch (Exception e) {
101            EventBus.publish(McservEvent.DIED);
102        }
103    }
104
105    /**
106     * 
107     */
108    public void stopProcess() {
109        proc.destroy();
110    }
111
112//    /**
113//     * 
114//     */
115//    public String toString() {
116//        return String.format("[AddeThread@%x: ADDE_ENV=%s, ADDE_COMMANDS=%s]", hashCode(), ADDE_ENV, ADDE_COMMANDS);
117//    }
118
119    /**
120     * Thread to read the stderr and stdout of mcservl
121     */
122    private static class StreamReaderThread extends Thread {
123        /** */
124        private final StringBuffer mOut;
125
126        /** */
127        private final InputStreamReader mIn;
128
129        /** */
130        public StreamReaderThread(final InputStream in, final StringBuffer out) {
131            mOut = out;
132            mIn = new InputStreamReader(in);
133        }
134
135        /** */
136        public void run() {
137            int ch;
138            try {
139                while (-1 != (ch = mIn.read())) {
140                    mOut.append((char)ch);
141                }
142            } catch (Exception e) {
143                mOut.append("\nRead error: "+e.getMessage());
144            }
145        }
146    }
147}