1
2
3
4
5
6
7 package org.sourceforge.jvb3d.Network;
8
9 import java.io.IOException;
10 import java.net.InetSocketAddress;
11 import java.net.SocketException;
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Observable;
18 import java.util.Observer;
19 import java.util.logging.Logger;
20
21 /***
22 * @author Łukasz Krzyżak
23 *
24 * Klasa odpowiada za obsługę komunikacji pomiędzy serwerem a klientami. Odbiera
25 * pakiety wysyłane przez klientów, analizuje i przekazuje do dalszej obróbki,
26 * oraz rozsyła informacje od serwera do klientów
27 */
28 public class ClientManager implements Observer {
29 private Map<InetSocketAddress, ClientData> clients = new HashMap<InetSocketAddress, ClientData>();
30
31 private NetworkServerFacade serverFacade = null;
32
33 private ClientFactory clientFactory = null;
34
35 private Logger fLogger = Logger.getLogger("ClientManager");
36
37 private List<InetSocketAddress> timeoutedClients = new LinkedList<InetSocketAddress>();
38
39 /***
40 * pobiera referencję do fasady
41 *
42 */
43 public ClientManager() {
44 serverFacade = NetworkServerFacadeHolder.getNetworkFacade();
45 clientFactory = serverFacade.getClientFactory();
46 }
47
48 /***
49 * metoda update - uruchamiana, gdy serwer otrzyma pakiet
50 *
51 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
52 */
53 public void update(Observable arg0, Object arg1) {
54
55 try {
56 Packet recvPacket = ((ReceivedPacketBuffer) arg0).getNextPacket();
57 if (recvPacket instanceof JoinPacket)
58 processJoinPacket((JoinPacket) recvPacket);
59 else if (recvPacket instanceof UpdatePacket)
60 processUpdatePacket((UpdatePacket) recvPacket);
61 else
62 fLogger.warning("Odebrano pakiet nieznanego typu: "
63 + recvPacket.getClass().getName());
64 } catch (Exception e) {
65 fLogger.severe("Złapano wyjątek - " + e.toString());
66 }
67 }
68
69 /***
70 * rozsyła dane podane jako parametr do wszystkich klientów. Sprawdza
71 * timeouty klientów, i powoduje usunięcie tych u których one występują.
72 *
73 * @param updateData dane do wysłania
74 * @throws IOException jeśli wystąpił błąd socketu
75 */
76 public void sendUpdate(byte[] updateData) throws IOException {
77 if (clients.size() == 0) {
78 fLogger.fine("Brak klientów do wysłania update");
79 } else {
80 Iterator<ClientData> clientIterator = clients.values().iterator();
81 timeoutedClients.clear();
82
83 while (clientIterator.hasNext()) {
84 try {
85 clientIterator.next().sendUpdate(updateData);
86 } catch (TimeoutException e) {
87 e.printStackTrace();
88 ClientData timeoutedClient = clients.get(e.getAddress());
89 serverFacade.forwardClientTimeout(timeoutedClient
90 .getAvatarID());
91 timeoutedClients.add(e.getAddress());
92 fLogger.warning("Utracono połączenie z klientem"
93 + timeoutedClient.getClientAddress());
94 }
95 }
96
97 for(InetSocketAddress client : timeoutedClients)
98 clients.remove(client);
99 }
100 }
101
102 /***
103 * metoda obsluguje pakiet JoinPacket: - jeśli klient o takim adresie już
104 * istnieje - rzucany jest wyjątek IllegalArgumentException - jesli klient
105 * nie istnieje - tworzony jest nowy, i dodawany do listy
106 *
107 * @param packet
108 * pakiet otrzymany od klienta
109 * @throws IllegalArgumentException
110 * jeśli klient już był wcześniej dodany
111 * @throws SocketException jeśli wystąpił bład socketu
112 */
113 private void processJoinPacket(JoinPacket packet) throws SocketException {
114 if (clients.containsKey(packet.getSourceAddress())) {
115 fLogger.warning("Klient z " + packet.getSourceAddress()
116 + " próbuje połączyć się drugi raz");
117 throw new IllegalArgumentException();
118 }
119 ClientData client = clientFactory.createClient(packet
120 .getSourceAddress());
121 clients.put(packet.getSourceAddress(), client);
122 fLogger.fine("Dodano klienta z " + packet.getSourceAddress());
123 }
124
125 /***
126 * obsługuje pakiet typu "update". Sprawdza w obiekcie z którego otrzymano
127 * pakiet czy jest poprawny, jeśli tak pakiet jest forwardowany na fasadę,
128 * jeśli nie umieszczany jest wpis w logach a pakiet idzie do kosza.
129 *
130 * @param packet
131 * pakiet update otrzymany z sieci
132 */
133 private void processUpdatePacket(UpdatePacket packet) {
134 ClientData client = clients.get(packet.getSourceAddress());
135 if (client == null)
136 fLogger.severe("Klient na " + packet.getSourceAddress()
137 + " nie istnieje");
138 else {
139 if (client.validatePacket(packet))
140 serverFacade.forwardUpdate(packet);
141 else
142 fLogger.warning("Klient na " + packet.getSourceAddress()
143 + " przysłał pakiet ze złym numerem seq");
144 }
145 }
146
147 /***
148 * metoda zwraca ilość połączonych klientów
149 *
150 * @return ilość połaczonych klientów
151 */
152 public int getClientCount() {
153 return clients.size();
154 }
155 }
156