1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.cb.jset.client;
21
22 import org.cb.jset.CardSet;
23 import org.cb.jset.MatchingException;
24 import org.cb.jset.CardProperties;
25 import org.cb.jset.server.RemoteSetGame;
26 import org.cb.jset.server.RemoteSetGamePlayer;
27 import org.cb.jset.server.RemoteSetGameConnection;
28
29 import org.apache.log4j.Logger;
30
31 import java.rmi.RemoteException;
32 import java.rmi.NoSuchObjectException;
33 import java.rmi.server.UnicastRemoteObject;
34 import java.io.Serializable;
35
36 /***
37 * FIXME document
38 *
39 * @author jerome@coffeebreaks.org - last modified by $LastModifiedBy$
40 * @version $Id: NetworkGame.java 129 2004-04-15 05:00:43Z jerome $
41 */
42 public class NetworkGame extends AbstractGame
43 {
44 private Logger _logger = Logger.getLogger(NetworkGame.class);
45
46 private RemoteSetGame _remoteGame;
47 private PlayerRemoteGame _playerRemoteGame;
48 private RemoteSetGameConnection _gameConnection;
49 private final String _clientName;
50
51 private boolean _wasDisconnected;
52
53 public NetworkGame(final String clientName)
54 {
55 _clientName = clientName;
56 }
57
58 static class PlayerRemoteGame implements RemoteSetGamePlayer, Serializable
59 {
60 private final transient Logger _logger = Logger.getLogger(PlayerRemoteGame.class);
61 private boolean _isBlocked;
62 private final String _clientName;
63 private transient final NetworkGame _game;
64
65 public PlayerRemoteGame(final NetworkGame game, final String clientName)
66 {
67 _game = game;
68 _clientName = clientName;
69 }
70
71 public String getName() throws RemoteException
72 {
73 return _clientName;
74 }
75
76 public void block() throws RemoteException
77 {
78 _isBlocked = true;
79
80 }
81
82 public void unblock() throws RemoteException
83 {
84 _isBlocked = false;
85
86 }
87
88 public boolean isBlocked() throws RemoteException
89 {
90 return _isBlocked;
91 }
92
93 public void disconnect() throws RemoteException
94 {
95 _game.setWasDisconnected(true);
96 }
97
98 public void cardsAdded(final CardProperties[] cards) throws RemoteException
99 {
100 _logger.debug("Cards Added " + CardProperties.toString(cards));
101 _game.fireCardsAdded(cards);
102 }
103
104 public void setRemoved(final CardSet set) throws RemoteException
105 {
106 _logger.debug("Set removed " + set);
107 _game.fireSetRemoved(set);
108 }
109
110 void registerClient()
111 throws RemoteException
112 {
113 UnicastRemoteObject.exportObject(this);
114 }
115
116 private void unregisterClient()
117 throws NoSuchObjectException
118 {
119 final boolean lUnexported = UnicastRemoteObject.unexportObject(this, false);
120 if (!lUnexported)
121 {
122 _logger.warn("Failure to unexport. Calls pending!! trying to force");
123 final boolean lUnexportedSecondTry = UnicastRemoteObject.unexportObject(this, true);
124 _logger.info("Managed to disconnect? " + lUnexportedSecondTry);
125 }
126 }
127
128 }
129
130 public void setRemoteGame(final RemoteSetGame remoteGame)
131 {
132 _remoteGame = remoteGame;
133 }
134
135 public void start()
136 {
137 _playerRemoteGame = new PlayerRemoteGame(this, _clientName);
138 final GameThread thread = new GameThread();
139
140
141 thread.start();
142 }
143
144
145 private void connect() throws RemoteException
146 {
147 _gameConnection = _remoteGame.connect(_playerRemoteGame);
148 }
149
150
151 public synchronized void setWasDisconnected(final boolean wasDisconnected)
152 {
153 _wasDisconnected = wasDisconnected;
154 notifyAll();
155 }
156
157 public synchronized boolean wasDisconnected()
158 {
159 return _wasDisconnected;
160 }
161
162 public void stop()
163 {
164 try
165 {
166 _gameConnection.close();
167 }
168 catch (RemoteException e)
169 {
170 _logger.debug("Failure to stop game " + e.getMessage(), e);
171 setWasDisconnected(true);
172 }
173 }
174
175 public void endTurn()
176 {
177
178 }
179
180 public void removeSet(final CardSet set) throws MatchingException
181 {
182 try
183 {
184 _gameConnection.matchSet(set);
185 }
186 catch (RemoteException e)
187 {
188 _logger.debug("Failure to remove set " + e.getMessage(), e);
189 setWasDisconnected(true);
190 }
191 }
192
193
194 private void forceCloseConnection()
195 {
196 try
197 {
198
199 if (_gameConnection != null && !this.wasDisconnected())
200 {
201 if (_logger.isInfoEnabled())
202 {
203 _logger.info("May have caught a CTRL-C");
204 }
205 _gameConnection.close();
206 }
207 }
208 catch (RemoteException e)
209 {
210 _logger.error("Communication problem while closing.", e);
211 }
212 }
213
214 void play() throws RemoteException
215 {
216
217 if (_logger.isInfoEnabled())
218 {
219 _logger.info("-- starting to play --");
220 }
221 while (! (_gameConnection.isClosed() && this.wasDisconnected()))
222 {
223 if (_logger.isInfoEnabled())
224 {
225 _logger.info("-- wait for cards to be added --");
226 }
227 synchronized (this)
228 {
229 try
230 {
231 this.wait();
232 }
233 catch (InterruptedException e)
234 {
235 }
236 }
237 }
238 if (_logger.isInfoEnabled())
239 {
240 _logger.info("-- player dying --");
241 }
242 }
243
244 void addShutdownHook()
245 {
246 Runtime.getRuntime().addShutdownHook(new Thread()
247 {
248 public void run()
249 {
250 forceCloseConnection();
251 }
252 });
253 }
254
255 private class GameThread extends Thread
256 {
257 public void run()
258 {
259 addShutdownHook();
260 try
261 {
262 registerClient();
263 try
264 {
265 connect();
266 play();
267 }
268 catch (RemoteException e)
269 {
270 _logger.error("Communication error in run().", e);
271 }
272 finally
273 {
274 unregisterClient();
275 }
276 }
277 catch (RemoteException e)
278 {
279 _logger.error("Couldn't export Client object properly.", e);
280 }
281 finally
282 {
283
284
285 _gameConnection = null;
286 }
287 if (_logger.isInfoEnabled())
288 {
289 _logger.info("player ending...");
290 }
291 }
292
293 private void registerClient()
294 throws RemoteException
295 {
296 UnicastRemoteObject.exportObject(_playerRemoteGame);
297 }
298
299 private void unregisterClient()
300 throws NoSuchObjectException
301 {
302 final boolean lUnexported = UnicastRemoteObject.unexportObject(_playerRemoteGame, false);
303 if (!lUnexported)
304 {
305 _logger.warn("Failure to unexport. Calls pending!! trying to force");
306 final boolean lUnexportedSecondTry = UnicastRemoteObject.unexportObject(_playerRemoteGame, true);
307 _logger.info("Managed to disconnect? " + lUnexportedSecondTry);
308 }
309 }
310 }
311 }