using com.itac.mes.tools; using System; using System.Diagnostics; 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.mes.domain; using com.itac.oib; using com.itac.oib.boardgatekeeper.service; using com.itac.oib.linecontrol.service; using com.itac.oib.monitoring.service; using com.itac.oib.siplacesetupcenter.service; using com.itac.oib.traceability.service; // Handler der das callen von Methoden des DataInterface aus dem iTAC.OIB.Adapter übernimmt namespace com.itac.mes.proxy.sockets { public delegate void PropertyChangeListener(object sender, string channelName, string message); public class IhapEventChannel : RealProxy { private static int CONNECTION_CHECK_MILLIES = 500; private TcpClient _client; private IhapOutputStream _ios; private IhapInputStream _iis; private bool _isShutdown; public string channelName { get; set; } private long lastCall = DateTime.Now.Ticks; private Object lockObject = new Object(); private Thread aliveThread; public event PropertyChangeListener connectionStateChangeListener; public IhapEventChannel(TcpClient client, String channelName) : base(typeof(OIBEvents)) { lock (typeof(IhapHandler)) { } this.channelName = channelName; this._client = client; _ios = new IhapOutputStream(_client.GetStream()); _iis = new IhapInputStream(_client.GetStream()); aliveThread = new Thread(new ThreadStart(aliveThreadRun)); } public void shutdown() { LogHandler.log(Constants.LOGGER, TraceEventType.Information, "closing channel" + channelName); _isShutdown = true; try { _client.Close(); } catch (Exception) { LogHandler.log(Constants.LOGGER, TraceEventType.Warning, "closing channel" + channelName + " failed"); } } public long getLastCall() { return lastCall; } public bool isConnected() { return _client.Client.Connected; } public bool isShutdownInProgress() { return _isShutdown; } public override IMessage Invoke(IMessage message) { lastCall = new DateTime().Ticks; IMethodCallMessage methodMsg = (IMethodCallMessage)message; try { MethodInfo methodInfo = typeof(OIBEvents).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); // der Reihe nach alle Interface durchgehen, die als Callback implementiert sind if (methodInfo == null) { methodInfo = typeof(ISiplaceSetupCenterNotify).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(ITraceability).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(ISetupCenterExternalControl).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(IMonitoringReceiver).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(ILineControlReceiver).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(IAdapterNotify).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(IChangeoverManager).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature); } if (methodInfo == null) { methodInfo = typeof(IBoardGateKeeper).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("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(Constants.LOGGER, TraceEventType.Verbose, "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(Constants.LOGGER, TraceEventType.Error, "Error while sending event call on " + channelName + ":" + e.Message + "\n" + e.StackTrace); shutdown(); } return result; } } 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, channelName, "connectionClosed"); } } /** * */ private void stopAliveThread() { if (aliveThread.IsAlive && (aliveThread.ThreadState != System.Threading.ThreadState.Running)) { aliveThread.Interrupt(); } } public void aliveThreadRun() { while (!_isShutdown && aliveThread.ThreadState == System.Threading.ThreadState.Running) { // wenn der letzte Call länger als .. her ist... try { Thread.Sleep(50); } catch (Exception ) { // wenn beim schliessen der Verbindung noch was passiert ist das nicht schlimm LogHandler.log(Constants.LOGGER, TraceEventType.Information, "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(Constants.LOGGER, TraceEventType.Information, "shutdown connection problem for " + channelName, e); } finally { // die Schreibverbindung ist kaputt, also diese Connection töten... LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "detected broken connection for " + channelName + " because Server closed port"); connectionClosed(); } } } } // wenn beim schliessen der Verbindung noch was passiert ist das nicht schlimm LogHandler.log(Constants.LOGGER, TraceEventType.Information, "channel shut down finished for " + channelName); } } }