1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package aigames.soccer.observer;
21
22 import org.apache.log4j.Logger;
23
24 import org.dom4j.Document;
25 import org.dom4j.DocumentException;
26 import org.dom4j.DocumentHelper;
27 import org.dom4j.Element;
28
29 import org.dom4j.io.SAXReader;
30
31 import java.io.BufferedReader;
32 import java.io.ByteArrayInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.PrintWriter;
37
38 import java.net.Socket;
39 import java.net.UnknownHostException;
40
41
42 /***
43 * The observer communication class.
44 * @version $Id: Communication.java,v 1.7 2004/05/08 21:55:29 mwerla Exp $
45 */
46 public class Communication implements Runnable {
47 private static Logger logger = Logger.getLogger(Communication.class);
48
49
50 private static String inlineEOT = "\004";
51
52
53 private static String EOT = "\n" + inlineEOT + "\n";
54 private static int ACCEPTED = 101;
55 private static int NOT_ACCEPTED = 202;
56 private static int REFUSED = 303;
57 private Socket socket;
58 private Document doc;
59 private PrintWriter out = null;
60 private BufferedReader in = null;
61 private Observer observer;
62 private boolean active;
63
64 /***
65 * Connect to a server.
66 * @param ip
67 * @param port
68 * @throws Exception Thrown when connection fails.
69 */
70 public void connect(String ip, int port) throws Exception {
71 try {
72 socket = new Socket(ip, port);
73 out = new PrintWriter(socket.getOutputStream(), false);
74 in = new BufferedReader(new InputStreamReader(
75 socket.getInputStream()));
76 } catch (UnknownHostException e) {
77 logger.error("Unknown host: " + ip);
78 throw new Exception();
79 } catch (Exception e) {
80 logger.error(ip + ": " + e.getMessage());
81 throw new Exception();
82 }
83
84 active = true;
85 }
86
87 /***
88 * Disconnect from a server.
89 * @throws Exception Thrown when disconnection fails.
90 */
91 public void disconnect() throws Exception {
92 try {
93 out.close();
94 in.close();
95 socket.close();
96 } catch (IOException e) {
97 logger.error("Stream closing error: " + e.getMessage());
98 throw new Exception();
99 }
100 }
101
102 /***
103 * Introduce the observer to a server.
104 * @param name observer name
105 * @throws Exception Thrown when message acceptation read fails.
106 */
107 public void sayHello(String name) throws Exception {
108 Document hello = DocumentHelper.createDocument();
109 Element message = hello.addElement("message");
110 message.addAttribute("type", "hello");
111 message.addAttribute("id", "1");
112 message.addElement("mod-type").setText("observer");
113 message.addElement("name").setText(name);
114
115 int answer;
116 int counter = 0;
117
118 do {
119 ++counter;
120 sendMessage(hello);
121 answer = isMessageAccepted("1");
122 } while ((NOT_ACCEPTED == answer) && (counter < 3));
123 }
124
125 /***
126 * Read and parse a message from a socket.
127 * @param confirm if true the confirmation will be send
128 * @return dom4j Document
129 * @throws Exception Thrown on read or parse error.
130 */
131 public Document readMessage(boolean confirm) throws Exception {
132 StringBuffer buffer = null;
133 String message = null;
134
135 try {
136 buffer = new StringBuffer();
137
138 while (false == in.ready()) {
139 Thread.sleep(100);
140 }
141
142 while (null != (message = in.readLine())) {
143 if (message.equals(inlineEOT)) {
144 break;
145 }
146
147 buffer.append(message);
148 }
149 } catch (IOException e) {
150 logger.error("I/O error: " + e.getMessage());
151 throw new Exception();
152 }
153
154 String xml = buffer.toString();
155
156 if (null != xml) {
157 InputStream stream = new ByteArrayInputStream(xml.getBytes());
158 SAXReader reader = new SAXReader();
159
160 try {
161 doc = reader.read(stream);
162 } catch (DocumentException e) {
163 logger.error("Parsing error: " + e.getMessage());
164 throw new Exception();
165 }
166
167 if (confirm) {
168 sendConfirmation();
169 }
170 } else {
171 doc = null;
172 }
173
174 return doc;
175 }
176
177 /***
178 * Read a list of games.
179 * @return list
180 */
181 public String[] getGamesList() {
182
183 String[] list = new String[3];
184 list[0] = "Red vs. Blue";
185 list[1] = "PathExtractor vs. MegaMózg";
186 list[2] = "Runner vs. Runner";
187
188 return list;
189 }
190
191 /***
192 * Chosing a game on the server to observe.
193 * @param name of the game
194 */
195 public void chooseGame(String name) {
196
197 }
198
199 /***
200 * Sending message as xml.
201 * @param message dom4j Document
202 */
203 private void sendMessage(Document message) {
204 String xml = message.asXML() + EOT;
205 out.print(xml);
206 out.flush();
207 }
208
209 /***
210 * Confirming that the message was received.
211 */
212 private void sendConfirmation() {
213 String id = doc.valueOf("//message/@id");
214 Document confirm = DocumentHelper.createDocument();
215
216 Element message = confirm.addElement("message");
217 message.addAttribute("type", "confirmation");
218 message.addAttribute("id", id);
219 message.addElement("accepted");
220 sendMessage(confirm);
221 }
222
223 /***
224 * Check message confirmation from a server.
225 * @param id message id
226 * @return state of confirmation
227 * @throws Exception Thrown on read error.
228 */
229 private int isMessageAccepted(String id) throws Exception {
230 readMessage(false);
231
232 String type = doc.valueOf("//message/@type");
233
234 if (!type.equals("confirmation")) {
235 return NOT_ACCEPTED;
236 }
237
238 String confirmedId = doc.valueOf("//message/@id");
239
240 if (!id.equals(confirmedId)) {
241 return NOT_ACCEPTED;
242 }
243
244 String reason = doc.valueOf("//message/refused");
245
246 if (!reason.equals("")) {
247 logger.error("Message refused with: " + reason);
248
249 return REFUSED;
250 }
251
252 return ACCEPTED;
253 }
254
255 /***
256 * Setter for observer object.
257 * @param observer
258 */
259 public void setObserver(Observer observer) {
260 this.observer = observer;
261 }
262
263 /***
264 * Stops the reading loop.
265 */
266 public void shutdown() {
267 active = false;
268 }
269
270 /***
271 * @see java.lang.Runnable#run()
272 */
273 public void run() {
274 while (active) {
275 try {
276 readMessage(true);
277 } catch (Exception e) {
278 try {
279 disconnect();
280
281 return;
282 } catch (Exception ee) {
283 return;
284 }
285 }
286
287 if (null != doc) {
288 observer.processMessage(doc);
289 }
290 }
291
292 return;
293 }
294 }