1 /*----------------------------------------------------------------------------
2 Name: XmlBlasterAccess.cs
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Provides abstraction to xmlBlaster access from C#
6 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info>
7 Date: 07/2006
8 See: http://www.xmlblaster.org/xmlBlaster/doc/requirements/interface.html
9 -----------------------------------------------------------------------------*/
10 using System;
11 using System.Text;
12 using System.Collections;
13 using System.Runtime.InteropServices;
14 using org.xmlBlaster.util;
15
16 namespace org.xmlBlaster.client
17 {
18 /// Calling unmanagegd code: xmlBlasterClientC.dll
19 public class XmlBlasterAccess : I_XmlBlasterAccess, I_ConnectionStateListener, I_ProgressCallback, I_LoggingCallback
20 {
21 private I_XmlBlasterAccess delegateXb;
22
23 private Hashtable properties;
24
25 private long pingIntervalMillis = 10000;
26
27 private long pollIntervalMillis = 5000;
28
29 private I_ConnectionStateListener connectionStateListener;
30
31 private XbPinger xbPinger;
32
33 private XbPoller xbPoller;
34
35 private I_LoggingCallback loggingCallback;
36
37 private I_ProgressCallback progressCallback;
38
39 private I_Callback callback;
40
41 private volatile string connectQosStr;
42
43 private volatile ConnectReturnQos connectReturnQos;
44
45 private volatile bool connectCalled = false;
46
47 private volatile bool initializeCalled = false;
48
49 private volatile bool disconnectCalled = false;
50
51 private volatile bool isDead = false;
52
53 private volatile bool pollOnInitialConnectFail = false;
54
55 private volatile ConnectionStateEnum currentState = ConnectionStateEnum.UNDEF;
56
57 private I_GprsManager gprsManager;
58
59 public XmlBlasterAccess()
60 {
61 this.delegateXb = CreateNative();
62 }
63
64 private I_XmlBlasterAccess CreateNative()
65 {
66 I_XmlBlasterAccess native = XmlBlasterAccessFactory.CreateInstance("org.xmlBlaster.client.PInvokeCE");
67 native.RegisterConnectionListener(this);
68 native.AddLoggingListener(this);
69 native.AddCallbackProgressListener(this);
70 native.Initialize(this.properties);
71 return native;
72 }
73
74 public void Initialize(string[] argv)
75 {
76 this.delegateXb.Initialize(argv);
77 }
78
79 public void Initialize(Hashtable properties)
80 {
81 this.initializeCalled = true;
82 if (properties == null) properties = new Hashtable();
83 this.properties = properties;
84 if (this.properties.Contains("I_GprsManager"))
85 {
86 this.gprsManager = (I_GprsManager)this.properties["I_GprsManager"];
87 this.properties.Remove("I_GprsManager"); // we later expect strings only
88 }
89 this.pingIntervalMillis = Stuff.Get(properties, "dispatch/connection/pingInterval", this.pingIntervalMillis);
90 this.pollIntervalMillis = Stuff.Get(properties, "dispatch/connection/delay", this.pollIntervalMillis);
91 this.pollOnInitialConnectFail = Stuff.Get(properties, "dispatch/connection/pollOnInitialConnectFail", this.pollOnInitialConnectFail);
92 //int retries = (int)Stuff.Get(properties, "dispatch/connection/retries", -1);
93 this.xbPinger = new XbPinger(this, this.pingIntervalMillis, this);
94 this.xbPoller = new XbPoller(this, this.pollIntervalMillis, this);
95 this.delegateXb.Initialize(this.properties);
96 }
97
98 public void RegisterConnectionListener(I_ConnectionStateListener connectionStateListener)
99 {
100 this.connectionStateListener = connectionStateListener;
101 this.delegateXb.RegisterConnectionListener(this);
102 }
103
104 public void CheckValid()
105 {
106 if (!this.initializeCalled)
107 throw new XmlBlasterException("user.illegalargument", "Please initialize XmlBlasterAccess first");
108 if (this.disconnectCalled)
109 throw new XmlBlasterException("user.illegalargument", "XmlBlasterAccess is shutdown");
110 if (this.isDead)
111 throw new XmlBlasterException("user.illegalargument", "XmlBlasterAccess is connection is DEAD");
112 }
113
114 public bool IsValid()
115 {
116 try
117 {
118 this.CheckValid();
119 return true;
120 }
121 catch (Exception)
122 {
123 return false;
124 }
125 }
126
127 public ConnectReturnQos Connect(string qos, I_Callback listener)
128 {
129 try
130 {
131 this.CheckValid();
132 this.connectQosStr = qos;
133 this.callback = listener;
134 this.connectCalled = true; // before connect()
135 this.disconnectCalled = false;
136 this.connectReturnQos = this.delegateXb.Connect(qos, listener);
137 this.xbPoller.Stop();
138 this.xbPinger.Start();
139 return this.connectReturnQos;
140 }
141 catch (Exception e)
142 {
143 if (this.pollOnInitialConnectFail)
144 {
145 StartPolling();
146 return null;
147 }
148 else
149 {
150 throw e;
151 }
152 }
153 }
154
155 public bool Disconnect(string qos)
156 {
157 this.CheckValid();
158 this.disconnectCalled = true;
159 bool ret = this.delegateXb.Disconnect(qos);
160 Shutdown();
161 return ret;
162 }
163
164 public void LeaveServer()
165 {
166 this.CheckValid();
167 this.disconnectCalled = true;
168 this.delegateXb.LeaveServer();
169 Shutdown();
170 }
171
172 private void Shutdown()
173 {
174 this.isDead = true;
175 ConnectionStateEnum oldState = this.currentState;
176 StopPinging();
177 StopPolling();
178 this.currentState = ConnectionStateEnum.DEAD;
179 callStateListener(oldState, ConnectionStateEnum.DEAD);
180 }
181
182 public PublishReturnQos Publish(MsgUnit msgUnit)
183 {
184 this.CheckValid();
185 return this.delegateXb.Publish(msgUnit);
186 }
187
188 public PublishReturnQos Publish(string key, string content, string qos)
189 {
190 this.CheckValid();
191 return this.delegateXb.Publish(key, content, qos);
192 }
193
194 public void PublishOneway(MsgUnit[] msgUnitArr)
195 {
196 this.CheckValid();
197 this.delegateXb.PublishOneway(msgUnitArr);
198 }
199
200 public SubscribeReturnQos Subscribe(string key, string qos)
201 {
202 this.CheckValid();
203 return this.delegateXb.Subscribe(key, qos);
204 }
205
206 public UnSubscribeReturnQos[] UnSubscribe(string key, string qos)
207 {
208 this.CheckValid();
209 return this.delegateXb.UnSubscribe(key, qos);
210 }
211
212 public EraseReturnQos[] Erase(string key, string qos)
213 {
214 this.CheckValid();
215 return this.delegateXb.Erase(key, qos);
216 }
217
218 public MsgUnitGet[] Get(string key, string qos)
219 {
220 this.CheckValid();
221 return this.delegateXb.Get(key, qos);
222 }
223
224 public string Ping(string qos)
225 {
226 this.CheckValid();
227 return this.delegateXb.Ping(qos);
228 }
229
230 public bool IsConnected()
231 {
232 if (!this.IsValid()) return false;
233 return this.delegateXb.IsConnected();
234 }
235
236 public string GetVersion()
237 {
238 return this.delegateXb.GetVersion();
239 }
240
241 public string GetUsage()
242 {
243 return this.delegateXb.GetUsage();
244 }
245
246 public void OnLogging(XmlBlasterLogLevel logLevel, string location, string message)
247 {
248 I_LoggingCallback l = this.loggingCallback;
249 if (l != null)
250 l.OnLogging(logLevel, location, message);
251 else
252 Console.WriteLine(logLevel + " " + location + " " + message);
253 }
254
255 public void AddLoggingListener(I_LoggingCallback listener)
256 {
257 this.loggingCallback = listener;
258 this.delegateXb.AddLoggingListener(this);
259 }
260
261 public void RemoveLoggingListener(I_LoggingCallback listener)
262 {
263 this.loggingCallback = null; // listener;
264 this.delegateXb.RemoveLoggingListener(listener);
265 }
266
267 public void AddCallbackProgressListener(I_ProgressCallback listener)
268 {
269 this.progressCallback = listener;
270 this.delegateXb.AddCallbackProgressListener(this);
271 }
272
273 public void RemoveCallbackProgressListener(I_ProgressCallback listener)
274 {
275 this.progressCallback = null; // listener;
276 this.delegateXb.RemoveCallbackProgressListener(listener);
277 }
278
279 public string GetEmeiId()
280 {
281 return this.delegateXb.GetEmeiId();
282 }
283
284 public string GetDeviceUniqueId()
285 {
286 return this.delegateXb.GetDeviceUniqueId();
287 }
288
289 public void OnData(bool read, int currBytesRead, int nbytes)
290 {
291 I_ProgressCallback l = this.progressCallback;
292 if (l != null)
293 {
294 l.OnData(read, currBytesRead, nbytes);
295 }
296 }
297
298 public void reachedAlive(ConnectionStateEnum oldStateBeneath, I_XmlBlasterAccess connection)
299 {
300 ConnectionStateEnum oldState = this.currentState;
301 this.currentState = ConnectionStateEnum.ALIVE;
302 I_ConnectionStateListener l = this.connectionStateListener;
303 if (l != null)
304 {
305 try
306 {
307 l.reachedAlive(oldState, connection);
308 }
309 catch (Exception e)
310 {
311 OnLogging(XmlBlasterLogLevel.WARN, "reachedAlive", "User code failed: " + e.ToString());
312 }
313 }
314 StopPolling();
315 StartPinging();
316 }
317
318 public void reachedPolling(ConnectionStateEnum oldStateBeneath, I_XmlBlasterAccess connection)
319 {
320 ConnectionStateEnum oldState = this.currentState;
321 this.currentState = ConnectionStateEnum.POLLING;
322 I_ConnectionStateListener l = this.connectionStateListener;
323 if (l != null)
324 {
325 try
326 {
327 l.reachedPolling(oldState, connection);
328 }
329 catch (Exception e)
330 {
331 OnLogging(XmlBlasterLogLevel.WARN, "reachedPolling", "User code failed: " + e.ToString());
332 }
333 }
334 StopPinging();
335 StartPolling();
336 }
337
338 public void reachedDead(ConnectionStateEnum oldStateBeneath, I_XmlBlasterAccess connection)
339 {
340 ConnectionStateEnum oldState = this.currentState;
341 if (this.xbPoller.IsConfiguredToWork()) // We know better than the layer below
342 {
343 this.currentState = ConnectionStateEnum.POLLING;
344 callStateListener(oldState, this.currentState);
345 StopPinging();
346 StartPolling();
347 return;
348 }
349 this.currentState = ConnectionStateEnum.DEAD;
350 callStateListener(oldState, this.currentState);
351 StopPinging();
352 StopPolling();
353 }
354
355 private bool StartPolling()
356 {
357 if (!this.IsValid()) return false;
358 //if (this.disconnectCalled) return false;
359 if (this.pollIntervalMillis < 1L) return false;
360 bool started = this.xbPoller.Start();
361 if (started)
362 {
363 ConnectionStateEnum oldState = this.currentState;
364 this.currentState = ConnectionStateEnum.POLLING;
365 callStateListener(oldState, this.currentState);
366 }
367 return started;
368 }
369
370 private void StopPolling()
371 {
372 this.xbPoller.Stop();
373 }
374
375
376 private bool StartPinging()
377 {
378 this.CheckValid();
379 //if (this.connectReturnQos == null) return false;
380 //if (this.disconnectCalled) return false;
381 if (this.pingIntervalMillis < 1L) return false;
382 bool started = this.xbPinger.Start();
383 if (started)
384 {
385 ConnectionStateEnum oldState = this.currentState;
386 this.currentState = ConnectionStateEnum.ALIVE;
387 callStateListener(oldState, this.currentState);
388 }
389 return started;
390 }
391
392 private void callStateListener(ConnectionStateEnum oldState, ConnectionStateEnum newState)
393 {
394 if (oldState == newState)
395 {
396 OnLogging(XmlBlasterLogLevel.WARN, "XmlBlasterAccess", "Same states in transition: " + newState);
397 return;
398 }
399
400 I_ConnectionStateListener l = this.connectionStateListener;
401 if (l != null)
402 {
403 try
404 {
405 if (newState == ConnectionStateEnum.ALIVE)
406 l.reachedAlive(oldState, this);
407 else if (newState == ConnectionStateEnum.POLLING)
408 l.reachedPolling(oldState, this);
409 else if (newState == ConnectionStateEnum.DEAD)
410 l.reachedDead(oldState, this);
411 }
412 catch (Exception e)
413 {
414 OnLogging(XmlBlasterLogLevel.WARN, ""+newState, "User code failed: " + e.ToString());
415 }
416 }
417 }
418
419 private bool StopPinging()
420 {
421 return this.xbPinger.Stop();
422 }
423
424 public void OnReconnectTry()
425 {
426 if (!this.connectCalled || this.disconnectCalled)
427 {
428 StopPolling();
429 return;
430 }
431
432 I_XmlBlasterAccess old = this.delegateXb;
433 if (old != null) {
434 this.delegateXb = null;
435 old.LeaveServer();
436 }
437
438 if (this.gprsManager != null)
439 this.gprsManager.Connect(false);
440
441 this.delegateXb = CreateNative();
442
443 ConnectReturnQos qr = Connect(this.connectQosStr, this.callback);
444 if (qr == null)
445 throw new XmlBlasterException("communication.noConnection", "we are polling for the server");
446
447 StopPolling();
448 StartPinging();
449 //OnLogging(XmlBlasterLogLevel.WARN, "XmlBlasterAccess", "No connection to server: " + e.ToString());
450 }
451
452 public void OnPingFailed(Exception ex)
453 {
454 if (this.disconnectCalled)
455 {
456 StopPinging();
457 return;
458 }
459 OnSocketDisconnected(ex);
460 }
461
462 // socket EOF
463 public void OnSocketDisconnected(Exception ex)
464 {
465 StopPinging();
466 StartPolling();
467 }
468 }
469 }
syntax highlighted by Code2HTML, v. 0.9.1