source: trunk/src/org/expeditee/network/FrameShare.java@ 843

Last change on this file since 843 was 843, checked in by jts21, 10 years ago

Implement uploading images to FrameServer so other people can see them

File size: 14.0 KB
Line 
1package org.expeditee.network;
2
3import java.io.BufferedReader;
4import java.io.File;
5import java.io.IOException;
6import java.io.InputStream;
7import java.io.OutputStream;
8import java.io.StringReader;
9import java.io.StringWriter;
10import java.net.DatagramPacket;
11import java.net.DatagramSocket;
12import java.net.InetAddress;
13import java.net.Socket;
14import java.net.SocketException;
15import java.net.UnknownHostException;
16import java.util.Collection;
17import java.util.HashMap;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Map;
21
22import org.expeditee.gui.AttributeValuePair;
23import org.expeditee.gui.Frame;
24import org.expeditee.gui.FrameIO;
25import org.expeditee.gui.MessageBay;
26import org.expeditee.io.ExpReader;
27import org.expeditee.io.ExpWriter;
28import org.expeditee.io.FrameReader;
29import org.expeditee.io.FrameWriter;
30import org.expeditee.items.Item;
31import org.expeditee.items.Picture;
32import org.expeditee.items.Text;
33import org.expeditee.settings.network.NetworkSettings;
34
35public class FrameShare {
36
37 public static boolean disableNetworking = false;
38
39 private static Collection<DefaultServer> _servers = new LinkedList<DefaultServer>();
40
41 private static FrameShare _theSession;
42
43 private Map<String, Peer> _peers;
44
45 private int _port = Peer.DEFAULT_PORT;
46
47
48 private void startServers() throws IOException
49 {
50 System.err.println("Starting Expeditee Server on port " + _port);
51 _servers.add(new FrameServer(_port));
52 _servers.add(new FrameSaver(_port));
53 _servers.add(new MessageReciever(_port));
54 _servers.add(new InfServer(_port));
55 _servers.add(new InfUpdate(_port));
56 _servers.add(new ImageServer(_port));
57 _servers.add(new ImageSaver(_port));
58
59 }
60
61 private FrameShare() {
62 _peers = new HashMap<String, Peer>();
63 }
64
65 private FrameShare(int port) {
66 this();
67 _port = port;
68
69 try {
70 startServers();
71
72 } catch (Exception e) {
73 e.printStackTrace();
74 System.err.println("Could not start servers [port: "
75 + port + "]");
76 }
77
78 try {
79 for (DefaultServer server : _servers) {
80 server.start();
81 }
82 } catch (Exception e) {
83 System.err.println("Error in server startup");
84 }
85 }
86
87
88 private FrameShare(Frame settingsFrame)
89 {
90 this();
91
92 // Set the settings
93 for (Text item : settingsFrame.getBodyTextItems(false)) {
94
95 AttributeValuePair avp = new AttributeValuePair(item.getText());
96 if (avp.isAnnotation())
97 continue;
98
99 String attribute = avp.getAttributeOrValue().toLowerCase();
100
101 if (attribute.equals("server")) {
102 try {
103 if (avp.hasPair()) {
104 _port = avp.getIntegerValue();
105 }
106 MessageBay.displayMessage("Starting Expeditee Server on port: " + _port);
107
108 startServers();
109 } catch (Exception e) {
110 e.printStackTrace();
111 MessageBay.errorMessage("Could not start servers ["
112 + avp.toString() + "]");
113 }
114 continue;
115 }
116
117 if (!avp.hasPair())
118 continue;
119
120 try {
121 Peer peer = new Peer(avp);
122 _peers.put(attribute, peer);
123 } catch (UnknownHostException e) {
124 MessageBay.errorMessage("Could not locate peer ["
125 + avp.toString() + "]");
126 }
127 }
128
129 try {
130 for (DefaultServer server : _servers) {
131 server.start();
132 }
133 } catch (Exception e) {
134 MessageBay.errorMessage("Error in PeerToPeer setup");
135 }
136 }
137
138 public void finalise() {
139 System.err.println("Closing servers");
140
141 for (DefaultServer server : _servers)
142 server.close();
143 }
144
145 public static FrameShare getInstance() {
146 return _theSession;
147 }
148
149 /**
150 * TODO check each peer on a different thread.
151 *
152 * @param frameName
153 * @return
154 */
155 public Frame loadFrame(String frameName, String peerName) {
156 String result = null;
157
158 try {
159 // get a datagram socket
160 DatagramSocket socket = new DatagramSocket();
161 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get() * 2);
162 if (peerName == null) {
163 for (Peer peer : _peers.values()) {
164 try {
165 result = getFrameContents(frameName, socket, peer);
166 if(result == null || result.length() == 0) {
167 continue;
168 }
169 peerName = peer.getName();
170 break;
171 } catch (Exception e) {
172 e.printStackTrace();
173 }
174 }
175 } else {
176 try {
177 Peer peer = _peers.get(peerName.toLowerCase());
178 if (peer != null) {
179 result = getFrameContents(frameName, socket, peer);
180 }
181 } catch (Exception e) {
182 e.printStackTrace();
183 }
184 }
185 socket.close();
186 } catch (Exception e) {
187 e.printStackTrace();
188 }
189
190 if (result == null || result.length() == 0)
191 return null;
192
193 // Now read the frame from the file contents
194 FrameReader reader = new ExpReader(frameName);
195 Frame frame = null;
196 try {
197 frame = reader.readFrame(new BufferedReader(
198 new StringReader(result)));
199 // Set the path for the frame to indicate it is NOT a local frame
200 // This allows the frame to be saved in the correct location
201 frame.setLocal(false);
202 frame.setPath(peerName);
203 } catch (IOException e) {
204 e.printStackTrace();
205 }
206
207 if (frame == null) {
208 MessageBay.errorMessage("Error: " + frameName
209 + " could not be successfully loaded.");
210 return null;
211 }
212
213 return frame;
214 }
215
216 /**
217 * Downloads an image from the server (if it exists),
218 * Saves it locally in the default image folder,
219 * Then returns the filename
220 *
221 * @param imageName
222 * @param peerName
223 * @return true if the image was successfully downloaded and saved in the default images folder
224 */
225 public boolean loadImage(String imageName, String peerName) {
226 boolean result = false;
227 try {
228 if (peerName == null) {
229 for (Peer peer : _peers.values()) {
230 try {
231 result = getImage(imageName, peer);
232 if(!result) {
233 continue;
234 }
235 peerName = peer.getName();
236 break;
237 } catch (Exception e) {
238 e.printStackTrace();
239 }
240 }
241 } else {
242 try {
243 Peer peer = _peers.get(peerName.toLowerCase());
244 if (peer != null) {
245 result = getImage(imageName, peer);
246 }
247 } catch (Exception e) {
248 e.printStackTrace();
249 }
250 }
251 } catch(Exception e) {
252 e.printStackTrace();
253 }
254 return result;
255 }
256
257 /**
258 * Send a list of images that may need to be uploaded
259 * Then wait for a response (in form of a list of shorts denoting which files to keep)
260 * Then send each file in sequence
261 * @author jts21
262 *
263 */
264 private class ImageSender extends Thread {
265
266 private List<File> imageFiles;
267 private Peer peer;
268
269 public ImageSender(List<File> imageFiles, Peer peer) {
270 super("ImageSender");
271 this.imageFiles = imageFiles;
272 this.peer = peer;
273 }
274
275 @Override
276 public void run() {
277 System.out.println("Sending images to server");
278 try(Socket socket = new Socket(peer.getAddress(), peer.getPort() + ImageSaver.OFFSET)) {
279 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get() * 2);
280 OutputStream os = socket.getOutputStream();
281 // send the list of filenames to the server
282 int numFiles = imageFiles.size();
283 if(numFiles > 255) {
284 throw new Exception("Too many images on the frame");
285 }
286 os.write((byte) (numFiles & 0xFF));
287 // send the list of different files
288 for(File f : imageFiles) {
289 byte[] fileName = f.getName().getBytes();
290 int fileNameLen = fileName.length;
291 if(fileNameLen > 255) {
292 throw new Exception("Filename too long");
293 }
294 os.write((byte) ((fileNameLen) & 0xFF));
295 os.write(fileName);
296 }
297 // the server sends indices of files it wants, send their data
298 InputStream is = socket.getInputStream();
299 int i = -1;
300 while((i = is.read()) != -1 && i < imageFiles.size()) {
301 File f = imageFiles.get(i);
302 System.out.println("... sending " + f.getName());
303 ImageServer.sendImage(f, socket);
304 }
305 } catch(Exception e) {
306 e.printStackTrace();
307 }
308 }
309 }
310
311 private boolean getImage(String imageName, Peer peer) throws IOException {
312 try(Socket socket = new Socket(peer.getAddress(), peer.getPort() + ImageServer.OFFSET)) {
313 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get() * 2);
314 byte[] fileName = imageName.getBytes(ImageServer.CHARSET);
315 int fileNameLen = fileName.length;
316 OutputStream os = socket.getOutputStream();
317 os.write((byte) ((fileNameLen) & 0xFF));
318 os.write(fileName);
319 os.flush();
320 socket.shutdownOutput();
321 boolean ret = ImageSaver.recvImage(new File(FrameIO.IMAGES_PATH + imageName), socket);
322 socket.close();
323 return ret;
324 } catch(Exception e) {
325 e.printStackTrace();
326 return false;
327 }
328 }
329
330 /**
331 * @param frameName
332 * @param socket
333 * @param peer
334 * @return
335 * @throws IOException
336 */
337 private String getFrameContents(String frameName, DatagramSocket socket, Peer peer) throws IOException {
338 byte[] nameBuf = frameName.getBytes();
339 byte[] buf = new byte[FrameServer.MAX_PACKET_LENGTH];
340 // send request for a frame
341 DatagramPacket packet = new DatagramPacket(nameBuf,
342 nameBuf.length, peer.getAddress(), peer
343 .getPort());
344 socket.send(packet);
345
346 // get response
347 packet = new DatagramPacket(buf, buf.length);
348 socket.receive(packet);
349
350 // store frame contents
351 return new String(packet.getData(), 0, packet
352 .getLength());
353 }
354
355 public boolean sendMessage(String message, String peerName) {
356 Peer peer = _peers.get(peerName.toLowerCase());
357
358 if (peer == null) {
359 return false;
360 }
361
362 try {
363 // get a datagram socket
364 DatagramSocket socket = new DatagramSocket(_port - 1);
365 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get());
366
367 // message = peerName + " says " + message;
368 byte[] contentsBuf = message.getBytes();
369
370 try {
371 // send save request
372 DatagramPacket packet = new DatagramPacket(contentsBuf,
373 contentsBuf.length, peer.getAddress(), peer.getPort()
374 + MessageReciever.OFFSET);
375 socket.send(packet);
376 } catch (Exception e) {
377 e.printStackTrace();
378 }
379 socket.close();
380
381 } catch (IOException e) {
382 e.printStackTrace();
383 }
384 return true;
385 }
386
387 public String saveFrame(Frame toSave) {
388
389 FrameIO.setSavedProperties(toSave);
390
391 Peer peer = _peers.get(toSave.getPath().toLowerCase());
392
393 List<File> imageFiles = new LinkedList<File>();
394 for(Item i : toSave.getItems()) {
395 if(i instanceof Picture) {
396 ((Picture) i).moveToImagesFolder();
397 File f = new File(((Picture) i).getPath());
398 if(f != null && f.isFile() && !imageFiles.contains(f)) {
399 imageFiles.add(f);
400 }
401 }
402 }
403 new ImageSender(imageFiles, peer).start();
404
405 String fileContents = "";
406 // Now read the frame from the file contents
407 FrameWriter writer = new ExpWriter();
408 try {
409 // String tempName = new Date().toString() + ".exp";
410 // writer.setOutputLocation(tempName);
411 // Write out the file to a StringBuffer
412 StringWriter sw = new StringWriter();
413 // First write out the name of the frame
414 sw.write(toSave.getName() + "\n");
415 // Then the version
416 sw.write(toSave.getVersion() + "\n");
417 // Write out the rest of the frame
418 writer.writeFrame(toSave, sw);
419 // Now send the packet
420 fileContents = sw.getBuffer().toString();
421 byte[] contentsBuf = fileContents.getBytes();
422
423 // get a datagram socket
424 DatagramSocket socket = new DatagramSocket(_port - 2);
425 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get());
426
427 try {
428 // send save request
429 DatagramPacket packet = new DatagramPacket(contentsBuf,
430 contentsBuf.length, peer.getAddress(), peer.getPort()
431 + FrameSaver.OFFSET);
432 socket.send(packet);
433 } catch (Exception e) {
434 e.printStackTrace();
435 }
436 socket.close();
437
438 } catch (IOException e) {
439 e.printStackTrace();
440 }
441 toSave.setSaved();
442 return fileContents;
443 }
444
445 public String getPeerName(int port, InetAddress address) {
446 for (Peer p : _peers.values()) {
447 if (p.getPort() == port && p.getAddress().equals(address))
448 return p.getName();
449 }
450 return null;
451 }
452
453 public int getInfNumber(String peerName, String frameset, boolean update)
454 throws IOException {
455 int result = -1;
456 // get a datagram socket
457 DatagramSocket socket = null;
458 try {
459 socket = new DatagramSocket(_port - 3);
460 socket.setSoTimeout(NetworkSettings.FrameShareTimeout.get());
461
462 byte[] contentsBuf = frameset.getBytes();
463 Peer peer = _peers.get(peerName.toLowerCase());
464 if(peer != null) {
465 try {
466 // send inf request
467 DatagramPacket packet = new DatagramPacket(
468 contentsBuf,
469 contentsBuf.length,
470 peer.getAddress(),
471 peer.getPort()
472 + (update ? InfUpdate.OFFSET : InfServer.OFFSET));
473 socket.send(packet);
474
475 byte[] buf = new byte[100];
476 // get response
477 packet = new DatagramPacket(buf, buf.length);
478 socket.receive(packet);
479
480 // store frame contents
481 result = Integer.parseInt(new String(packet.getData(), 0,
482 packet.getLength()));
483 peerName = peer.getName();
484
485 } catch (Exception e) {
486 e.printStackTrace();
487 }
488 }
489 socket.close();
490 } catch (SocketException e1) {
491 e1.printStackTrace();
492 }
493
494 return result;
495 }
496
497 public static void init(Frame settingsFrame) {
498 if (disableNetworking || settingsFrame == null)
499 return;
500
501 if (_theSession == null)
502 _theSession = new FrameShare(settingsFrame);
503 }
504
505 public static void init(int port) {
506
507 if (_theSession == null) {
508 _theSession = new FrameShare(port);
509 }
510 }
511
512
513 /**
514 * Start a server running on the port number supplied on the command line
515 *
516 * @param args
517 */
518 public static void main(String[] args) {
519
520 if (args.length != 1) {
521
522 // Work out the 'program name' (i.e. this class), but done in a general
523 // way in case class name is changed at a later date
524 StackTraceElement[] stack = Thread.currentThread ().getStackTrace ();
525 StackTraceElement main = stack[stack.length - 1];
526 String mainClass = main.getClassName ();
527
528 System.err.println("Usage: java " + mainClass + " port-number");
529 System.exit(1);
530 }
531
532 MessageBay.suppressMessages(true);
533
534 String port_str = args[0];
535
536 try {
537 int port = Integer.parseInt(port_str);
538
539 init(port);
540 }
541 catch (Exception e) {
542 e.printStackTrace();
543 System.exit(2);
544 }
545
546 }
547
548}
Note: See TracBrowser for help on using the repository browser.