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