initialize
This commit is contained in:
205
interface/commonsmt/dotnetplugin/Plugin/FailoverHostList.cs
Normal file
205
interface/commonsmt/dotnetplugin/Plugin/FailoverHostList.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using com.itac.mes.commonsmt;
|
||||
using com.itac.mes.commonsmt.data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
class FailoverHostList
|
||||
{
|
||||
// this list is cyclically updated as long as a mesService Endpoint is active and not closed
|
||||
private List<FailoverHost> failoverHosts;
|
||||
// this is the host all current calls are going to
|
||||
private FailoverHost activeHost;
|
||||
|
||||
public event MyEventHandler OnLog;
|
||||
|
||||
|
||||
public FailoverHostList(MyEventHandler log)
|
||||
{
|
||||
this.OnLog = log;
|
||||
}
|
||||
|
||||
public void log(TraceEventType traceEventType, string message)
|
||||
{
|
||||
if (OnLog == null) { return; }
|
||||
MyEventArgs myEventArgs = new MyEventArgs();
|
||||
myEventArgs.message = "iTAC.MES.Suite SMT-Plugin:" + message;
|
||||
myEventArgs.traceEventType = traceEventType;
|
||||
OnLog(this, myEventArgs);
|
||||
}
|
||||
|
||||
public void setFailover(FailoverHost[] newFailoverHosts)
|
||||
{
|
||||
// protocol all changes
|
||||
Boolean newHosts = false;
|
||||
if (newFailoverHosts == null)
|
||||
{
|
||||
activeHost = null;
|
||||
this.failoverHosts = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.failoverHosts == null)
|
||||
{
|
||||
// initial setting
|
||||
log(TraceEventType.Information, "setting initial failover hosts :");
|
||||
foreach (FailoverHost item in newFailoverHosts)
|
||||
{
|
||||
log(TraceEventType.Information, ": " + item.getHostname());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// whats new, whats removed...
|
||||
Dictionary<String, FailoverHost> currentHosts = new Dictionary<String, FailoverHost>();
|
||||
|
||||
foreach (FailoverHost item in this.failoverHosts)
|
||||
{
|
||||
currentHosts.Add(item.getHostname(), item);
|
||||
}
|
||||
|
||||
foreach (FailoverHost item in newFailoverHosts)
|
||||
{
|
||||
if (currentHosts.ContainsKey(item.getHostname()))
|
||||
{
|
||||
// enthalten, also aus dieser Liste lösche
|
||||
currentHosts.Remove(item.getHostname());
|
||||
}
|
||||
else
|
||||
{
|
||||
// bisher nicht enthalten, also neu
|
||||
Console.Write("new failover host " + item.getHostname());
|
||||
newHosts = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentHosts.Count > 0)
|
||||
{
|
||||
log(TraceEventType.Information, "some failover host removed ");
|
||||
foreach (FailoverHost removedHost in currentHosts.Values)
|
||||
{
|
||||
log(TraceEventType.Information, " - " + removedHost.getHostname());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!newHosts)
|
||||
{
|
||||
log(TraceEventType.Information, "failover host list remains unchanged ");
|
||||
foreach (FailoverHost item in newFailoverHosts)
|
||||
{
|
||||
log(TraceEventType.Information, ":" + item.getHostname());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.failoverHosts = newFailoverHosts.ToList();
|
||||
|
||||
// der erste Host in der Liste ist auch der Host, zu dem die aufrufe ohne Failover gehen!!!
|
||||
if (activeHost == null)
|
||||
{
|
||||
if (newFailoverHosts.Length > 0)
|
||||
{
|
||||
activeHost = newFailoverHosts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// clean default host
|
||||
activeHost = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a host from the failover list.
|
||||
*
|
||||
* If the host is the currently active host {@link #getActiveHost()} then the current host is set to null<br>
|
||||
* If the host is not in the host list then nothing happens
|
||||
*
|
||||
* @param host
|
||||
* the host to be removed; do nothing if host is null
|
||||
*/
|
||||
public void remove(FailoverHost host)
|
||||
{
|
||||
if (host == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
log(TraceEventType.Information, "remove host " + host.getHostname() + " from failover list");
|
||||
for (int i = 0; i < getList().Count; i++)
|
||||
{
|
||||
FailoverHost item = getList()[i];
|
||||
if (item.getHostname().Equals(host.getHostname()))
|
||||
{
|
||||
getList().Remove(item);
|
||||
log(TraceEventType.Information, "host " + item.getHostname() + " removed from failover list");
|
||||
}
|
||||
}
|
||||
if (activeHost != null && activeHost.getHostname().Equals(host.getHostname()))
|
||||
{
|
||||
setActiveHost(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of hosts in the failover list
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return failoverHosts == null ? 0 : failoverHosts.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of currently known host to fail over
|
||||
*/
|
||||
public List<FailoverHost> getList()
|
||||
{
|
||||
return failoverHosts == null ? new List<FailoverHost>() : failoverHosts;
|
||||
}
|
||||
|
||||
public FailoverHost getActiveHost()
|
||||
{
|
||||
return activeHost;
|
||||
}
|
||||
|
||||
public void setActiveHost(FailoverHost host)
|
||||
{
|
||||
if (host == null)
|
||||
{
|
||||
log(TraceEventType.Information, "clear active failover hosts");
|
||||
}
|
||||
else
|
||||
{
|
||||
log(TraceEventType.Information, "set " + host.getHostname() + " as active failover hosts");
|
||||
}
|
||||
this.activeHost = host;
|
||||
}
|
||||
|
||||
public FailoverHost getNextFailoverHost()
|
||||
{
|
||||
FailoverHost failoverHost = null;
|
||||
log(TraceEventType.Information, "scanning for other failover hosts. list contains a total of " + size() + " hosts");
|
||||
foreach (FailoverHost host in getList())
|
||||
{
|
||||
if (host.Equals(getActiveHost()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
failoverHost = host;
|
||||
log(TraceEventType.Information, "next failover hosts is " + host.getHostname());
|
||||
break;
|
||||
}
|
||||
// den nächsten aus der Liste ohne den defaultHost
|
||||
if (size() == 0)
|
||||
{
|
||||
log(TraceEventType.Information, "No more failover host available!");
|
||||
}
|
||||
return failoverHost;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
using com.itac.mes.commonsmt;
|
||||
using com.itac.mes.commonsmt.data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Runtime.Remoting.Proxies;
|
||||
using System.Text;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
class FailoverInvocationHandler : FailoverHostList
|
||||
{
|
||||
|
||||
// Zugriff auf die folgenden Maps muss synchronisiert erfolgen
|
||||
static readonly object _locker = new object();
|
||||
// In dieser Map sind alle offenen Verbindungen zum DataInterface enthalten
|
||||
private Dictionary<String, IhapEventChannel> openClientChannels = new Dictionary<String, IhapEventChannel>();
|
||||
// pro Verbindung wird gezaehlt wie viele Connections es schon gab...
|
||||
private Dictionary<String, Int32> channelNameCounter = new Dictionary<String, Int32>();
|
||||
|
||||
public FailoverInvocationHandler(MyEventHandler OnLog)
|
||||
: base(OnLog)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a new communication channel with specified name
|
||||
*
|
||||
* @param channelName
|
||||
* the name for the channel
|
||||
* @param connectionListener
|
||||
* when a connection listener is set (!= null) a thread is established to cyclically check wether the channel is still
|
||||
* active or not. If a connection is shutdown by a server (the remote function host) an event at the listener is fired
|
||||
* @return the communication channel where mesFunctions are exceuted (remote calls via IHap)
|
||||
* @throws IOException
|
||||
* when no connection could be established
|
||||
*/
|
||||
|
||||
private IMesServicesChannel getConnection(string channelName, Object s)
|
||||
{
|
||||
if (getActiveHost() == null)
|
||||
{
|
||||
log(TraceEventType.Error, "cannot get new connection " + channelName + " because active host is unset");
|
||||
return null;
|
||||
}
|
||||
// for every channel a new connection Every connection has it's own counter
|
||||
string channelNameWithNumber = getChannelName(channelName);
|
||||
|
||||
// Neue Verbindung zum DataInterface aufmachen
|
||||
var tcpClient = new TcpClient(getActiveHost().getHostname(), getActiveHost().getPort());
|
||||
// eine neue TCp-Client-Verbindung
|
||||
var iHapEventChannel = new IhapEventChannel(tcpClient, channelNameWithNumber);
|
||||
if (iHapEventChannel == null)
|
||||
{
|
||||
log(TraceEventType.Error, "iHapEventChannel not created");
|
||||
throw new Exception("iHapEventChannel not created");
|
||||
}
|
||||
|
||||
log(TraceEventType.Information, "before adding " + channelNameWithNumber);
|
||||
lock (_locker)
|
||||
{
|
||||
if (openClientChannels.ContainsKey(channelNameWithNumber))
|
||||
{
|
||||
openClientChannels.Remove(channelNameWithNumber);
|
||||
}
|
||||
openClientChannels.Add(channelNameWithNumber, iHapEventChannel);
|
||||
}
|
||||
log(TraceEventType.Information, "" + channelNameWithNumber + " added");
|
||||
|
||||
iHapEventChannel.channelName = channelNameWithNumber;
|
||||
// Listener installieren, um zu reagieren, wenn das Data-Interface die Verbindung abgebrochen hat
|
||||
// iHapEventChannel.connectionStateChangeListener += new PropertyChangeListener(iHapEventChannel_connectionStateChangeListener);
|
||||
|
||||
var remoteMesService = (IMesServicesChannel)iHapEventChannel.GetTransparentProxy();
|
||||
if (remoteMesService == null)
|
||||
{
|
||||
log(TraceEventType.Error, "iHapEventChannel.transparentProxy not created");
|
||||
throw new Exception("iHapEventChannel.transparentProxy not created");
|
||||
}
|
||||
remoteMesService.setChannelName(channelNameWithNumber);
|
||||
remoteMesService.startup();
|
||||
return remoteMesService;
|
||||
}
|
||||
|
||||
private string getChannelName(string channelName)
|
||||
{
|
||||
// gab es fuer diesen channelName bereits eine Connection
|
||||
string channelNameWithNumber = channelName;
|
||||
var counter = 0;
|
||||
lock (_locker)
|
||||
{
|
||||
if (channelNameCounter.ContainsKey(channelName))
|
||||
{
|
||||
counter = channelNameCounter[channelName];
|
||||
counter++;
|
||||
if (counter > 100000) { counter = 1; }
|
||||
channelNameCounter.Remove(channelName);
|
||||
channelNameCounter.Add(channelName, counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
channelNameCounter.Add(channelName, counter);
|
||||
}
|
||||
channelNameWithNumber = channelName + "#" + counter;
|
||||
}
|
||||
return channelNameWithNumber;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void handleThrowable(Object response, Exception throwable)
|
||||
{
|
||||
if (!(response is MesResponse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
MesResponse mesResponse = (MesResponse)response;
|
||||
mesResponse.setTotalResult(MesServices.MES_RESULT_NOT_OK);
|
||||
if (throwable is PluginException)
|
||||
{
|
||||
setResponseValues(mesResponse, ((PluginException)throwable).getResponseDetail());
|
||||
}
|
||||
else if (throwable is IOException)
|
||||
{
|
||||
addError(mesResponse.getErrorDetails(),
|
||||
getErrorDetail(throwable.Message, ResponseDetail.COMMUNICATION_FAILURE));
|
||||
}
|
||||
else
|
||||
{
|
||||
addError(mesResponse.getErrorDetails(),
|
||||
getErrorDetail(throwable.Message, ResponseDetail.PROCESSED_WITH_EXCEPTION));
|
||||
}
|
||||
}
|
||||
|
||||
private ErrorDetail[] addError(ErrorDetail[] errorDetails, ErrorDetail errorDetail)
|
||||
{
|
||||
List<ErrorDetail> list = new List<ErrorDetail>();
|
||||
foreach (ErrorDetail item in errorDetails)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
list.Add(errorDetail);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
// convenient method
|
||||
private ErrorDetail getErrorDetail(String detail, int code)
|
||||
{
|
||||
ErrorDetail errorDetail = new ErrorDetail();
|
||||
errorDetail.setCode(code);
|
||||
errorDetail.setDetail(detail);
|
||||
return errorDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* finalizing means closing communication channel and loggin response Object
|
||||
*
|
||||
* @param connection
|
||||
* the used connection
|
||||
*/
|
||||
private void finalizeRequest(IMesServicesChannel connection)
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
string connectionName = connection.getChannelName();
|
||||
if (connectionName != null)
|
||||
{
|
||||
openClientChannels.Remove(connectionName);
|
||||
}
|
||||
connection.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private IMesServicesChannel getConnection(string channelName)
|
||||
{
|
||||
return getConnection(channelName, null);
|
||||
}
|
||||
|
||||
protected void setResponseValues(MesResponse response, ResponseDetail responseDetail)
|
||||
{
|
||||
if (responseDetail.getCode() == ResponseDetail.OK)
|
||||
{
|
||||
response.setTotalResult(MesServices.MES_RESULT_OK);
|
||||
return;
|
||||
}
|
||||
response.setTotalResult(MesServices.MES_RESULT_NOT_OK);
|
||||
addError(response.getErrorDetails(), getErrorDetail(responseDetail.getText(), responseDetail.getCode()));
|
||||
}
|
||||
|
||||
public IMessage Invoke(IMessage msg)
|
||||
{
|
||||
IMethodCallMessage methodMsg = (IMethodCallMessage)msg;
|
||||
|
||||
MethodInfo methodInfo = typeof(IMesServices).GetMethod(methodMsg.MethodName, (Type[])methodMsg.MethodSignature);
|
||||
if (methodInfo == null)
|
||||
{
|
||||
// TODO: check if this is longer required
|
||||
// object ret = failoverInvocationHandler.invoke(this, methodInfo, methodMsg.InArgs);
|
||||
}
|
||||
|
||||
// special handling for a couple of function (mesStart, mesStop, getFailoverHosts..FailoverInvocationHandler.)
|
||||
Object response = Activator.CreateInstance(methodInfo.ReturnType);
|
||||
|
||||
// if no failoverhost available return error
|
||||
if (getActiveHost() == null && size() == 0)
|
||||
{
|
||||
// no host set, no failover available --> fail
|
||||
return null;
|
||||
}
|
||||
|
||||
// do a failover for all methods startswith "mes" (operational methods)
|
||||
if (methodInfo.Name.StartsWith("mes"))
|
||||
{
|
||||
IMesServices connection = null;
|
||||
try
|
||||
{
|
||||
|
||||
bool callFailed = false;
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
callFailed = false;
|
||||
log(TraceEventType.Information, "call " + methodInfo.Name + "@" + getActiveHost().getHostname());
|
||||
connection = getConnection(methodInfo.Name);
|
||||
if (connection == null)
|
||||
{
|
||||
callFailed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
response = methodInfo.Invoke(connection, methodMsg.InArgs);
|
||||
if (response == null)
|
||||
{
|
||||
callFailed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ((response is MesResponse))
|
||||
{
|
||||
MesResponse responseObject = (MesResponse)response;
|
||||
if (responseObject.getTotalResult() == MesServices.MES_RESULT_NOT_OK)
|
||||
{
|
||||
// set DetailResult to COMMUNICATION_FAILURE
|
||||
// repeat this call to another host
|
||||
callFailed = hasCommunicationFailure(responseObject.getErrorDetails());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
callFailed = true;
|
||||
}
|
||||
|
||||
if (callFailed)
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
// explicit finalize this connection
|
||||
connection = null;
|
||||
}
|
||||
remove(getActiveHost());
|
||||
setActiveHost(getNextFailoverHost());
|
||||
}
|
||||
} while (callFailed && getActiveHost() != null);
|
||||
|
||||
// if failover did not find any available host return communication error
|
||||
if (getActiveHost() == null)
|
||||
{
|
||||
|
||||
if ((response is MesResponse))
|
||||
{
|
||||
MesResponse responseObject = (MesResponse)response;
|
||||
|
||||
addError(responseObject.getErrorDetails(),
|
||||
getErrorDetail("no failover host active", ResponseDetail.COMMUNICATION_FAILURE));
|
||||
|
||||
responseObject.setTotalResult(MesServices.MES_RESULT_NOT_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(response, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (response is MesFailoverResponse)
|
||||
{
|
||||
// internally update the list
|
||||
setFailover(((MesFailoverResponse)response).getFailoverHosts());
|
||||
}
|
||||
finalizeRequest((IMesServicesChannel)connection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// simply call the method, no failover for them
|
||||
response = methodInfo.Invoke(this, methodMsg.InArgs);
|
||||
}
|
||||
|
||||
return new ReturnMessage(response, methodMsg.Args, 0, methodMsg.LogicalCallContext, methodMsg);
|
||||
}
|
||||
|
||||
private Boolean hasCommunicationFailure(ErrorDetail[] errorDetails)
|
||||
{
|
||||
if (errorDetails == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (ErrorDetail errDetail in errorDetails)
|
||||
{
|
||||
if (errDetail.getCode() == ResponseDetail.COMMUNICATION_FAILURE)
|
||||
{
|
||||
log(TraceEventType.Error, "communication failure on this connection");
|
||||
throw new SocketException();
|
||||
}
|
||||
if (errDetail.getCode() == -10005)
|
||||
{
|
||||
log(TraceEventType.Error, "communication failure on this connection");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
interface/commonsmt/dotnetplugin/Plugin/FailoverProxy.cs
Normal file
23
interface/commonsmt/dotnetplugin/Plugin/FailoverProxy.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Runtime.Remoting.Proxies;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
class FailoverProxy : RealProxy
|
||||
{
|
||||
private FailoverInvocationHandler failoverInvocationHandler;
|
||||
|
||||
public FailoverProxy(Type type, FailoverInvocationHandler failoverInvocationHandler)
|
||||
: base(type)
|
||||
{
|
||||
this.failoverInvocationHandler = failoverInvocationHandler;
|
||||
}
|
||||
|
||||
public override IMessage Invoke(IMessage msg)
|
||||
{
|
||||
return failoverInvocationHandler.Invoke(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IMesServicesChannel
|
||||
/// </summary>
|
||||
public interface IMesServicesChannel : IMesServices
|
||||
{
|
||||
/// <summary>
|
||||
/// returns true when this channel is currently shutting down. While shutting down this channel could not be used for communication.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Boolean isShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// starting up this channel. While starting up this channel could not be used for communication.
|
||||
/// </summary>
|
||||
void startup();
|
||||
|
||||
/// <summary>
|
||||
/// initiate the shutdown of the channel.
|
||||
/// </summary>
|
||||
void shutdown();
|
||||
|
||||
/// <summary>
|
||||
/// setting a name for this channel. Name could be used by java client as well.
|
||||
/// </summary>
|
||||
/// <param name="channelName"></param>
|
||||
void setChannelName(String channelName);
|
||||
|
||||
/// <summary>
|
||||
/// returning the name of this channel.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
String getChannelName();
|
||||
}
|
||||
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
837
interface/commonsmt/dotnetplugin/Plugin/MesServices.cs
Normal file
837
interface/commonsmt/dotnetplugin/Plugin/MesServices.cs
Normal file
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* 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 com.itac.mes.tools;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using com.itac.mes.commonsmt.data;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// documentation for the namespace
|
||||
/// </summary>
|
||||
[System.Runtime.CompilerServices.CompilerGenerated]
|
||||
class NamespaceDoc
|
||||
{
|
||||
}
|
||||
|
||||
public class MyEventArgs : EventArgs
|
||||
{
|
||||
public TraceEventType traceEventType;
|
||||
public String message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public delegate void MyEventHandler(Object sender, MyEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Class level summary documentation goes here.</summary>
|
||||
/// <remarks>
|
||||
/// Longer comments can be associated with a type or member through
|
||||
/// the remarks tag.</remarks>
|
||||
public class MesServices : IMesServices
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public event MyEventHandler OnLog;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// return this value in {@link MesResponse#setTotalResult(int)}
|
||||
/// {@link MesResponse#getTotalResult()} for any request
|
||||
/// which was processed successfully.
|
||||
/// All returned values are be valid.</summary>
|
||||
public static int MES_RESULT_OK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// return this value in {@link MesResponse#setTotalResult(int)}/{@link MesResponse#getTotalResult()} for any request
|
||||
/// which was NOT processed successfully. Not all returned values must be valid, depends on the request.
|
||||
///
|
||||
/// @see separate calls in {@link IMesServices#} for detailled information.
|
||||
/// </summary>
|
||||
public static int MES_RESULT_NOT_OK = 1;
|
||||
// allowed port range
|
||||
private static int MIN_PORT = 1023;
|
||||
private static int MAX_PORT = 49150;
|
||||
// 10 minutes default
|
||||
private static int DEFAULT_REFRESH_INTERVAL = 600000;
|
||||
|
||||
|
||||
// some bool flags for operation
|
||||
private Boolean configured;
|
||||
private Boolean active;
|
||||
|
||||
// every call to a mes host needs an own id; the id does not change when a call is completed on a failover host
|
||||
private RequestIdGenerator idGenerator = new RequestIdGenerator();
|
||||
// the invocation handler accepts all calls from the failoverProxy
|
||||
private FailoverInvocationHandler failoverInvocationHandler;
|
||||
// this proxy delegates the calls to all known failover hosts
|
||||
private IMesServices failoverProxy;
|
||||
// update Thread counter
|
||||
private int runCounter;
|
||||
/// <summary>
|
||||
/// do not marshal objects but print as xml
|
||||
/// </summary>
|
||||
private ItacXmlSerializer serializer = new ItacXmlSerializer();
|
||||
//// failover detection
|
||||
private static int updateThreadCount;
|
||||
private Thread failoverUpdateThread;
|
||||
private int refreshFailoverhostsInterval;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesServices(String hostname, int port, int refreshFailoverhostsInterval)
|
||||
{
|
||||
setConfigured(false);
|
||||
setActive(false);
|
||||
//// create and initialize the failover proxy
|
||||
failoverInvocationHandler = new FailoverInvocationHandler(OnLog);
|
||||
// create the proxy and set the delegate
|
||||
failoverProxy = (IMesServices)new FailoverProxy(typeof(IMesServices), failoverInvocationHandler).GetTransparentProxy();
|
||||
// check hostname
|
||||
if (!isHostNameValid(hostname))
|
||||
{
|
||||
log(TraceEventType.Error, "hostname must not be null or empty");
|
||||
return;
|
||||
}
|
||||
// check port range
|
||||
if (!isPortValid(port))
|
||||
{
|
||||
log(TraceEventType.Error, String.Format("value {0} is out of range {1}..{2}", port, MIN_PORT, MAX_PORT));
|
||||
return;
|
||||
}
|
||||
// check refresh interval
|
||||
if (!isRefreshIntervalValid(refreshFailoverhostsInterval))
|
||||
{
|
||||
log(TraceEventType.Error, "value {0} is out of valid values [-1], [0], [>60000]");
|
||||
return;
|
||||
}
|
||||
setRefreshFailoverhostsInterval(refreshFailoverhostsInterval);
|
||||
|
||||
setConfigured(true);
|
||||
FailoverHost failoverHost = new FailoverHost();
|
||||
failoverHost.setHostname(hostname);
|
||||
failoverHost.setPort(port);
|
||||
|
||||
failoverInvocationHandler.setFailover(new FailoverHost[] { failoverHost });
|
||||
}
|
||||
|
||||
protected void setRefreshFailoverhostsInterval(int refreshFailoverhostsInterval)
|
||||
{
|
||||
this.refreshFailoverhostsInterval = refreshFailoverhostsInterval;
|
||||
}
|
||||
|
||||
protected Boolean isPortValid(int newPort)
|
||||
{
|
||||
Boolean result = newPort >= MIN_PORT && newPort <= MAX_PORT;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Boolean isHostNameValid(String hostname)
|
||||
{
|
||||
return hostname != null && hostname.Length != 0;
|
||||
}
|
||||
|
||||
protected Boolean isRefreshIntervalValid(long refreshFailoverhostsInterval)
|
||||
{
|
||||
return refreshFailoverhostsInterval == -1 || refreshFailoverhostsInterval == 0 || refreshFailoverhostsInterval > 60000;
|
||||
}
|
||||
|
||||
protected void setActive(Boolean active)
|
||||
{
|
||||
if (!this.active && active)
|
||||
{
|
||||
log(TraceEventType.Information, "setting MesServices active");
|
||||
}
|
||||
else if (this.active && !active)
|
||||
{
|
||||
log(TraceEventType.Information, "setting MesServices inactive");
|
||||
}
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
protected Boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
protected Boolean isConfigured()
|
||||
{
|
||||
return configured;
|
||||
}
|
||||
|
||||
protected void setConfigured(Boolean configured)
|
||||
{
|
||||
if (!this.configured && configured)
|
||||
{
|
||||
log(TraceEventType.Information, "setting MesServices configured");
|
||||
}
|
||||
else if (this.configured && !configured)
|
||||
{
|
||||
log(TraceEventType.Information, "setting MesServices unconfigured");
|
||||
}
|
||||
this.configured = configured;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Vorbedingungen sind dass der Request gesetzt ist, sowie die Konfiguration und die aktivierung des Plugin
|
||||
/// </summary>
|
||||
/// <param name="mesResponse"> Parameter description for s goes here.</param>
|
||||
/// <param name="mesRequest"> Parameter description for s goes here.</param>
|
||||
/// <seealso cref="System.String">
|
||||
/// You can use the cref attribute on any tag to reference a type or member
|
||||
/// and the compiler will check that the reference exists. </seealso>
|
||||
private void checkPreconditions(MesResponse mesResponse, MesRequest mesRequest) /* throws CogiscanException */{
|
||||
checkRequestPreconditons(mesRequest);
|
||||
if (mesResponse == null)
|
||||
{
|
||||
throw new PluginException(ResponseDetail.RESPONSE_IS_NULL, "response is null");
|
||||
}
|
||||
// requestId aus Request in den Response uebernehmen
|
||||
mesResponse.setRequestId(mesRequest.getRequestId());
|
||||
// Konfigurationsprobleme checken
|
||||
if (!isConfigured())
|
||||
{
|
||||
throw new PluginException(ResponseDetail.PLUGIN_NOT_CONFIGURED, "plugin is not yet configured");
|
||||
}
|
||||
if (!isActive())
|
||||
{
|
||||
throw new PluginException(ResponseDetail.PLUGIN_NOT_ACTIVE, "plugin is not yet active");
|
||||
}
|
||||
setResponseValues(mesResponse, new ResponseDetail("", ResponseDetail.OK));
|
||||
}
|
||||
|
||||
private void checkRequestPreconditons(MesRequest mesRequest)
|
||||
{
|
||||
if (mesRequest == null)
|
||||
{
|
||||
throw new PluginException(ResponseDetail.REQUEST_IS_NULL, "the request is null");
|
||||
}
|
||||
if (mesRequest.getRequestId() <= 0)
|
||||
{
|
||||
mesRequest.setRequestId(idGenerator.getNextId());
|
||||
}
|
||||
if (mesRequest.getEventDate() == null || mesRequest.getEventDate().Ticks == 0)
|
||||
{
|
||||
mesRequest.setEventDate(DateTime.Now);
|
||||
}
|
||||
// Request ausgeben
|
||||
logRequest(mesRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* finalizing means closing communication channel and loggin response Object
|
||||
*
|
||||
* @param connection
|
||||
* the used connection
|
||||
* @param responseObject
|
||||
* the responseObject
|
||||
*/
|
||||
private void finalizeRequest(MesResponse responseObject)
|
||||
{
|
||||
logResponse(responseObject);
|
||||
}
|
||||
|
||||
// * gets a new communication cahnnel with specified name
|
||||
// *
|
||||
// * @param channelName
|
||||
// * the name for the channel
|
||||
// * @param connectionListener
|
||||
// * @return
|
||||
// * @throws IOException
|
||||
// eine neue socket zum DataInterface als Client aufmachen. ?ber diese Verbindung werden alle Events zum
|
||||
// Datainterface ?bertragen
|
||||
// Returned nie einen Null-Wert
|
||||
/// <summary>
|
||||
/// Description for SomeMethod.</summary>
|
||||
/// You can use the cref attribute on any tag to reference a type or member
|
||||
/// and the compiler will check that the reference exists.
|
||||
private void log(TraceEventType traceEventType, string message)
|
||||
{
|
||||
if (OnLog == null) { return; }
|
||||
MyEventArgs myEventArgs = new MyEventArgs();
|
||||
myEventArgs.message = "iTAC.MES.Suite SMT-Plugin:" + message;
|
||||
myEventArgs.traceEventType = traceEventType;
|
||||
OnLog(this, myEventArgs);
|
||||
}
|
||||
|
||||
// convenient method
|
||||
private ErrorDetail getErrorDetail(String detail, int code)
|
||||
{
|
||||
ErrorDetail errorDetail = new ErrorDetail();
|
||||
errorDetail.setCode(code);
|
||||
errorDetail.setDetail(detail);
|
||||
return errorDetail;
|
||||
}
|
||||
|
||||
private void handleThrowable(MesResponse response, Exception throwable)
|
||||
{
|
||||
response.setTotalResult(MesServices.MES_RESULT_NOT_OK);
|
||||
if (throwable is PluginException)
|
||||
{
|
||||
setResponseValues(response, ((PluginException)throwable).getResponseDetail());
|
||||
}
|
||||
else if (throwable is IOException)
|
||||
{
|
||||
ErrorDetail[] details = response.getErrorDetails();
|
||||
addError(ref details, getErrorDetail(throwable.Message, ResponseDetail.COMMUNICATION_FAILURE));
|
||||
response.setErrorDetails(details);
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorDetail[] details = response.getErrorDetails();
|
||||
addError(ref details, getErrorDetail(throwable.Message, ResponseDetail.PROCESSED_WITH_EXCEPTION));
|
||||
response.setErrorDetails(details);
|
||||
}
|
||||
}
|
||||
|
||||
private void logResponse(MesResponse mesResponse)
|
||||
{
|
||||
if (mesResponse == null)
|
||||
{
|
||||
log(TraceEventType.Information, "finish empty response");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String v = serializer.serialize(mesResponse).ToString();
|
||||
log(TraceEventType.Verbose, "finish response " + mesResponse.getRequestId() + " (" + mesResponse.GetType().Name + ")"
|
||||
+ " with code " + mesResponse.getTotalResult() + "\n" + v);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
log(TraceEventType.Verbose, "finish request " + mesResponse.getRequestId() + " with code " + mesResponse.getTotalResult() + "\ncannot log response message");
|
||||
}
|
||||
}
|
||||
|
||||
private void logRequest(MesRequest mesRequest)
|
||||
{
|
||||
if (mesRequest == null)
|
||||
{
|
||||
log(TraceEventType.Information, "finish empty request");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String v = serializer.serialize(mesRequest).ToString();
|
||||
log(TraceEventType.Verbose, "finish request " + mesRequest.getRequestId() + " (" + mesRequest.GetType().Name + ")" + "\n" + v);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
log(TraceEventType.Verbose, "finish request " + mesRequest.getRequestId() + "\ncannot log request message");
|
||||
}
|
||||
}
|
||||
|
||||
private void setResponseValues(MesResponse response, ResponseDetail responseDetail)
|
||||
{
|
||||
if (responseDetail.getCode() == ResponseDetail.OK)
|
||||
{
|
||||
response.setTotalResult(MesServices.MES_RESULT_OK);
|
||||
return;
|
||||
}
|
||||
response.setTotalResult(MesServices.MES_RESULT_NOT_OK);
|
||||
|
||||
ErrorDetail[] details = response.getErrorDetails();
|
||||
addError(ref details, getErrorDetail(responseDetail.getText(), responseDetail.getCode()));
|
||||
response.setErrorDetails(details);
|
||||
}
|
||||
|
||||
protected IMesServices getFailoverProxy()
|
||||
{
|
||||
return failoverProxy;
|
||||
}
|
||||
|
||||
#region IMesServices_Member
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="createContainerRequest"></param>
|
||||
/// <returns></returns>
|
||||
public CreateContainerResponse mesCreateContainer(CreateContainerRequest createContainerRequest)
|
||||
{
|
||||
CreateContainerResponse responseObject = new CreateContainerResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, createContainerRequest);
|
||||
responseObject = getFailoverProxy().mesCreateContainer(createContainerRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
public CreateMslContainerResponse mesCreateMslContainer(CreateMslContainerRequest createMslContainerRequest)
|
||||
{
|
||||
CreateMslContainerResponse responseObject = new CreateMslContainerResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, createMslContainerRequest);
|
||||
responseObject = getFailoverProxy().mesCreateMslContainer(createMslContainerRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public CheckContainerResponse mesCheckContainer(CheckContainerRequest checkContainerRequest)
|
||||
{
|
||||
CheckContainerResponse responseObject = new CheckContainerResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, checkContainerRequest);
|
||||
responseObject = getFailoverProxy().mesCheckContainer(checkContainerRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
public CheckMslContainerResponse mesCheckMslContainer(CheckMslContainerRequest checkMslContainerRequest)
|
||||
{
|
||||
CheckMslContainerResponse responseObject = new CheckMslContainerResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, checkMslContainerRequest);
|
||||
responseObject = getFailoverProxy().mesCheckMslContainer(checkMslContainerRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public PlacementRecipeCheckResponse mesCheckPlacementRecipe(PlacementRecipeCheckRequest placementRecipeCheckRequest)
|
||||
{
|
||||
PlacementRecipeCheckResponse responseObject = new PlacementRecipeCheckResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, placementRecipeCheckRequest);
|
||||
responseObject = getFailoverProxy().mesCheckPlacementRecipe(placementRecipeCheckRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public InterlockingResponse mesInterlocking(InterlockingRequest interlockingRequest)
|
||||
{
|
||||
InterlockingResponse responseObject = new InterlockingResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, interlockingRequest);
|
||||
responseObject = getFailoverProxy().mesInterlocking(interlockingRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// <param name="name">description</param>
|
||||
/// <returns>description</returns>
|
||||
/// <seealso cref="MesRequest"/>
|
||||
/// </summary>
|
||||
public PanelInfoResponse mesPanelInformation(PanelInfoRequest infoRequest)
|
||||
{
|
||||
PanelInfoResponse responseObject = new PanelInfoResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, infoRequest);
|
||||
responseObject = getFailoverProxy().mesPanelInformation(infoRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public MesResponse mesItemProduced(ItemProducedRequest itemProducedRequest)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, itemProducedRequest);
|
||||
responseObject = getFailoverProxy().mesItemProduced(itemProducedRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesResponse mesMachineState(MachineStatusRequest machineStatus)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, machineStatus);
|
||||
responseObject = getFailoverProxy().mesMachineState(machineStatus);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesResponse mesMachineMessage(MachineMessageRequest machineMessage)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, machineMessage);
|
||||
responseObject = getFailoverProxy().mesMachineMessage(machineMessage);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesFailoverResponse mesGetFailoverList(MesRequest mesRequest)
|
||||
{
|
||||
MesFailoverResponse responseObject = new MesFailoverResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, mesRequest);
|
||||
responseObject = getFailoverProxy().mesGetFailoverList(mesRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesResponse mesMaterialConsumed(MaterialConsumedRequest materialConsumedRequest)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, materialConsumedRequest);
|
||||
responseObject = getFailoverProxy().mesMaterialConsumed(materialConsumedRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public MesConfigurationResponse mesGetConfiguration(MesRequest mesRequest)
|
||||
{
|
||||
MesConfigurationResponse responseObject = new MesConfigurationResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, mesRequest);
|
||||
responseObject = getFailoverProxy().mesGetConfiguration(mesRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finalizeRequest(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public MesResponse mesStart(MesStartRequest mesRequest)
|
||||
{
|
||||
checkRequestPreconditons(mesRequest);
|
||||
MesResponse responseObject = new MesResponse();
|
||||
responseObject.setRequestId(mesRequest.getRequestId());
|
||||
try
|
||||
{
|
||||
if (!isConfigured())
|
||||
{
|
||||
throw new PluginException(ResponseDetail.MES_NOT_CONFIGURED_PROPERLY, "");
|
||||
}
|
||||
|
||||
if (isActive())
|
||||
{
|
||||
setResponseValues(responseObject, new ResponseDetail("", ResponseDetail.OK));
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
|
||||
// append own assembly vresion to mesStart message
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
responseObject = getFailoverProxy().mesStart(mesRequest);
|
||||
stopWatch.Stop();
|
||||
long millies = stopWatch.ElapsedMilliseconds;
|
||||
log(TraceEventType.Information, "roundtrip = " + (millies) + " milliseconds");
|
||||
if (responseObject.getTotalResult() == MES_RESULT_OK)
|
||||
{
|
||||
setActive(true);
|
||||
startUpdateThread();
|
||||
}
|
||||
}
|
||||
catch (PluginException cse)
|
||||
{
|
||||
handleThrowable(responseObject, cse);
|
||||
}
|
||||
finally
|
||||
{
|
||||
logResponse(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesResponse mesGetStatus(MesRequest mesRequest)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, mesRequest);
|
||||
responseObject = getFailoverProxy().mesGetStatus(mesRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
logResponse(responseObject);
|
||||
}
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MesResponse mesStop(MesRequest mesRequest)
|
||||
{
|
||||
MesResponse responseObject = new MesResponse();
|
||||
try
|
||||
{
|
||||
checkPreconditions(responseObject, mesRequest);
|
||||
responseObject = getFailoverProxy().mesStop(mesRequest);
|
||||
}
|
||||
catch (Exception throwable)
|
||||
{
|
||||
handleThrowable(responseObject, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
logResponse(responseObject);
|
||||
}
|
||||
setActive(false);
|
||||
stopUpdateThread();
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
#endregion IMesServices_Member
|
||||
|
||||
#region UpdateThread
|
||||
public void failoverThreadProc()
|
||||
{
|
||||
log(TraceEventType.Information, Thread.CurrentThread.Name + "renew failoverHost list thread started, call #" + (++runCounter));
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
mesGetFailoverList(new MesRequest());
|
||||
log(TraceEventType.Information, Thread.CurrentThread.Name + "renew failoverHost list finished");
|
||||
int millies = refreshFailoverhostsInterval;
|
||||
if (millies == -1)
|
||||
{
|
||||
millies = DEFAULT_REFRESH_INTERVAL;
|
||||
}
|
||||
TimeSpan ts = TimeSpan.FromMilliseconds(millies);
|
||||
log(TraceEventType.Information, Thread.CurrentThread.Name + "next failover resolving in " + ts.ToString());
|
||||
Thread.Sleep(millies);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
log(TraceEventType.Error, Thread.CurrentThread.Name + "interrupted or failed");
|
||||
break;
|
||||
}
|
||||
catch (ThreadInterruptedException)
|
||||
{
|
||||
log(TraceEventType.Error, Thread.CurrentThread.Name + "interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
log(TraceEventType.Information, Thread.CurrentThread.Name + "closed");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
protected Thread getUpdateThread()
|
||||
{
|
||||
String threadName = "failoverUpdateThread#" + (updateThreadCount++);
|
||||
Thread failoverUpdateThread = new Thread(new ThreadStart(failoverThreadProc));
|
||||
|
||||
// threadName) {
|
||||
|
||||
|
||||
//};
|
||||
log(TraceEventType.Error, Thread.CurrentThread.Name + "created");
|
||||
return failoverUpdateThread;
|
||||
}
|
||||
|
||||
protected void startUpdateThread()
|
||||
{
|
||||
// if connection is established and OK start observation thread
|
||||
if (failoverUpdateThread == null)
|
||||
{
|
||||
failoverUpdateThread = getUpdateThread();
|
||||
failoverUpdateThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* the current active channel was closed (port closed on DataInterface)
|
||||
*
|
||||
* @param channelName
|
||||
*/
|
||||
protected void stopUpdateThread()
|
||||
{
|
||||
log(TraceEventType.Information, " was closed by iTAC.MES.Suite DataInterface");
|
||||
|
||||
// den Ueberwachungsthread stoppen
|
||||
if (failoverUpdateThread != null)
|
||||
{
|
||||
log(TraceEventType.Information, " stop " + failoverUpdateThread.Name + " now");
|
||||
failoverUpdateThread.Interrupt();
|
||||
failoverUpdateThread = null;
|
||||
}
|
||||
}
|
||||
private void addError(ref ErrorDetail[] errorDetail1, ErrorDetail errorDetail2)
|
||||
{
|
||||
if (errorDetail1 == null)
|
||||
{
|
||||
errorDetail1 = new ErrorDetail[0];
|
||||
}
|
||||
int newArrSize = errorDetail1.Length + 1;
|
||||
Array.Resize<ErrorDetail>(ref errorDetail1, newArrSize);
|
||||
errorDetail1[newArrSize - 1] = errorDetail2;
|
||||
}
|
||||
#endregion UpdateThread
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
77
interface/commonsmt/dotnetplugin/Plugin/Plugin.csproj
Normal file
77
interface/commonsmt/dotnetplugin/Plugin/Plugin.csproj
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C3D8FC7C-22B2-46F9-842F-19165F078217}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommonSmtPlugin</RootNamespace>
|
||||
<AssemblyName>CommonSmtPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
<DocumentationFile>bin\Release\CommonSmtPlugin.XML</DocumentationFile>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="artes-dotnet">
|
||||
<HintPath>lib\artes-dotnet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CommonSmtApi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>lib\CommonSmtApi.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FailoverHostList.cs" />
|
||||
<Compile Include="FailoverInvocationHandler.cs" />
|
||||
<Compile Include="FailoverProxy.cs" />
|
||||
<Compile Include="IhapEventChannel.cs" />
|
||||
<Compile Include="IMesServicesChannel.cs" />
|
||||
<Compile Include="RequestIdGenerator.cs" />
|
||||
<Compile Include="tool\ItacXmlSerializer.cs" />
|
||||
<Compile Include="ResponseDetail.cs" />
|
||||
<Compile Include="PluginException.cs" />
|
||||
<Compile Include="MesServices.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
51
interface/commonsmt/dotnetplugin/Plugin/PluginException.cs
Normal file
51
interface/commonsmt/dotnetplugin/Plugin/PluginException.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
/// <summary>
|
||||
/// This Exception contains some details about the reason
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PluginException : Exception
|
||||
{
|
||||
|
||||
private ResponseDetail responseDetail;
|
||||
private int p;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public PluginException(ResponseDetail responseDetail)
|
||||
{
|
||||
this.responseDetail = responseDetail;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public PluginException(int p, String message)
|
||||
{
|
||||
this.responseDetail = new ResponseDetail(message, p);
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ResponseDetail getResponseDetail()
|
||||
{
|
||||
|
||||
return responseDetail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die mit einer Assembly verknüpft sind.
|
||||
[assembly: AssemblyTitle("Common SMT Plugin: ${mes.interface.version}/${timestamp}")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("iTAC Software AG")]
|
||||
[assembly: AssemblyProduct("CommonSmtPlugin")]
|
||||
[assembly: AssemblyCopyright("Copyright © iTAC Software AG 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
|
||||
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("fd38d098-5efd-432e-86b9-451f5c47cf00")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||
// übernehmen, indem Sie "*" eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
class RequestIdGenerator
|
||||
{
|
||||
|
||||
protected static int MIN_REQUEST_ID = 0;
|
||||
protected static int MAX_REQUEST_ID = 1000000;
|
||||
|
||||
private int requestId;
|
||||
|
||||
static object lockObject = new object();
|
||||
|
||||
// creates an almost unique id
|
||||
public int getNextId()
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
requestId += 1;
|
||||
if (requestId >= MAX_REQUEST_ID)
|
||||
{
|
||||
requestId = MIN_REQUEST_ID;
|
||||
}
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
124
interface/commonsmt/dotnetplugin/Plugin/ResponseDetail.cs
Normal file
124
interface/commonsmt/dotnetplugin/Plugin/ResponseDetail.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace com.itac.mes.commonsmt
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ResponseDetail
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// WARNINGS, HINTS: positive values
|
||||
/// </summary>
|
||||
public static int OK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-ERRORS: negative values
|
||||
/// </summary>
|
||||
public static int REQUEST_IS_NULL = -10001; //
|
||||
/// <summary>
|
||||
/// any call to MES before mesConfigure was called properly
|
||||
/// </summary>
|
||||
public static int PLUGIN_NOT_CONFIGURED = -10002; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int PLUGIN_NOT_ACTIVE = -10003; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int PLUGIN_NOT_CONNECTED = -10004; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int COMMUNICATION_FAILURE = -10005; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int WRONG_COMMUNICATION_PROPERTIES = -10006; //
|
||||
/// <summary>
|
||||
/// the version from the mes does not fit the version of the interface
|
||||
/// </summary>
|
||||
public static int PLUGIN_VERSION_MISMATCH = -10007; //
|
||||
/// <summary>
|
||||
/// The response was not set before
|
||||
/// </summary>
|
||||
public static int RESPONSE_IS_NULL = -10008; //
|
||||
|
||||
/// <summary>
|
||||
/// Errors from Data Interface negative values
|
||||
/// </summary>
|
||||
public static int MES_NOT_CONNECTED = -20000; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int MES_NOT_CONFIGURED_PROPERLY = -20001; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int MES_NOT_INITIALIZED = -20002; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int PARSED_WITH_EXCEPTION = -20003; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int PROCESSED_WITH_EXCEPTION = -20004; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int SERIALNUMBER_NOT_ALLOWED = -20005; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int PARSE_PROBLEM = -20006; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int NOT_SENT = -20007; //
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int MES_SERVICE_NOT_REACHABLE = -20008; //
|
||||
|
||||
|
||||
private int code;
|
||||
private String text;
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ResponseDetail(String text, int code)
|
||||
{
|
||||
this.text = text;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
interface/commonsmt/dotnetplugin/Plugin/SocketAdapter.cs
Normal file
154
interface/commonsmt/dotnetplugin/Plugin/SocketAdapter.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
#region Namespace
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using com.itac.mes.proxy.business;
|
||||
using com.itac.oib;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace com.itac.mes.proxy.sockets
|
||||
{
|
||||
|
||||
public class SocketAdapter
|
||||
{
|
||||
|
||||
private readonly IList<IhapHandler> _channels = new List<IhapHandler>();
|
||||
private readonly TcpListener _listener;
|
||||
|
||||
private readonly IAdapterControl _adapterControl;
|
||||
private readonly OIBServiceImpl _serviceImpl;
|
||||
|
||||
private bool _isShutdown = false;
|
||||
private int listeningPort;
|
||||
|
||||
// Wenn ein IHapHandler ein Disconnect feststellt wird eine Verbindung entfernt...
|
||||
public void ClientDisconnected(IhapHandler iHapHandler)
|
||||
{
|
||||
// remove handler with disconnected sockets
|
||||
for (int i = _channels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IhapHandler element = _channels[i];
|
||||
if (element == iHapHandler)
|
||||
{
|
||||
_channels[i].shutdown();
|
||||
_channels.RemoveAt(i);
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Remove socket connection.");
|
||||
}
|
||||
}
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "Nr of active connections: " + _channels.Count);
|
||||
}
|
||||
|
||||
public SocketAdapter(int listeningPort, IAdapterControl adapterControl, OIBServiceImpl serviceImpl)
|
||||
{
|
||||
_listener = new TcpListener(IPAddress.Any, listeningPort);
|
||||
_listener.Start();
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Listen on port " + listeningPort);
|
||||
_adapterControl = adapterControl;
|
||||
_serviceImpl = serviceImpl;
|
||||
|
||||
var thread = new Thread(Run);
|
||||
thread.Start();
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Startup " + Constants.SERVICE_NAME + " finished.");
|
||||
|
||||
//
|
||||
// neuen Thread aufmachen, der immer wieder nachguckt, wie oft die IHapHandler benutzt werden. und unbenutzte Verbindungen entfernt
|
||||
var checkAliveThread = new Thread(RunCheckAlive);
|
||||
checkAliveThread.Start();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Thread.CurrentThread.Name = "SocketAdapter";
|
||||
while (!_isShutdown)
|
||||
{
|
||||
TcpClient client;
|
||||
try
|
||||
{
|
||||
client = _listener.AcceptTcpClient();
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "Accepting new socket connection failed", se);
|
||||
continue;
|
||||
}
|
||||
var handler = new IhapHandler(client, _serviceImpl);
|
||||
handler.setAdapterControl(_adapterControl);
|
||||
|
||||
handler.ClientDisconnected += ClientDisconnected;
|
||||
|
||||
_channels.Add(handler);
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Incoming socket connection from " + client.Client.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void RunCheckAlive()
|
||||
{
|
||||
Thread.CurrentThread.Name = "CheckAliveThread";
|
||||
while (!_isShutdown)
|
||||
{
|
||||
bool removed = false;
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "registered incoming socket connections: " + _channels.Count);
|
||||
try
|
||||
{
|
||||
for (int i = _channels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var channel = _channels[i];
|
||||
if (!channel.isConnected())
|
||||
{
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "remove disconnected incoming socket connection for " + channel.getName());
|
||||
_channels.Remove(channel);
|
||||
removed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "" + channel.getName() + " channel last used: " + new DateTime(channel.getLastCall()));
|
||||
if ((channel.getLastCall() + 36001000L) < DateTime.Now.Ticks) // eine Stunde...
|
||||
{
|
||||
// Verbindung schliessen, wenn Sie länger als ... nicht benutzt wurde
|
||||
// channel.shutdown();
|
||||
}
|
||||
}
|
||||
if (removed)
|
||||
{
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "remaining open incoming socket connections after cleanup: " + _channels.Count);
|
||||
}
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "service channel listing interrupted");
|
||||
}
|
||||
|
||||
// LG: Why this??
|
||||
Thread.Sleep(60000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_isShutdown = true;
|
||||
try
|
||||
{
|
||||
_listener.Stop();
|
||||
foreach (var channel in _channels)
|
||||
{
|
||||
if (channel.isConnected())
|
||||
{
|
||||
channel.shutdown();
|
||||
}
|
||||
}
|
||||
_channels.Clear();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Listen port closed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
interface/commonsmt/dotnetplugin/Plugin/lib/CommonSmtApi.dll
Normal file
BIN
interface/commonsmt/dotnetplugin/Plugin/lib/CommonSmtApi.dll
Normal file
Binary file not shown.
BIN
interface/commonsmt/dotnetplugin/Plugin/lib/artes-dotnet.dll
Normal file
BIN
interface/commonsmt/dotnetplugin/Plugin/lib/artes-dotnet.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\bin\Debug\CommonSmtPlugin.dll
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\bin\Debug\CommonSmtPlugin.pdb
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\bin\Debug\artes-dotnet.dll
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\bin\Debug\CommonSmtApi.dll
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\obj\Debug\Plugin.csprojResolveAssemblyReference.cache
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\obj\Debug\CommonSmtPlugin.dll
|
||||
C:\projects_jee\imsinterface\mainline\interface\commonsmt\dotnetplugin\Plugin\obj\Debug\CommonSmtPlugin.pdb
|
||||
Binary file not shown.
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace com.itac.mes.tools
|
||||
{
|
||||
/// <summary>
|
||||
/// This Class is able to serialize all objects to a xml string.
|
||||
/// </summary>
|
||||
public class ItacXmlSerializer
|
||||
{
|
||||
|
||||
private static int MAX_INDENT_LEVEL = 15;
|
||||
private static int indentationWidth = 2;
|
||||
|
||||
private int indentationLevel = 0;
|
||||
private bool formatting = true;
|
||||
private StringBuilder writer;
|
||||
private static String[] indentStrings;
|
||||
private bool logXmlFormat = true;// Eine Möglichkeit auch nicht-XML zu loggen
|
||||
|
||||
|
||||
static ItacXmlSerializer()
|
||||
{
|
||||
indentStrings = new String[MAX_INDENT_LEVEL];
|
||||
for (int level = 0; level < MAX_INDENT_LEVEL; level++)
|
||||
{
|
||||
StringBuilder indentBuffer = new StringBuilder();
|
||||
int count = level * indentationWidth;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
indentBuffer.Append(' ');
|
||||
}
|
||||
indentStrings[level] = indentBuffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// [MethodImpl(MethodImplOptions.Synchronized)]
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public StringBuilder serialize(Object source)
|
||||
{
|
||||
if (source == null) { return new StringBuilder("null"); }
|
||||
writer = new StringBuilder();
|
||||
if (source.GetType().IsArray)
|
||||
{
|
||||
writeArray("", source);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeStart(source.GetType().Name, true);
|
||||
writeStructure(source);
|
||||
writeEnd(source.GetType().Name, true, true);
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
private void indent()
|
||||
{
|
||||
if (formatting)
|
||||
{
|
||||
indentationLevel += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void unindent()
|
||||
{
|
||||
if (formatting && indentationLevel > 0)
|
||||
{
|
||||
indentationLevel -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeArray(String fieldName, Object fieldvalue)
|
||||
{
|
||||
Object[] array = (Object[])fieldvalue;
|
||||
// do not print empty arrays
|
||||
if (array != null && array.Length > 0)
|
||||
{
|
||||
if (!fieldName.Equals(""))
|
||||
{
|
||||
writeStart(fieldName, true);
|
||||
}
|
||||
String simpleClassName = fieldvalue.GetType().Name.Substring(0, fieldvalue.GetType().Name.Length - 2);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
writeStart(simpleClassName, true);
|
||||
writeObject("", array[i]);
|
||||
writeEnd(simpleClassName, true, false);
|
||||
}
|
||||
|
||||
if (!fieldName.Equals(""))
|
||||
{
|
||||
writeEnd(fieldName, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeList(String fieldName, Object fieldvalue)
|
||||
{
|
||||
IList array = (IList)fieldvalue;
|
||||
// do not print empty arrays
|
||||
if (array != null && array.Count > 0)
|
||||
{
|
||||
if (!fieldName.Equals(""))
|
||||
{
|
||||
writeStart(fieldName, true);
|
||||
}
|
||||
String simpleClassName = fieldvalue.GetType().Name.Substring(0, fieldvalue.GetType().Name.Length - 2);
|
||||
for (int i = 0; i < array.Count; i++)
|
||||
{
|
||||
// writeStart(simpleClassName, true);
|
||||
writeStructure(array[i]);
|
||||
// writeEnd(simpleClassName, true, false);
|
||||
}
|
||||
|
||||
if (!fieldName.Equals(""))
|
||||
{
|
||||
writeEnd(fieldName, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void allClassProperties(List<PropertyInfo> fieldList, Type clazz)
|
||||
{
|
||||
// über alle Felder aller parent Interfaces, solange das Interface nicht Object ist.
|
||||
if (clazz == null || clazz == typeof(Object))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// fields: all public fields
|
||||
PropertyInfo[] fields = clazz.GetProperties();
|
||||
foreach (PropertyInfo field in fields)
|
||||
{
|
||||
fieldList.Add(field);
|
||||
}
|
||||
allClassProperties(fieldList, clazz.BaseType);
|
||||
}
|
||||
|
||||
private void allClassFields(List<FieldInfo> fieldList, Type clazz)
|
||||
{
|
||||
// über alle Felder aller parent Interfaces, solange das Interface nicht Object ist.
|
||||
if (clazz == null || clazz == typeof(Object))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// fields: all public fields
|
||||
FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance| BindingFlags.NonPublic);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
fieldList.Add(field);
|
||||
}
|
||||
|
||||
// allClassFields(fieldList, clazz.BaseType);
|
||||
}
|
||||
|
||||
private void writeStructure(Object source)
|
||||
{
|
||||
List<PropertyInfo> propertyList = new List<PropertyInfo>();
|
||||
allClassProperties(propertyList, source.GetType());
|
||||
|
||||
List<FieldInfo> fieldList = new List<FieldInfo>();
|
||||
allClassFields(fieldList, source.GetType());
|
||||
foreach (PropertyInfo field2 in propertyList)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object fieldvalue = field2.GetValue(source, null);
|
||||
writeObject(field2.Name, fieldvalue);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
writeObject(field2.Name, "property write failed");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (FieldInfo field2 in fieldList)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object fieldvalue = field2.GetValue(source);
|
||||
writeObject(field2.Name, fieldvalue);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
writeObject(field2.Name, "field write failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(String fieldName, object fieldvalue)
|
||||
{
|
||||
if (fieldvalue == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fieldvalue.GetType() == typeof(String))
|
||||
{
|
||||
writeString(fieldName, (String)fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType() == typeof(DateTime))
|
||||
{
|
||||
writeDate(fieldName, (DateTime)fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType() == typeof(bool) || fieldvalue.GetType() == typeof(Boolean))
|
||||
{
|
||||
if (((bool)fieldvalue)) { writeString(fieldName, "true"); } else { writeString(fieldName, "false"); }
|
||||
}
|
||||
else if (fieldvalue.GetType() == typeof(byte) || fieldvalue.GetType() == typeof(int) || fieldvalue.GetType() == typeof(Int16) || fieldvalue.GetType() == typeof(Int32)
|
||||
|| fieldvalue.GetType() == typeof(Int64))
|
||||
{
|
||||
writeIntNumber(fieldName, (Object)fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType() == typeof(double) || fieldvalue.GetType() == typeof(float))
|
||||
{
|
||||
writeNumber(fieldName, (Object)fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType() == typeof(Double))
|
||||
{
|
||||
writeNumber(fieldName, (Object)fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType().IsGenericType)
|
||||
{
|
||||
writeList(fieldName, fieldvalue);
|
||||
}
|
||||
else if (fieldvalue.GetType().IsArray)
|
||||
{
|
||||
writeArray(fieldName, fieldvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Strukturierten Wert schreiben
|
||||
writeStart(fieldName, true);
|
||||
writeStructure(fieldvalue);
|
||||
writeEnd(fieldName, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDate(String fieldName, DateTime fieldvalue)
|
||||
{
|
||||
writeStart(fieldName, false);
|
||||
writer.Append(fieldvalue.ToString("o"));
|
||||
writeEnd(fieldName, false, false);
|
||||
}
|
||||
|
||||
private void writeStart(string fieldName, bool endLineAndIndent)
|
||||
{
|
||||
startLine();
|
||||
if (logXmlFormat)
|
||||
{
|
||||
writer.Append("<");
|
||||
writer.Append(fieldName);
|
||||
writer.Append(">");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Append(fieldName);
|
||||
writer.Append(": ");
|
||||
}
|
||||
if (endLineAndIndent)
|
||||
{
|
||||
endLine();
|
||||
indent();
|
||||
}
|
||||
}
|
||||
private void writeEnd(string fieldName, bool indenting, bool newLine)
|
||||
{
|
||||
if (logXmlFormat)
|
||||
{
|
||||
if (indenting)
|
||||
{
|
||||
unindent();
|
||||
startLine();
|
||||
}
|
||||
writer.Append("</");
|
||||
writer.Append(fieldName);
|
||||
writer.Append(">");
|
||||
endLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (indenting)
|
||||
{
|
||||
unindent();
|
||||
}
|
||||
if (newLine)
|
||||
{
|
||||
endLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNumber(String fieldName, Object fieldvalue)
|
||||
{
|
||||
writeStart(fieldName, false);
|
||||
writer.Append(fieldvalue.ToString());
|
||||
writeEnd(fieldName, false, true);
|
||||
}
|
||||
|
||||
private void writeIntNumber(String fieldName, Object fieldvalue)
|
||||
{
|
||||
writeStart(fieldName, false);
|
||||
writer.Append(fieldvalue.ToString());
|
||||
writeEnd(fieldName, false, true);
|
||||
}
|
||||
|
||||
private void writeString(String fieldName, String value)
|
||||
{
|
||||
writeStart(fieldName, false);
|
||||
writer.Append(value);
|
||||
writeEnd(fieldName, false, true);
|
||||
}
|
||||
|
||||
private void endLine()
|
||||
{
|
||||
if (formatting)
|
||||
{
|
||||
writer.Append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void startLine()
|
||||
{
|
||||
if (formatting)
|
||||
{
|
||||
writer.Append(indentStrings[Math.Min(indentationLevel, MAX_INDENT_LEVEL)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user