initialize
This commit is contained in:
319
interface/commonsmt/dotnetplugin/Plugin/IhapEventChannel.cs
Normal file
319
interface/commonsmt/dotnetplugin/Plugin/IhapEventChannel.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2015 iTAC Software AG, Germany. All Rights Reserved.
|
||||
*
|
||||
* This software is protected by copyright. Under no circumstances may any part of this file in any form be copied,
|
||||
* printed, edited or otherwise distributed, be stored in a retrieval system, or be translated into another language
|
||||
* without the written permission of iTAC Software AG.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Runtime.Remoting.Proxies;
|
||||
using System.Threading;
|
||||
using com.itac.artes.ihap;
|
||||
using com.itac.util.logging;
|
||||
|
||||
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class MyChannelEventArgs : EventArgs
|
||||
{
|
||||
public MyChannelEventArgs(string channelName, string message)
|
||||
{
|
||||
this.channelName = channelName;
|
||||
this.message = message;
|
||||
}
|
||||
public string channelName; public string message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public delegate void PropertyChangeListener(Object sender, MyChannelEventArgs e);
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class IhapEventChannel : RealProxy
|
||||
{
|
||||
|
||||
public static Object classLock = new Object();
|
||||
|
||||
private static int CONNECTION_CHECK_MILLIES = 500;
|
||||
|
||||
private TcpClient _client;
|
||||
private IhapOutputStream _ios;
|
||||
private IhapInputStream _iis;
|
||||
private bool _isShutdown;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string channelName { get; set; }
|
||||
private long lastCall = DateTime.Now.Ticks;
|
||||
private Object lockObject = new Object();
|
||||
private Thread aliveThread;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public event PropertyChangeListener connectionStateChangeListener;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IhapEventChannel(TcpClient client, String channelName)
|
||||
: base(typeof(IMesServicesChannel))
|
||||
{
|
||||
// diesen Constructor nur einmal betreten
|
||||
lock (classLock)
|
||||
{
|
||||
}
|
||||
this.channelName = channelName;
|
||||
this._client = client;
|
||||
_ios = new IhapOutputStream(_client.GetStream());
|
||||
_iis = new IhapInputStream(_client.GetStream());
|
||||
|
||||
aliveThread = new Thread(new ThreadStart(aliveThreadRun));
|
||||
aliveThread.Name = channelName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void shutdown()
|
||||
{
|
||||
LogHandler.log("LOGGER", LogLevel.INFO, "closing channel" + channelName);
|
||||
_isShutdown = true;
|
||||
try
|
||||
{
|
||||
_client.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LogHandler.log("LOGGER", LogLevel.WARN, "closing channel" + channelName + " failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long getLastCall()
|
||||
{
|
||||
return lastCall;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool isConnected()
|
||||
{
|
||||
return _client.Client.Connected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool isShutdownInProgress()
|
||||
{
|
||||
return _isShutdown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override IMessage Invoke(IMessage message)
|
||||
{
|
||||
lastCall = new DateTime().Ticks;
|
||||
IMethodCallMessage methodMsg = (IMethodCallMessage)message;
|
||||
try
|
||||
{
|
||||
MethodInfo methodInfo = typeof(IMesServices).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature);
|
||||
// der Reihe nach alle Interface durchgehen, die als Callback implementiert sind
|
||||
if (methodInfo == null)
|
||||
{
|
||||
methodInfo = typeof(IMesServicesChannel).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature);
|
||||
}
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new Exception("IHapHandler.cs: methode '" + methodMsg.MethodName + "' nicht in den Interfacen gefunden");
|
||||
}
|
||||
|
||||
object[] args = methodMsg.Args;
|
||||
if (methodMsg.MethodName.Equals("Equals"))
|
||||
{
|
||||
return new ReturnMessage(args[0].Equals(this), args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
else if (methodMsg.MethodName.Equals("getChannelName"))
|
||||
{
|
||||
return new ReturnMessage(channelName, args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
else if (methodMsg.MethodName.Equals("GetHashCode"))
|
||||
{
|
||||
return new ReturnMessage(this.GetHashCode(), args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
else if (methodMsg.MethodName.Equals("shutdown"))
|
||||
{
|
||||
shutdown();
|
||||
stopAliveThread();
|
||||
connectionClosed();
|
||||
return new ReturnMessage(null, args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
else if (methodMsg.MethodName.Equals("startup"))
|
||||
{
|
||||
aliveThread.Start();
|
||||
return new ReturnMessage(null, args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
Object retValue = sendCall(methodInfo, args);
|
||||
return new ReturnMessage(retValue, args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
catch (TargetInvocationException ite)
|
||||
{
|
||||
return new ReturnMessage(ite.GetBaseException(), methodMsg);
|
||||
}
|
||||
catch (Exception ite)
|
||||
{
|
||||
return new ReturnMessage(ite.GetBaseException(), methodMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private Object sendCall(MethodInfo method, Object[] args)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
LogHandler.log("LOGGER", LogLevel.DEBUG, "Send event '" + method.Name + "' to socket " + _client.Client.RemoteEndPoint + " on " + channelName);
|
||||
Object result = null;
|
||||
try
|
||||
{
|
||||
_ios.writeBoolean(false);
|
||||
_ios.call(method, args);
|
||||
_ios.Flush();
|
||||
IhapReply reply = _iis.readReply();
|
||||
if (reply is IhapSuccessReply)
|
||||
{
|
||||
result = ((IhapSuccessReply)reply).getReturnValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
IhapFaultReply fault = (IhapFaultReply)reply;
|
||||
switch (fault.getFaultCode())
|
||||
{
|
||||
case FaultCode.NoSuchMethodException:
|
||||
throw new NotImplementedException(fault.getMessage());
|
||||
case FaultCode.ProtocolException:
|
||||
throw new IhapProtocolException(fault.getMessage(), null);
|
||||
default:
|
||||
throw new IhapProtocolException(fault.getMessage(), null);
|
||||
//(Exception)fault.getException();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHandler.log("LOGGER", LogLevel.ERROR, "Error while sending event call on " + channelName + ":" + e.Message + "\n" + e.StackTrace);
|
||||
shutdown();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected void connectionClosed()
|
||||
{
|
||||
// Hier wird überprüft, ob ein Eintrag in der Aufruf-Liste vorhanden ist.
|
||||
if (this.connectionStateChangeListener != null)
|
||||
{
|
||||
// Hier wird jeder Delegat, der sich für den Event registriert hat, aufgerufen.
|
||||
this.connectionStateChangeListener(this, new MyChannelEventArgs(channelName, "connectionClosed"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void stopAliveThread()
|
||||
{
|
||||
if (aliveThread.IsAlive && (aliveThread.ThreadState != System.Threading.ThreadState.Running))
|
||||
{
|
||||
aliveThread.Interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void aliveThreadRun()
|
||||
{
|
||||
while (!_isShutdown && aliveThread.ThreadState == System.Threading.ThreadState.Running)
|
||||
{
|
||||
// wenn der letzte Call laenger als .. her ist...
|
||||
try
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// wenn beim schliessen der Verbindung noch was passiert ist das nicht schlimm
|
||||
LogHandler.log("LOGGER", LogLevel.INFO, "interrupted for " + channelName);
|
||||
}
|
||||
if (DateTime.Now.Ticks - lastCall > CONNECTION_CHECK_MILLIES)
|
||||
{
|
||||
try
|
||||
{
|
||||
// versuchen den Server zu pingen
|
||||
// wenn das fehlschlägt ist die Verbindung kaputt
|
||||
lock (lockObject)
|
||||
{ // das erfolgreiche Schreiben eines booleschen Wertes ist aus Kommunikationssicht zu sehen wie der
|
||||
// erfolgreiche Aufruf einer Methode
|
||||
if (!_isShutdown && (aliveThread.ThreadState == System.Threading.ThreadState.Running))
|
||||
{
|
||||
// nur wenn die Verbindung nicht bereits gestoppt wurde...
|
||||
_ios.writeBoolean(true);
|
||||
_ios.Flush();
|
||||
lastCall = DateTime.Now.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
_isShutdown = true;
|
||||
_client.Close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// wenn beim schliessen der Verbindung noch was passiert ist das nicht schlimm
|
||||
LogHandler.log("LOGGER", LogLevel.INFO, "shutdown connection problem for " + channelName, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// die Schreibverbindung ist kaputt, also diese Connection töten...
|
||||
LogHandler.log("LOGGER", LogLevel.DEBUG, "detected broken connection for " + channelName
|
||||
+ " because Server closed port");
|
||||
connectionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHandler.log("LOGGER", LogLevel.DEBUG, "Channel too old, stop channel now");
|
||||
}
|
||||
}
|
||||
// wenn beim schliessen der Verbindung noch was passiert ist das nicht schlimm
|
||||
stopAliveThread();
|
||||
LogHandler.log("LOGGER", LogLevel.INFO, "channel shut down finished for " + channelName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user