001 /*
002 * $Id: AddeThread.java,v 1.11 2012/04/23 15:32:55 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
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 */
030 package edu.wisc.ssec.mcidasv.servermanager;
031
032 import java.io.InputStream;
033 import java.io.InputStreamReader;
034
035 import org.bushe.swing.event.EventBus;
036
037 import edu.wisc.ssec.mcidasv.Constants;
038 import edu.wisc.ssec.mcidasv.McIDASV;
039
040 /**
041 * Thread that actually execs mcservl
042 */
043 public class AddeThread extends Thread {
044
045 /** Mcserv events. */
046 public enum McservEvent {
047 /** Mcservl is actively listening. */
048 ACTIVE("Local servers are running."),
049 /** Mcservl has died unexpectedly. */
050 DIED("Local servers quit unexpectedly."),
051 /** Mcservl started listening. */
052 STARTED("Local servers started listening on port %s."),
053 /** Mcservl has stopped listening. */
054 STOPPED("Local servers have been stopped.");
055
056 /** */
057 private final String message;
058
059 /**
060 * Creates an object that represents the status of a mcservl process.
061 *
062 * @param message Should not be {@code null}.
063 */
064 private McservEvent(final String message) {
065 this.message = message;
066 }
067
068 /**
069 *
070 *
071 * @return Format string associated with an event.
072 */
073 public String getMessage() {
074 return message;
075 }
076 };
077
078 /** */
079 Process proc;
080
081 /** Server manager. */
082 private final EntryStore entryStore;
083
084 /**
085 * Creates a thread that controls a mcservl process.
086 *
087 * @param entryStore Server manager.
088 */
089 public AddeThread(final EntryStore entryStore) {
090 this.entryStore = entryStore;
091 }
092
093 public void run() {
094 StringBuilder err = new StringBuilder();
095 String[] cmds = entryStore.getAddeCommands();
096 String[] env = (McIDASV.isWindows()) ? entryStore.getWindowsAddeEnv() : entryStore.getUnixAddeEnv();
097 try {
098 //start ADDE binary with "-p PORT" and set environment appropriately
099 proc = Runtime.getRuntime().exec(cmds, env);
100
101 //create thread for reading inputStream (process' stdout)
102 StreamReaderThread outThread = new StreamReaderThread(proc.getInputStream(), new StringBuilder());
103
104 //create thread for reading errorStream (process' stderr)
105 StreamReaderThread errThread = new StreamReaderThread(proc.getErrorStream(), err);
106
107 //start both threads
108 outThread.start();
109 errThread.start();
110
111 //wait for process to end
112 int result = proc.waitFor();
113
114 //finish reading whatever's left in the buffers
115 outThread.join();
116 errThread.join();
117
118 if (result != 0) {
119 // entryStore.stopLocalServer(entryStore.getRestarting());
120 entryStore.stopLocalServer();
121 String errString = err.toString();
122
123 // If the server couldn't start for a known reason, try again on another port
124 // Retry up to 10 times
125 if ((result==35584 || errString.indexOf("Error binding to port") >= 0) &&
126 Integer.parseInt(EntryStore.getLocalPort()) < Integer.parseInt(Constants.LOCAL_ADDE_PORT) + 30) {
127 EntryStore.setLocalPort(EntryStore.nextLocalPort());
128 // entryStore.startLocalServer(entryStore.getRestarting());
129 entryStore.startLocalServer();
130 }
131 }
132 } catch (InterruptedException e) {
133 McservEvent type = McservEvent.DIED;
134 // if (entryStore.getRestarting()) {
135 type = McservEvent.STARTED;
136 // }
137 EventBus.publish(type);
138 } catch (Exception e) {
139 EventBus.publish(McservEvent.DIED);
140 }
141 }
142
143 /**
144 *
145 */
146 public void stopProcess() {
147 proc.destroy();
148 }
149
150 // /**
151 // *
152 // */
153 // public String toString() {
154 // return String.format("[AddeThread@%x: ADDE_ENV=%s, ADDE_COMMANDS=%s]", hashCode(), ADDE_ENV, ADDE_COMMANDS);
155 // }
156
157 /**
158 * Thread to read the stderr and stdout of mcservl
159 */
160 private static class StreamReaderThread extends Thread {
161 /** */
162 private final StringBuilder mOut;
163
164 /** */
165 private final InputStreamReader mIn;
166
167 /** */
168 public StreamReaderThread(final InputStream in, final StringBuilder out) {
169 mOut = out;
170 mIn = new InputStreamReader(in);
171 }
172
173 /** */
174 public void run() {
175 int ch;
176 try {
177 while (-1 != (ch = mIn.read())) {
178 mOut.append((char)ch);
179 }
180 } catch (Exception e) {
181 mOut.append("\nRead error: "+e.getMessage());
182 }
183 }
184 }
185 }