View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.ui.commands;
39  
40  import java.io.InputStream;
41  import java.io.ObjectInputStream;
42  import java.io.ObjectOutputStream;
43  import java.io.OutputStream;
44  import java.net.InetSocketAddress;
45  import java.net.Socket;
46  import java.util.logging.Logger;
47  
48  /**
49   * The FFXClient class encapsulates a socket connection to an FFXServer started by an executing FFX
50   * instance. FFXSystem and FFXUpdate objects are sent by the FFXServer to the FFXClient on request.
51   *
52   * @author Michael J. Schnieders
53   */
54  public class FFXClient {
55  
56    private static final Logger logger = Logger.getLogger(FFXClient.class.getName());
57    private Socket client; // Socket connection to the server
58    private InetSocketAddress address; // Server address
59    private InputStream in; // Input from the server
60    private ObjectInputStream oin; // Input form the server
61    private OutputStream out; // Output to the server
62    private ObjectOutputStream oout; // Output to the server
63    private SimulationDefinition system; // Tinker system definition
64    private SimulationUpdate update; // Tinker update information
65    private SimulationMessage message; // Message Passed Between Client & Server
66    // Various connection status variables
67    private int retryCount = 0; // Count of Client attempts to Connect
68    private int retryLimit = 10000; // Maximum number of retries
69    private boolean connectionMade = false; // True when a connection has been
70    // made
71    // closed is True if the server closes an open connection
72    // or if the retryLimit is reached
73    private boolean closed = false;
74  
75    /** Constructor for FFXClient. */
76    public FFXClient() {
77      address = new InetSocketAddress(2000);
78    }
79  
80    /**
81     * Constructor for FFXClient.
82     *
83     * @param a a {@link java.net.InetSocketAddress} object.
84     */
85    public FFXClient(InetSocketAddress a) {
86      address = a;
87    }
88  
89    /**
90     * Constructor for FFXClient.
91     *
92     * @param port a int.
93     */
94    public FFXClient(int port) {
95      address = new InetSocketAddress(port);
96    }
97  
98    /**
99     * Attempts to connect to a Tinker FServer. If this FClient is already connected, the connection
100    * will be closed.
101    */
102   public void connect() {
103     if (client != null && client.isConnected()) {
104       release();
105     }
106     closed = false;
107     client = new Socket();
108     try {
109       client.connect(address, 100);
110       client.setTcpNoDelay(true);
111       out = client.getOutputStream();
112       oout = new ObjectOutputStream(out);
113       in = client.getInputStream();
114       oin = new ObjectInputStream(in);
115       connectionMade = true;
116       logger.info("Connected to FFX Server: " + client);
117     } catch (Exception e) {
118       client = null;
119     } finally {
120       if (client == null || !client.isConnected()) {
121         release();
122       }
123     }
124   }
125 
126   /**
127    * Getter for the field <code>system</code>.
128    *
129    * @return a {@link ffx.ui.commands.SimulationDefinition} object.
130    */
131   public SimulationDefinition getSystem() {
132     readSocket();
133     return system;
134   }
135 
136   /**
137    * Getter for the field <code>update</code>.
138    *
139    * @return a {@link ffx.ui.commands.SimulationUpdate} object.
140    */
141   public SimulationUpdate getUpdate() {
142     readSocket();
143     return update;
144   }
145 
146   /**
147    * isClosed
148    *
149    * @return a boolean.
150    */
151   public boolean isClosed() {
152     return closed;
153   }
154 
155   /**
156    * isConnected
157    *
158    * @return a boolean.
159    */
160   public boolean isConnected() {
161     if (client != null && client.isConnected()) {
162       return true;
163     }
164     return false;
165   }
166 
167   /** readSocket */
168   public void readSocket() {
169     try {
170       while (oin != null && in.available() > 0) {
171         Object o = oin.readObject();
172         if (o instanceof SimulationMessage) {
173           message = (SimulationMessage) o;
174           // logger.info(message.toString());
175           if (message.getMessage() == SimulationMessage.SYSTEM) {
176             system = (SimulationDefinition) oin.readObject();
177             system.read = false;
178           } else if (message.getMessage() == SimulationMessage.UPDATE) {
179             update = (SimulationUpdate) oin.readObject();
180             update.read = false;
181           } else if (message.getMessage() == SimulationMessage.CLOSING) {
182             closed = true;
183             release();
184           }
185         }
186       }
187       if (system == null) {
188         message = new SimulationMessage(SimulationMessage.SYSTEM);
189         oout.reset();
190         oout.writeObject(message);
191         oout.flush();
192       } else if (update == null || update.read) {
193         message = new SimulationMessage(SimulationMessage.UPDATE);
194         if (update != null) {
195           if (update.type == SimulationUpdate.SIMULATION) {
196             message.setTime(update.time);
197           } else {
198             message.setStep(update.step);
199           }
200         }
201         oout.reset();
202         oout.writeObject(message);
203         oout.flush();
204       }
205     } catch (Exception e) {
206       logger.warning("Exception reading data from FFX\n" + e);
207       release();
208     }
209   }
210 
211   /** release */
212   public void release() {
213     if (client == null) {
214       return;
215     }
216     retryCount++;
217     if (retryCount > retryLimit || connectionMade) {
218       closed = true;
219     }
220     if (client != null && client.isConnected() && oout != null) {
221       try {
222         SimulationMessage close = new SimulationMessage(SimulationMessage.CLOSING);
223         oout.reset();
224         oout.writeObject(close);
225         oout.flush();
226       } catch (Exception e) {
227         oout = null;
228       }
229     }
230     try {
231       if (oin != null) {
232         oin.close();
233       }
234       if (in != null) {
235         in.close();
236       }
237       if (oout != null) {
238         oout.close();
239       }
240       if (out != null) {
241         out.close();
242       }
243       if (client != null) {
244         client.close();
245       }
246     } catch (Exception e) {
247       client = null;
248     } finally {
249       in = null;
250       oin = null;
251       out = null;
252       oout = null;
253       client = null;
254     }
255   }
256 }