/* * 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 { /// /// documentation for the namespace /// [System.Runtime.CompilerServices.CompilerGenerated] class NamespaceDoc { } public class MyEventArgs : EventArgs { public TraceEventType traceEventType; public String message; } /// /// /// public delegate void MyEventHandler(Object sender, MyEventArgs e); /// /// Class level summary documentation goes here. /// /// Longer comments can be associated with a type or member through /// the remarks tag. public class MesServices : IMesServices { /// /// /// public event MyEventHandler OnLog; /// /// return this value in {@link MesResponse#setTotalResult(int)} /// {@link MesResponse#getTotalResult()} for any request /// which was processed successfully. /// All returned values are be valid. public static int MES_RESULT_OK = 0; /// /// 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. /// 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; /// /// do not marshal objects but print as xml /// private ItacXmlSerializer serializer = new ItacXmlSerializer(); //// failover detection private static int updateThreadCount; private Thread failoverUpdateThread; private int refreshFailoverhostsInterval; /// /// /// 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; } /// /// Vorbedingungen sind dass der Request gesetzt ist, sowie die Konfiguration und die aktivierung des Plugin /// /// Parameter description for s goes here. /// Parameter description for s goes here. /// /// 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 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 /// /// Description for SomeMethod. /// 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 /// /// /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// description /// description /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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; } /// /// /// 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(ref errorDetail1, newArrSize); errorDetail1[newArrSize - 1] = errorDetail2; } #endregion UpdateThread } }