initialize
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Ascii {
|
||||
|
||||
/** Konstanten */
|
||||
public static final byte NUL = 0x00; // null
|
||||
public static final byte SOH = 0x01; // start of
|
||||
public static final byte STX = 0x02; // start of text
|
||||
public static final byte ETX = 0x03; // end of text
|
||||
public static final byte EOT = 0x04; // end of transmission
|
||||
public static final byte ENQ = 0x05; // enquiry
|
||||
public static final byte ACK = 0x06; // acknowledge
|
||||
public static final byte BEL = 0x07; // bell
|
||||
public static final byte BS = 0x08; // backspace
|
||||
public static final byte TAB = 0x09; // tabulator
|
||||
public static final byte NL = 0x0A; // NL new line (or LF, line feed)
|
||||
public static final byte VT = 0x0B; // VT vertical tab
|
||||
public static final byte NP = 0x0C; // NP new page (or FF, form feed)
|
||||
public static final byte CR = 0x0D; // CR carriage return
|
||||
public static final byte SO = 0x0E; // SO shift out
|
||||
public static final byte SI = 0x0F; // SI shift in
|
||||
public static final byte DLE = 0x10; // DLE data link escape
|
||||
public static final byte DC1 = 0x11; // DC1 device control 1
|
||||
public static final byte DC2 = 0x12; // DC2 device control 2
|
||||
public static final byte DC3 = 0x13; // DC3 device control 3
|
||||
public static final byte DC4 = 0x14; // DC4 device control 4
|
||||
public static final byte NAK = 0x15; // NAK negative acknowledge
|
||||
public static final byte SYN = 0x16; // SYN synchronous idle
|
||||
public static final byte ETB = 0x17; // ETB end of transmission block
|
||||
public static final byte CAN = 0x18; // CAN cancel
|
||||
public static final byte EM = 0x19; // EM end of medium
|
||||
public static final byte SUB = 0x1A; // SUB substitute
|
||||
public static final byte ESC = 0x1B; // ESC escape
|
||||
public static final byte FS = 0x1C; // FS file separator
|
||||
public static final byte GS = 0x1D; // GS group separator
|
||||
public static final byte RS = 0x1E; // RS record separator
|
||||
public static final byte US = 0x1F; // US unit separator
|
||||
public static final byte SPC = 0x20; // US unit separator
|
||||
|
||||
public static final char TAB_ = (char) Ascii.TAB;
|
||||
public static final char CR_ = (char) Ascii.CR;
|
||||
|
||||
|
||||
/** diejenigen Zeichen, die in der Form <TAB> ausgegeben werden sollen */
|
||||
public static Set<Byte> explicitPrintableConstants = new HashSet<Byte>();
|
||||
|
||||
/** diejenigen Zeichen, die im steuerbereich liegen und ohne Umwandlung ausgegeben werden sollen */
|
||||
public static Set<Byte> directPrintableConstants = new HashSet<Byte>();
|
||||
|
||||
public static Object getUserTextForChar(char c) {
|
||||
if (explicitPrintableConstants.contains((byte)c)) {
|
||||
return getPrintableStringforChar((byte) c);
|
||||
} else if (directPrintableConstants.contains((byte)c)) {
|
||||
return c;
|
||||
} else if (c < SPC || c >= 127) {
|
||||
// alle normalerweise nicht druckbaren Zeichen in Hex-ausgeben
|
||||
return "<0x" + Integer.toHexString((byte) c) + ">";
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private static String getPrintableStringforChar(byte c) {
|
||||
switch (c) {
|
||||
case NUL:
|
||||
return "<NUL>";
|
||||
case SOH:
|
||||
return "<SOH>";
|
||||
case STX:
|
||||
return "<STX>";
|
||||
case ETX:
|
||||
return "<ETX>";
|
||||
case EOT:
|
||||
return "<EOT>";
|
||||
case ENQ:
|
||||
return "<ENQ>";
|
||||
case ACK:
|
||||
return "<ACK>";
|
||||
case BEL:
|
||||
return "<BEL>";
|
||||
case BS:
|
||||
return "<BS>";
|
||||
case TAB:
|
||||
return "<TAB>";
|
||||
case NL:
|
||||
return "<NL>";
|
||||
case VT:
|
||||
return "<VT>";
|
||||
case NP:
|
||||
return "<NP>";
|
||||
case CR:
|
||||
return "<CR>";
|
||||
case SO:
|
||||
return "<SO>";
|
||||
case SI:
|
||||
return "<SI>";
|
||||
case DLE:
|
||||
return "<DLE>";
|
||||
case DC1:
|
||||
return "<DC1>";
|
||||
case DC2:
|
||||
return "<DC2>";
|
||||
case DC3:
|
||||
return "<DC3>";
|
||||
case DC4:
|
||||
return "<DC4>";
|
||||
case NAK:
|
||||
return "<NAK>";
|
||||
case SYN:
|
||||
return "<SYN>";
|
||||
case ETB:
|
||||
return "<ETB>";
|
||||
case CAN:
|
||||
return "<CAN>";
|
||||
case EM:
|
||||
return "<EM>";
|
||||
case SUB:
|
||||
return "<SUB>";
|
||||
case ESC:
|
||||
return "<ESC>";
|
||||
case FS:
|
||||
return "<FS>";
|
||||
case GS:
|
||||
return "<GS>";
|
||||
case RS:
|
||||
return "<RS>";
|
||||
case US:
|
||||
return "<US>";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// alle Zeichen STX, ETX, SOH werden in der Form "<STX>" ausgegeben, alle anderen Zeichen als Text
|
||||
public static String toReadableString(StringBuffer source) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (int i = 0; i < source.length(); i++) {
|
||||
char c = source.charAt(i);
|
||||
result.append(getUserTextForChar(c));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
public interface IMesServicesLog {
|
||||
|
||||
/**
|
||||
* default printing information (as System.out)
|
||||
*
|
||||
* @param text
|
||||
* the text to be printed
|
||||
*/
|
||||
public void out(String text);
|
||||
|
||||
/**
|
||||
* default error printing (as System.err)
|
||||
*
|
||||
* @param text
|
||||
* the text to be printed
|
||||
*/
|
||||
public void err(String text);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
public class InvalidMessageFormatException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
public InvalidMessageFormatException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
|
||||
public InvalidMessageFormatException(String pattern, Object... arguments) {
|
||||
super(MessageFormat.format(pattern, arguments));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
public class RequestIdGenerator {
|
||||
|
||||
protected static int MIN_REQUEST_ID = 0;
|
||||
protected static int MAX_REQUEST_ID = 1000000;
|
||||
|
||||
private int requestId;
|
||||
|
||||
// creates an almost unique id
|
||||
public synchronized int getNextId() {
|
||||
requestId += 1;
|
||||
if (requestId >= MAX_REQUEST_ID) {
|
||||
requestId = MIN_REQUEST_ID;
|
||||
}
|
||||
return requestId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.ihap;
|
||||
|
||||
public class InstanceInfo {
|
||||
|
||||
private String instanceName;
|
||||
private InstanceState instanceState;
|
||||
|
||||
/**
|
||||
* @param instanceName
|
||||
*/
|
||||
public void setInstanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param instanceState
|
||||
*/
|
||||
public void setInstanceState(InstanceState instanceState) {
|
||||
this.instanceState = instanceState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getInstanceName() {
|
||||
return instanceName == null ? "" : instanceName;
|
||||
}
|
||||
|
||||
public String getInfoText() {
|
||||
return getInstanceName() + ": " + getInstanceState().name();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always a valid state, never null
|
||||
*/
|
||||
public InstanceState getInstanceState() {
|
||||
return instanceState == null ? InstanceState.INITIALIZED : instanceState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.ihap;
|
||||
|
||||
import com.itac.resource.ResourcePool;
|
||||
import com.itac.resource.ResourcesIMSInterfaces;
|
||||
|
||||
public enum InstanceState {
|
||||
|
||||
INITIALIZED(ResourcesIMSInterfaces.INSTANCE_INITIALIZED), //
|
||||
RUNNING(ResourcesIMSInterfaces.INSTANCE_RUNNING), //
|
||||
PAUSED(ResourcesIMSInterfaces.INSTANCE_PAUSED), //
|
||||
STOPPED(ResourcesIMSInterfaces.INSTANCE_STOPPED), //
|
||||
LICENSE_BLOCKED(ResourcesIMSInterfaces.INSTANCE_LICENSE_BLOCKED);
|
||||
|
||||
private int resourceId;
|
||||
|
||||
private InstanceState(int resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
public String getLocalizedText() {
|
||||
if (resourceId < 0) {
|
||||
return name();
|
||||
}
|
||||
return ResourcePool.getInstance().getString(resourceId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.socket;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Socket;
|
||||
|
||||
import com.itac.artes.ihap.IhapFaultReply;
|
||||
import com.itac.artes.ihap.IhapInputStream;
|
||||
import com.itac.artes.ihap.IhapOutputStream;
|
||||
import com.itac.artes.ihap.IhapProtocolException;
|
||||
import com.itac.artes.ihap.IhapReply;
|
||||
import com.itac.artes.ihap.IhapSuccessReply;
|
||||
import com.itac.mes.datainterface.data.IMesServicesLog;
|
||||
|
||||
/**
|
||||
* The basic function for an Ihap Handler. It is responsible for sending calls to a iHap server socket and evaluates the responses.
|
||||
*
|
||||
* @author frankp
|
||||
*
|
||||
*/
|
||||
public class BaseIhapHandler implements InvocationHandler {
|
||||
|
||||
/**
|
||||
* the interval in milliseconds. This defines how long the channel may be unsused before a check is sent to find out if the
|
||||
* connection is still active.
|
||||
*/
|
||||
private static final int CONNECTION_CHECK_MILLIES = 500;
|
||||
/** the client socket for communication */
|
||||
private Socket clientSocket;
|
||||
/** streams for reading and writing data to or from the connection */
|
||||
private IhapInputStream inputStream;
|
||||
private IhapOutputStream outputStream;
|
||||
/**
|
||||
* if this flag is true no more communication over this connection is possible.<br>
|
||||
* The connection is shut down when a communication failure occures or when the shutdown() method is invoked.
|
||||
*/
|
||||
private boolean isShutdown;
|
||||
/** the name of the channel; used for logging and debugging purposes */
|
||||
private String channelName;
|
||||
/** time of the last successful call or time of initialization */
|
||||
private long lastCall = System.currentTimeMillis();
|
||||
private Object lockObject = new Object();
|
||||
/** This listener fires when the connection was stopped by the server */
|
||||
private PropertyChangeListener connectionStateChangeListener;
|
||||
/** this thread observes the communication channel */
|
||||
private Thread aliveThread;
|
||||
/** as long as callActive is true a call is executed */
|
||||
private boolean callActive;
|
||||
/** Log messages to this MesLog or log to console if unset */
|
||||
private IMesServicesLog log;
|
||||
|
||||
public static BaseIhapHandler createHandler(String host, int port, String channelName,
|
||||
PropertyChangeListener connectionStateCloseListener, ClassLoader classLoader, IMesServicesLog log) throws IOException {
|
||||
BaseIhapHandler handler = new BaseIhapHandler();
|
||||
handler.setLog(log);
|
||||
@SuppressWarnings("resource")
|
||||
Socket socket = new Socket(host, port);
|
||||
handler.clientSocket = socket;
|
||||
handler.inputStream = new IhapInputStream(socket.getInputStream());
|
||||
handler.outputStream = new IhapOutputStream(socket.getOutputStream());
|
||||
|
||||
handler.channelName = channelName;
|
||||
handler.connectionStateChangeListener = connectionStateCloseListener;
|
||||
// handler._iis.setDebug(true);
|
||||
// handler._ios.setDebug(true);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
Object result = null;
|
||||
if (method.getName().equals(": isShutdown")) {
|
||||
return isShutdown;
|
||||
} else if (method.getName().equals("startup")) {
|
||||
// control the connection
|
||||
getLog().out(getChannelName() + ": startup");
|
||||
|
||||
if (connectionStateChangeListener != null) {
|
||||
aliveThread = new Thread(getChannelName() + "AliveThread") {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!isShutdown && !isInterrupted()) {
|
||||
// is the last call is longer ago than ... millies
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) { // ignore this exception
|
||||
}
|
||||
if (System.currentTimeMillis() - lastCall > CONNECTION_CHECK_MILLIES) {
|
||||
try {
|
||||
// try to ping the server
|
||||
// if this fails the conenction is broken
|
||||
synchronized (lockObject) {
|
||||
// writing a bool value is as goog as calling a function.
|
||||
// This is to chek if a connection (the server part) is still active.
|
||||
if (!isShutdown && !isInterrupted()) {
|
||||
// initiate a call if connection is valid
|
||||
|
||||
// do not check whilst a call is running
|
||||
if (!callActive) {
|
||||
outputStream.writeBoolean(true);
|
||||
outputStream.flush();
|
||||
}
|
||||
lastCall = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
} catch (IOException e3) {
|
||||
try {
|
||||
isShutdown = true;
|
||||
clientSocket.close();
|
||||
} catch (IOException e) {
|
||||
// ignore exceptions when shutting down
|
||||
getLog().out("shutdown connection problem for " + getChannelName());
|
||||
} finally {
|
||||
// can't write, kill the connection
|
||||
getLog().out("detected broken connection for " + getChannelName() + " because server closed port");
|
||||
connectionClosed();
|
||||
}
|
||||
} catch (Exception except) {
|
||||
getLog().err("shutdown connection problem for " + getChannelName());
|
||||
except.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
aliveThread.start();
|
||||
}
|
||||
return null;
|
||||
} else if (method.getName().equals("toString")) {
|
||||
return toString();
|
||||
} else if (method.getName().equals("getChannelName")) {
|
||||
return this.getChannelName();
|
||||
} else if (method.getName().equals("shutdown")) {
|
||||
stopAliveThread();
|
||||
isShutdown = true;
|
||||
clientSocket.close();
|
||||
getLog().out("shut down " + getChannelName() + " on local port " + clientSocket.getLocalPort() + " finished");
|
||||
connectionClosed();
|
||||
return null;
|
||||
}
|
||||
synchronized (lockObject) {
|
||||
outputStream.writeBoolean(false);
|
||||
result = sendCall(method, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IMesServicesLog getLog() {
|
||||
if (log == null) {
|
||||
log = new IMesServicesLog() {
|
||||
|
||||
@Override
|
||||
public void out(String text) {
|
||||
System.out.println(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void err(String text) {
|
||||
System.err.println(text);
|
||||
}
|
||||
};
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(IMesServicesLog log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
protected void connectionClosed() {
|
||||
if (connectionStateChangeListener != null) {
|
||||
connectionStateChangeListener.propertyChange(new PropertyChangeEvent(this, "connectionClosed", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void stopAliveThread() {
|
||||
if (aliveThread == null) {
|
||||
return;
|
||||
}
|
||||
if (aliveThread.isAlive()) {
|
||||
aliveThread.interrupt();
|
||||
}
|
||||
aliveThread = null;
|
||||
}
|
||||
|
||||
private Object sendCall(Method method, Object[] args) throws Exception {
|
||||
callActive = true;
|
||||
lastCall = System.currentTimeMillis();
|
||||
Object result = null;
|
||||
try {
|
||||
outputStream.call(method, args);
|
||||
outputStream.flush();
|
||||
getLog().out(getChannelName() + ": flush methodcall " + method.getName());
|
||||
IhapReply reply = inputStream.readReply();
|
||||
getLog().out(getChannelName() + ": read " + reply.getClass().getSimpleName() + " for method " + method.getName());
|
||||
if (reply instanceof IhapSuccessReply) {
|
||||
result = ((IhapSuccessReply) reply).getReturnValue();
|
||||
} else {
|
||||
IhapFaultReply fault = (IhapFaultReply) reply;
|
||||
switch (fault.getFaultCode()) {
|
||||
case NoSuchMethodException:
|
||||
throw new NoSuchMethodException(fault.getMessage());
|
||||
case ProtocolException:
|
||||
throw new IhapProtocolException(fault.getMessage(), null);
|
||||
default:
|
||||
throw new IhapProtocolException(fault.getMessage(), null);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
getLog().err(getChannelName() + ": invoking remote call " + method.getName() + " failed.");
|
||||
stopAliveThread();
|
||||
throw e;
|
||||
}
|
||||
callActive = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getChannelName() {
|
||||
return channelName == null ? "" : channelName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (clientSocket != null) {
|
||||
return clientSocket.toString();
|
||||
|
||||
}
|
||||
return "IhapHandler";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
package com.itac.mes.datainterface.socket;
|
||||
|
||||
import static com.itac.util.logging.LogLevel.DEBUG;
|
||||
import static com.itac.util.logging.LogLevel.ERROR;
|
||||
import static com.itac.util.logging.LogLevel.INFO;
|
||||
import static com.itac.util.logging.LogLevel.WARN;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import com.itac.artes.ihap.ArtesRemoteException;
|
||||
import com.itac.artes.ihap.FaultCode;
|
||||
import com.itac.artes.ihap.IhapCall;
|
||||
import com.itac.artes.ihap.IhapInputStream;
|
||||
import com.itac.artes.ihap.IhapOutputStream;
|
||||
import com.itac.artes.ihap.IhapProtocolException;
|
||||
import com.itac.artes.ihap.serialize.ProtocolMapping;
|
||||
import com.itac.artes.ihap.serialize.ProtocolMappingFactory;
|
||||
import com.itac.util.logging.LogHandler;
|
||||
|
||||
/**
|
||||
* @author frankp created 2010
|
||||
*/
|
||||
public class GenericIhapServerEventHandler<T> {
|
||||
|
||||
private static final String LOGGER = GenericIhapServerEventHandler.class.getSimpleName();
|
||||
private static final long serialVersionUID = -3032397461757597876L;
|
||||
|
||||
/** Map mit den Namen aller zu empfangenden Methoden */
|
||||
private static Hashtable<String, Method> _methodMap;
|
||||
|
||||
private static int handlerCounter;
|
||||
private T mesService;
|
||||
private Socket _client;
|
||||
private IhapOutputStream _ios;
|
||||
private IhapInputStream _iis;
|
||||
private boolean _isShutdown;
|
||||
private String handlerName = "";
|
||||
private Thread receiveThread;
|
||||
private PropertyChangeListener changeListener;
|
||||
|
||||
public GenericIhapServerEventHandler(Socket client, T serviceHandler, PropertyChangeListener changeListener) {
|
||||
handlerCounter++;
|
||||
this._client = client;
|
||||
this.mesService = serviceHandler;
|
||||
this.changeListener = changeListener;
|
||||
initMethodMap();
|
||||
|
||||
// das ist der initiale Name des Empfangthreads. Wenn der iTAC.OIB.Adapter die Methode setChannelName aufruft wird
|
||||
// der neue (eindeutige Name) an den Thread vergeben. Der ist dann auch mit Tools wie z.B. JvisualVM zu sehen
|
||||
handlerName = "IHapServerEventHandler#" + handlerCounter;
|
||||
receiveThread = new Thread(handlerName) {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
_ios = new IhapOutputStream(_client.getOutputStream());
|
||||
} catch (IOException e1) {
|
||||
LogHandler.log(LOGGER, ERROR, toString() + " failed to create input stream!", e1);
|
||||
}
|
||||
try {
|
||||
_iis = new IhapInputStream(_client.getInputStream());
|
||||
} catch (IOException e1) {
|
||||
LogHandler.log(LOGGER, ERROR, toString() + " failed to create output stream!", e1);
|
||||
}
|
||||
try {
|
||||
while (!_isShutdown && isConnected()) {
|
||||
receiveCall();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// keine Fehlerausgabe, wird durch shutdown() korrekt behandelt!
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GenericIhapServerEventHandler.this.toString();
|
||||
}
|
||||
};
|
||||
receiveThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* einmalig für diese Klasse eine Map aufbauen, in der alle remote aufrufbaren Methoden enthalten sind.
|
||||
*/
|
||||
private synchronized void initMethodMap() {
|
||||
if (_methodMap != null) {
|
||||
return;
|
||||
}
|
||||
ProtocolMapping protocolMapping = ProtocolMappingFactory.getMapping(1);
|
||||
_methodMap = new Hashtable<String, Method>();
|
||||
Method[] methods = mesService.getClass().getDeclaredMethods();
|
||||
LogHandler.log(LOGGER, DEBUG, "implements interface '" + mesService.getClass().getSimpleName() + "'");
|
||||
for (Method method : methods) {
|
||||
LogHandler.log(LOGGER, DEBUG, "implements method '" + method.getName() + "'");
|
||||
_methodMap.put(protocolMapping.getOverloadMethodName(method), method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shutting down this connection
|
||||
*/
|
||||
public void shutdown() {
|
||||
_isShutdown = true;
|
||||
try {
|
||||
_client.close();
|
||||
} catch (Exception e) {
|
||||
LogHandler.log(LOGGER, WARN, handlerName + " closing tcp client failed!", e);
|
||||
}
|
||||
if (changeListener != null) {
|
||||
changeListener.propertyChange(new PropertyChangeEvent(this, "closing", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isConnected() {
|
||||
return _client.isConnected();
|
||||
}
|
||||
|
||||
// public boolean isShutdownInProgress() {
|
||||
// return _isShutdown;
|
||||
// }
|
||||
|
||||
private void receiveCall() throws IOException {
|
||||
try {
|
||||
Exception fault = null;
|
||||
Object returnValue = null;
|
||||
String methodName = null;
|
||||
try {
|
||||
boolean boolValue = _iis.readBoolean();
|
||||
if (!boolValue) {
|
||||
IhapCall lCall = _iis.readCall();
|
||||
methodName = lCall.getOverloadMethodName();
|
||||
LogHandler.log(LOGGER, INFO, toString() + " receive method call '" + methodName + "'");
|
||||
if (methodName.equals("setChannelName_string")) {
|
||||
handlerName = lCall.getArgs()[0].toString();
|
||||
receiveThread.setName(handlerName);
|
||||
} else if (_methodMap.containsKey(methodName)) {
|
||||
Method lMethod = _methodMap.get(methodName);
|
||||
Object[] args = lCall.getArgs();
|
||||
returnValue = lMethod.invoke(mesService, args);
|
||||
LogHandler.log(LOGGER, INFO, toString() + " return value ");
|
||||
} else {
|
||||
throw new NoSuchMethodException();
|
||||
}
|
||||
}
|
||||
} catch (IhapProtocolException pe) {
|
||||
if (pe.getMessage().endsWith("end of file")) {
|
||||
throw pe;
|
||||
}
|
||||
fault = new ArtesRemoteException(toString() + "Unable to read client request", pe);
|
||||
_ios.writeFaultReply(FaultCode.ProtocolException, fault);
|
||||
} catch (NoSuchMethodException nsm) {
|
||||
fault = new ArtesRemoteException(toString() + "Unknown method '" + methodName + "'");
|
||||
_ios.writeFaultReply(FaultCode.NoSuchMethodException, fault);
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
} catch (Exception e) {
|
||||
fault = e;
|
||||
_ios.writeFaultReply(FaultCode.ServiceException, fault);
|
||||
}
|
||||
if (fault == null) {
|
||||
_ios.writeSuccessReply(returnValue);
|
||||
}
|
||||
} catch (SocketException socketException) {
|
||||
LogHandler.log(LOGGER, ERROR, toString() + " disconnected!");
|
||||
shutdown();
|
||||
} catch (IOException ioe) {
|
||||
if (ioe.getMessage().endsWith("end of file")) {
|
||||
LogHandler.log(LOGGER, ERROR, toString() + " disconnected!");
|
||||
shutdown();
|
||||
} else {
|
||||
LogHandler.log(LOGGER, ERROR, toString() + ": Error receiving call:" + ioe.getMessage() + "\n", ioe);
|
||||
}
|
||||
throw ioe;
|
||||
} finally {
|
||||
try {
|
||||
_ios.flush();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Handler " + handlerName + " on socket(" + _client.getRemoteSocketAddress() + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
package com.itac.mes.datainterface.socket;
|
||||
|
||||
import static com.itac.util.logging.LogLevel.ERROR;
|
||||
import static com.itac.util.logging.LogLevel.INFO;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.itac.util.logging.LogHandler;
|
||||
|
||||
/**
|
||||
* @author frankp created 2010
|
||||
*/
|
||||
public class GenericSocketAdapter<T> implements PropertyChangeListener {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final String LOGGER = GenericSocketAdapter.class.getSimpleName();
|
||||
|
||||
private List<GenericIhapServerEventHandler<T>> _channels = new ArrayList<GenericIhapServerEventHandler<T>>();
|
||||
|
||||
private ServerSocket serverSocket = null;
|
||||
|
||||
private T mesServiceHandler = null;
|
||||
|
||||
private boolean _isShutdown = false;
|
||||
|
||||
private Thread socketAdapterThread;
|
||||
|
||||
private int listeningPort;
|
||||
|
||||
public GenericSocketAdapter(int listeningPort, T eventHandler) {
|
||||
this.listeningPort = listeningPort;
|
||||
if (!startServerSocket()) {
|
||||
return;
|
||||
}
|
||||
this.mesServiceHandler = eventHandler;
|
||||
start();
|
||||
}
|
||||
|
||||
private boolean startServerSocket() {
|
||||
LogHandler.log(LOGGER, INFO, "create socket listener for port " + listeningPort);
|
||||
try {
|
||||
serverSocket = new java.net.ServerSocket(listeningPort);
|
||||
} catch (IOException e) {
|
||||
LogHandler.log(LOGGER, ERROR, "no socket listener for port " + listeningPort + " created", e);
|
||||
return false;
|
||||
}
|
||||
LogHandler.log(LOGGER, INFO, "Listen on port " + listeningPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void start() {
|
||||
if (serverSocket == null || serverSocket.isClosed()) {
|
||||
if (!startServerSocket()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (socketAdapterThread != null && !socketAdapterThread.isInterrupted()) {
|
||||
LogHandler.log(LOGGER, INFO, "GenericSocketAdapter already running");
|
||||
return;
|
||||
}
|
||||
LogHandler.log(LOGGER, INFO, "Startup GenericSocketAdapter ");
|
||||
socketAdapterThread = new Thread("GenericSocketAdapter") {
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public void run() {
|
||||
while (!_isShutdown) {
|
||||
Socket client = null;
|
||||
try {
|
||||
client = serverSocket.accept();
|
||||
} catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
GenericIhapServerEventHandler<T> handler = new GenericIhapServerEventHandler<T>(client, mesServiceHandler,
|
||||
GenericSocketAdapter.this);
|
||||
|
||||
_channels.add(handler);
|
||||
LogHandler.log(LOGGER, INFO, "Incoming socket connection from " + client.getRemoteSocketAddress());
|
||||
}
|
||||
}
|
||||
};
|
||||
socketAdapterThread.start();
|
||||
LogHandler.log(LOGGER, INFO, "Startup GenericSocketAdapter finished.");
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
// wenn der AcceptThread nicht läuft einfach fertig
|
||||
if (socketAdapterThread == null || socketAdapterThread.isInterrupted()) {
|
||||
LogHandler.log(LOGGER, INFO, "no GenericSocketAdapter running");
|
||||
return;
|
||||
}
|
||||
|
||||
socketAdapterThread.interrupt();
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (IOException e) {
|
||||
LogHandler.log(LOGGER, ERROR, "closing GenericSocketAdapter failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void shutdown() {
|
||||
LogHandler.log(LOGGER, INFO, "shutdown GenericSocketAdapter for incoming Channels from DataInterface");
|
||||
_isShutdown = true;
|
||||
try {
|
||||
serverSocket.close();
|
||||
for (GenericIhapServerEventHandler<T> channel : _channels) {
|
||||
channel.shutdown();
|
||||
}
|
||||
_channels.clear();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
LogHandler.log(LOGGER, INFO, "Listen port closed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
LogHandler.log(LOGGER, INFO, "removing " + evt.getSource().toString());
|
||||
_channels.remove(evt.getSource());
|
||||
LogHandler.log(LOGGER, INFO, _channels.size() + " remaining open channel(s)");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.itac.mes.datainterface.socket;
|
||||
|
||||
public interface IMesChannelServices {
|
||||
|
||||
public boolean isShutdown();
|
||||
|
||||
public void startup();
|
||||
|
||||
public void shutdown();
|
||||
|
||||
public void setChannelName(String channelName);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author frankp
|
||||
*
|
||||
*/
|
||||
public class AsciiTest {
|
||||
|
||||
@Test
|
||||
public void testNonPrintables() {
|
||||
assertEquals("<0x0>", Ascii.getUserTextForChar((char) 0x00));
|
||||
Ascii.explicitPrintableConstants.add((byte) 0);
|
||||
assertEquals("<NUL>", Ascii.getUserTextForChar((char) 0x00));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.itac.mes.datainterface.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class RequestIdGeneratorTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
RequestIdGenerator.MAX_REQUEST_ID = 100;
|
||||
|
||||
Set<Integer> idSet = new HashSet<Integer>();
|
||||
|
||||
RequestIdGenerator testee = new RequestIdGenerator();
|
||||
for (int i = 0; i < 200; i++) {
|
||||
idSet.add(testee.getNextId());
|
||||
}
|
||||
assertEquals(100, idSet.size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.itac.mes.datainterface.ihap;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author frankp
|
||||
*
|
||||
*/
|
||||
public class InstanceInfoTest {
|
||||
|
||||
@Test
|
||||
public void testNotNull() {
|
||||
InstanceInfo testee = new InstanceInfo();
|
||||
assertNotNull(testee.getInstanceName());
|
||||
assertNotNull(testee.getInstanceState());
|
||||
assertNotNull(testee.getInfoText());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user