1 package twcsckernel.serverKernel.utils;
2
3 import java.io.IOException;
4 import java.rmi.NoSuchObjectException;
5 import java.rmi.Remote;
6 import java.rmi.RemoteException;
7 import java.rmi.server.RMISocketFactory;
8 import java.rmi.server.UnicastRemoteObject;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Map;
12 import java.util.Set;
13
14 import twcsckernel.projectbase.common.RemoteAgent;
15 import twcsckernel.projectbase.common.RemoteServer;
16 import twcsckernel.projectbase.rmi.registry.LocateRegistry;
17 import twcsckernel.projectbase.rmi.registry.RegistryImpl;
18 import twcsckernel.projectbase.rmi.socketfactory.ServerTwoWaySocketFactory;
19 import twcsckernel.serverKernel.impl.UserImpl;
20 import twcsckernel.serverKernel.usr.UserGarbageCollector;
21
22 /***
23 * Manager serwera RMI służący do odpalania serwera RMI wraz z przydzieleniem
24 * serwerowi i rejestracją podanej implementacji
25 * {@link twcsckernel.projectbase.common.RemoteServer RemoteServer}.<br/>
26 * Ponadto wyłącznie ta klasa powinna być używana do rejestrowania i
27 * wyrejestrowywania obiektów zdalnych z serwera RMI za pomocą metod
28 * {@link #exportObject(Remote) exportObject} oraz
29 * {@link #unexportObject(Remote, boolean) unexportObject}
30 *
31 * @author VMD Group
32 *
33 */
34 public class RmiManager {
35
36 private RegistryImpl registry = null;
37
38 private Map<RemoteAgent, Integer> registeredAgentMap = new HashMap<RemoteAgent, Integer>();
39
40 private Set<UserImpl> registeredUserSet = new HashSet<UserImpl>();
41
42 private UserGarbageCollector userGbC = null;
43
44 private int port;
45
46 private long gbcInterval;
47
48 /***
49 * Konstruktor rejestrujący odpowiednią fabrykę gniazd sieciowych.
50 *
51 * @param port -
52 * numer portu na którym będzie odpalany serwer RMI
53 * @param useUserGbC -
54 * <code>true</code> jeśli ma być włączony user garbage
55 * collector lub <code>false</code> w przeciwnym wypadku
56 * @param connectionTimeout -
57 * timeout (w ms) próby połączenia do klienta (np. jeśli jest
58 * za NAT/firewall). Jeśli zero, to traktowany jest jak
59 * nieskończoność i połączenie będzie nawiązywane dopóki nie
60 * wystąpi błąd połączenia (wtedy dopiero natstępuje połączenie
61 * pasywne).
62 * @throws IOException -
63 * wyjątek rzucany w przypadku niepowodzenia rejestracji fabryki
64 * gniazd sieciowych.
65 */
66 public RmiManager(int port, boolean useUserGbC, int connectionTimeout)
67 throws IOException {
68 RMISocketFactory.setSocketFactory(new ServerTwoWaySocketFactory(
69 connectionTimeout));
70 this.port = port;
71 if (useUserGbC) {
72 userGbC = new UserGarbageCollector();
73 userGbC.setUserSet(registeredUserSet);
74 }
75 }
76
77 /***
78 * @return interwał czasu (w milisekunach) co jaki ma być "sprzątane" - zero
79 * oznacza wyłączony user garbage collector
80 */
81 public long getUserCollectorInterval() {
82 return gbcInterval;
83 }
84
85 /***
86 * Ustawia "sprzątacza" użytkowników, którzy nie utrzymywali połączenia
87 * przez pewnien określony w nim czas.
88 *
89 * @param interval -
90 * interwał czasu (w milisekunach) co jaki ma być "sprzątane" -
91 * zero oznacza wyłączenie
92 */
93 public void setUserCollectorInterval(long interval) {
94 if (userGbC != null) {
95 userGbC.setInterval(interval);
96 gbcInterval = interval;
97 }
98 }
99
100 /***
101 * Metoda odpala serwer na danym porcie oraz rejestruje podany serwer
102 * logowania
103 * {@link twcsckernel.projectbase.common.RemoteServer RemoteServer} na
104 * serwerze RMI.
105 *
106 * @param remoteServer -
107 * serwer logowania rejestrowany w serwerze RMI
108 * @throws RemoteException -
109 * wyjątek rzucany w przypadku niepowodzenia utworzenia serwera
110 * RMI lub niepowodzenia rejestracji na nim serwera logowania
111 */
112 public void startRegistryServer(RemoteServer remoteServer)
113 throws RemoteException {
114 registry = (RegistryImpl) LocateRegistry.createRegistry(port);
115 try {
116 UnicastRemoteObject.exportObject(remoteServer, port);
117 } catch (RemoteException re) {
118 UnicastRemoteObject.unexportObject(registry, true);
119 registry = null;
120 throw re;
121 }
122 registry.registerRemoteServer(remoteServer);
123 if (userGbC != null)
124 userGbC.enable();
125 }
126
127 /***
128 * Metoda wyłączająca serwer RMI.
129 *
130 * @return <code>true</code> wtedy i tylko wtedy gdy serwer był włączony i
131 * operacja wyłączenia się powiodła lub <code>false</code> w
132 * przeciwnym wypadku.
133 */
134 public boolean stopRegistryServer() {
135 if (registry == null)
136 return false;
137 try {
138 if (userGbC != null)
139 userGbC.disable();
140 synchronized (registeredUserSet) {
141
142
143
144 UserImpl[] tmpUsrCopy = registeredUserSet
145 .toArray(new UserImpl[0]);
146 for (UserImpl user : tmpUsrCopy)
147 user.kickUser();
148 return UnicastRemoteObject.unexportObject(registry, true);
149 }
150 } catch (NoSuchObjectException e) {
151 return false;
152 }
153 }
154
155 /***
156 * Metoda rejestrująca obiekt zdalny w serwerze RMI. Tylko ona powinna być
157 * używana do rejestrowania obiektów zdalnych.<br/> Metoda wyróżnia dwie
158 * klasy na które reaguje oddzielnie:
159 * <ul>
160 * <li><i>UserImpl</i> - metoda zapisuje dodatkowo obiekt w zbiorze
161 * dostępnym dla garbage collectora użytkowników, przez co podlegają jego
162 * ew. kontroli.</li>
163 * <li><i>RemoteAgent</i> - obiekty te można rejestrować wielokrotnie,
164 * gdyż pluginy mogą potencjalnie stosować tego samego agenta dla wielu
165 * użytkowników. Prowadzony jest zatem dla każdego zarejestrowanego agenta
166 * licznik liczby rejestrowań. Obiekt niezarejestrowany jest rejestrowany i
167 * dodawany do mapy liczników. Jeśli ponownie ten sam agent jest
168 * rejestrowany zwiększany jest tylko licznik rejestrowań.<br/> Obrazowy
169 * schemat:<br/> <code>
170 * if (agent.count==0) {
171 * rejestruj(agent);
172 * agent.count=1;
173 * } else
174 * agent.count++;
175 * </code></li>
176 * </ul>
177 *
178 *
179 * @param object -
180 * rejestrowany obiekt
181 * @throws RemoteException -
182 * wyjątek rzucany w przypadku niepowodzenia rejestracji
183 */
184 public void exportObject(Remote object) throws RemoteException {
185 if (object instanceof RemoteAgent)
186 synchronized (registeredAgentMap) {
187 Integer existing = registeredAgentMap.get(object);
188 if (existing == null) {
189 existing = 1;
190 UnicastRemoteObject.exportObject(object, port);
191 registeredAgentMap.put((RemoteAgent) object, existing);
192 } else {
193 existing++;
194 registeredAgentMap.put((RemoteAgent) object, existing);
195 }
196 }
197 else if (object instanceof UserImpl)
198 synchronized (registeredUserSet) {
199 UnicastRemoteObject.exportObject(object, port);
200 registeredUserSet.add((UserImpl) object);
201 }
202 else
203 UnicastRemoteObject.exportObject(object, port);
204
205 }
206
207 /***
208 * Metoda wyrejestrowująca obiekt zdalny z serwera RMI. Tylko ta metoda
209 * powinna być używana do wyrejestrowania obiektu.<br/> Metoda wyróżnia
210 * dwie klasy na które reaguje oddzielnie:
211 * <ul>
212 * <li><i>UserImpl</i> - metoda usuwa dodatkowo obiekt ze zbioru
213 * dostępnego dla garbage collectora użytkowników</li>
214 * <li><i>RemoteAgent</i> - działa odwrotnie do
215 * {@link #exportObject(Remote) exportObject}.<br/> Obrazowy schemat:<br/>
216 * <code>
217 * if (agent.count>1)
218 * agent.count--;
219 * else {
220 * wyrejestruj(agent);
221 * agent.count=0;
222 * }
223 * </code>
224 * </li>
225 * </ul>
226 *
227 * @param object -
228 * obiekt to wyrejestrowania
229 * @param ifForce -
230 * jeśli <code>true</code> to obiekt zostanie wyrejestrowany
231 * nawet w przypadku przeprowadzanych w aktualnie operacji
232 * zdalnych, w przeciwnym wypadku obiekt będzie wyrejestrowany
233 * tylko jeśli nie wykonuje żadnych operacji zdalnych.
234 * @return <code>true</code> jeśli operacja zakończona powodzeniem lub
235 * <code>false</code> w przeciwnym wypadku.
236 * @throws NoSuchObjectException -
237 * wyjątek rzucany jeśli podany obiekt nie był zarejestrowany
238 */
239 public boolean unexportObject(Remote object, boolean ifForce)
240 throws NoSuchObjectException {
241 if (object instanceof RemoteAgent)
242 synchronized (registeredAgentMap) {
243 Integer existing = registeredAgentMap.get(object);
244 if (existing == null)
245 return false;
246
247
248 if (existing > 1) {
249 existing--;
250 registeredAgentMap.put((RemoteAgent) object, existing);
251 return true;
252 } else {
253 boolean result = UnicastRemoteObject.unexportObject(object,
254 ifForce);
255 if (result)
256 registeredAgentMap.remove(object);
257 return result;
258 }
259 }
260 else if (object instanceof UserImpl)
261 synchronized (registeredUserSet) {
262 boolean result = UnicastRemoteObject.unexportObject(object,
263 ifForce);
264 if (result)
265 registeredUserSet.remove(object);
266 return result;
267 }
268 else
269 return UnicastRemoteObject.unexportObject(object, ifForce);
270 }
271 }