catch up with development

Signed-off-by: Ralf Mollik <ramollik@compex-commerce.com>
diff --git a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractEventSource.java b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractEventSource.java
index 93d2349..c8d1e34 100644
--- a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractEventSource.java
+++ b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractEventSource.java
@@ -31,7 +31,7 @@
 	protected boolean ready;
 
 	@Override
-	public void init() {
+	public void init(String host, int port) {
 	}
 
 	@Override
diff --git a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractPeripheralService.java b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractPeripheralService.java
index 6e9930c..516d56a 100644
--- a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractPeripheralService.java
+++ b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractPeripheralService.java
@@ -23,12 +23,14 @@
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -77,7 +79,9 @@
 import jpos.POSPrinter;
 import jpos.POSPrinterConst;
 import jpos.POSPrinterControl114;
+import jpos.Scale;
 import jpos.config.JposEntryRegistry;
+import jpos.config.simple.SimpleEntry;
 import jpos.events.ErrorListener;
 import jpos.events.OutputCompleteEvent;
 import jpos.events.OutputCompleteListener;
@@ -93,8 +97,9 @@
  * PeripheralService is a bridge between javaPOS and the state machine
  * participant.
  */
-public abstract class AbstractPeripheralService extends AbstractStateMachineParticipant	implements IPeripheral, IPeripheral.Command, 
-								StatusUpdateListener, ErrorListener, OutputCompleteListener, ISignatureListener, ActionListener {
+public abstract class AbstractPeripheralService extends AbstractStateMachineParticipant
+		implements IPeripheral, IPeripheral.Command, StatusUpdateListener, ErrorListener, OutputCompleteListener,
+		ISignatureListener, ActionListener {
 	private static final String HTTP = "http";
 
 	private static final String APPLICATION_JSON = "application/json";
@@ -116,6 +121,11 @@
 	/** The windows created. */
 	protected int windowsCreated = 0;
 
+	/** */
+	private boolean paymentTerminalIsOpen = false;
+	private boolean signaturePadIsOpen = false;
+	private boolean printerBitmapIsSet[] = { false, false, false, false, false };
+
 	/** The pt IP. */
 	protected String ptIP;
 
@@ -128,15 +138,15 @@
 	/** is init done correctly? */
 	protected boolean initDone = false;
 	/** The pen data supplied by signature pad. */
-	
+
 	private List<PenData> penData = new ArrayList<>();
-	
+
 	/** The beeper. */
 	protected IBeeper beeper;
-	
+
 	/** The audio. */
 	protected Audio audio;
-	
+
 	/** The video. */
 	protected Video video;
 
@@ -145,26 +155,26 @@
 
 	/** The remote host. */
 	protected String remoteHost;
-	
+
 	/** The remote port. */
 	protected int remotePort = 9090;
-	
+
 	/** The devices status poll. */
 	private Timer statusPoll;
 
 	/** The signature status poll. */
 	private Timer signatureStatusPoll;
-	
+
 	/** The fields of CashDrawerConst. */
 	Field[] cashDrawerFields = CashDrawerConst.class.getDeclaredFields();
-	
+
 	/** The pos printer fields. */
 	Field[] posPrinterFields = POSPrinterConst.class.getDeclaredFields();
-	
+
 	private Map<Integer, String> printerBitmaps = new HashMap<>();
 
-    private String esc = ((char)0x1b)+"";
-	
+	private String esc = ((char) 0x1b) + "";
+
 	@Override
 	public boolean equals(Object obj) {
 		return super.equals(obj);
@@ -191,22 +201,54 @@
 		}
 	}
 
+	private boolean isJavaPosRemote() {
+		if( !"null".equals(remoteHost) && remotePort > 0 ) {
+			String cmd = String.format("http://%s:%d/devices/posParameters", remoteHost, remotePort);
+			HttpGet get = new HttpGet(cmd);
+			get.addHeader("Accept", "application/json");
+			
+			try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+				CloseableHttpResponse response = httpClient.execute(get);
+				LOGGER.info(EntityUtils.toString(response.getEntity()));
+				if(response.getEntity().getContentLength()==0) {
+					return false;
+				}
+				return true;
+			} catch (ParseException | IOException e) {
+				// it's ok - we have no remote javapos
+			} finally {
+				get.releaseConnection();
+			}
+		}
+		return false;
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 
 	 * @see foodmartdialogdslplugin.AbstractStateMachineParticipant#init()
 	 */
-	@Override 
-	public void init() {
-		isRemote = statemachine.isJavaPosRemote();
-		if(!isRemote) {
+	@Override
+	public void init(String pRemoteHost, int pRemotePort) {
+		
+		if( pRemoteHost == null )
+			remoteHost = "null";
+		else
+			remoteHost = pRemoteHost;
+		
+		remotePort = pRemotePort;
+		
+		isRemote = isJavaPosRemote();
+		
+		if (!isRemote) {
 			LOGGER.debug("Library path={}", System.getProperty("java.library.path"));
 			// load all names of configured devices, instantiate and cache it
 			String configFile = ProductConfiguration.getJavaPosConfiguration();
 			if (configFile == null || configFile.length() == 0) {
-				LOGGER.debug("POS setupfile is not registered in product preferences");
+				LOGGER.info("POS setupfile is not registered in product preferences");
 				return;
 			}
+			LOGGER.info("POS setupfile to be used: {}", configFile);
 			try {
 				new URL(configFile);
 				System.setProperty(JposPropertiesConst.JPOS_POPULATOR_FILE_URL_PROP_NAME, configFile);
@@ -229,30 +271,29 @@
 			remotePort = statemachine.getRemotePort();
 			URIBuilder builder = new URIBuilder();
 			builder.setScheme(HTTP).setHost(remoteHost).setPort(remotePort);
-			if(statusPoll == null) {
+			if (statusPoll == null) {
 				statusPoll = new Timer(1000, this);
 				statusPoll.start();
-			} else if(!statusPoll.isRunning()){
+			} else if (!statusPoll.isRunning()) {
 				statusPoll.restart();
 			}
 		}
 	}
 
 	private String doHttpGet(String path) {
-		return doHttpGet(path, null, null, null, null);
+		return doHttpGet(path, null);
 	}
-	
-	private String doHttpGet(String path, String paraName1, String para1, String paraName2, String para2) {
+
+	private String doHttpGet(String path, Map<String, String> params) {
 		String responseString = null;
 		URIBuilder builder = new URIBuilder();
 		builder.setScheme(HTTP).setHost(remoteHost).setPort(remotePort);
 		builder.setPath(path);
 		builder.clearParameters();
-		if(paraName1 != null && para1 != null) {
-			builder.addParameter(paraName1, para1);
-		}
-		if(paraName2 != null && para2 != null) {
-			builder.addParameter(paraName2, para2);
+		if (params != null) {
+			for (String paramKey : params.keySet()) {
+				builder.addParameter(paramKey, params.get(paramKey));
+			}
 		}
 		try {
 			HttpGet get = new HttpGet(builder.build());
@@ -262,7 +303,7 @@
 			responseString = EntityUtils.toString(response.getEntity());
 			get.releaseConnection();
 		} catch (URISyntaxException | ParseException | IOException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("doHttpGet exception: {}", e);
 		}
 		return responseString;
 	}
@@ -270,16 +311,16 @@
 	private void doHttpPut(String path, String paraName1, String para1) {
 		doHttpPut(path, paraName1, para1, null, null);
 	}
-	
+
 	private void doHttpPut(String path, String paraName1, String para1, String paraName2, String para2) {
-		URIBuilder builder = new URIBuilder(); 
+		URIBuilder builder = new URIBuilder();
 		builder.setScheme(HTTP).setHost(remoteHost).setPort(remotePort);
 		builder.setPath(path);
 		builder.clearParameters();
-		if(paraName1 != null && para1 != null) {
+		if (paraName1 != null && para1 != null) {
 			builder.addParameter(paraName1, para1);
 		}
-		if(paraName2 != null && para2 != null) {
+		if (paraName2 != null && para2 != null) {
 			builder.addParameter(paraName2, para2);
 		}
 		try {
@@ -289,18 +330,18 @@
 			httpClient.execute(put);
 			put.releaseConnection();
 		} catch (URISyntaxException | ParseException | IOException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("doHttpPut exception: {}", e);
 		}
 	}
 
 	private void doHttpPost(String path) {
 		doHttpPost(path, null, null);
 	}
-	
+
 	private void doHttpPost(String path, String paraName, String para) {
 		doHttpPost(path, paraName, para, null);
 	}
-	
+
 	private void doHttpPost(String path, String paraName, String para, byte[] image) {
 		URIBuilder builder = new URIBuilder();
 		builder.setScheme(HTTP).setHost(remoteHost).setPort(remotePort);
@@ -308,13 +349,13 @@
 		try {
 			HttpPost post = new HttpPost(builder.build());
 			post.addHeader(ACCEPT, APPLICATION_JSON);
-			if(paraName != null && para != null || image != null) {
+			if (paraName != null && para != null || image != null) {
 				MultipartEntityBuilder mpeBuilder = MultipartEntityBuilder.create();
 				mpeBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
-				if(paraName != null && para != null) {
+				if (paraName != null && para != null) {
 					mpeBuilder.addTextBody(paraName, para);
 				}
-				if(image != null) {
+				if (image != null) {
 					mpeBuilder.addBinaryBody("image", image, ContentType.MULTIPART_FORM_DATA, "");
 				}
 				post.setEntity(mpeBuilder.build());
@@ -323,18 +364,101 @@
 			httpClient.execute(post);
 			post.releaseConnection();
 		} catch (URISyntaxException | ParseException | IOException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("doHttpPost exception {}", e);
 		}
 	}
 	
-	public void releaseDevices() {
-		if(statusPoll != null && statusPoll.isRunning()) {
-			statusPoll.stop();
-		}
-		if(signatureStatusPoll != null && signatureStatusPoll.isRunning()) {
-			signatureStatusPoll.stop();
+	public void initDevice(String deviceName ) {
+		if (isRemote) {
+			
+			HttpPut put = new HttpPut(String.format("http://%s:%d/devices/claim?deviceName=%s", remoteHost, remotePort, deviceName));
+	    	put.addHeader("Accept", "application/json");
+	    	try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+	    		CloseableHttpResponse response = httpClient.execute(put);
+	    		LOGGER.info(EntityUtils.toString(response.getEntity()));
+	    	} catch (IOException e) {
+	    		LOGGER.error("Unable to init device {}\n{}", deviceName, e);
+	    	} finally {
+	    		put.releaseConnection();
+	    	}
+			
+		} else {
+		    BaseControl device = null;
+		    SimpleEntry entry = null;
+	    	entry = (SimpleEntry) props.getJposEntry(deviceName);
+	    	if(entry == null) {
+	    		LOGGER.error("{} is not configured", deviceName);
+	    	} else {
+	    		try {
+	    			device = (BaseControl) Class.forName("jpos." + entry.getProp("deviceCategory").getValueAsString()).getConstructor().newInstance();
+	    			device.open(deviceName);
+	    			device.claim(1000);
+	    			device.setDeviceEnabled(true);
+	    			if ( "POSPrinter".equals(entry.getProp("deviceCategory").getValueAsString() ) ) { 
+		    			((POSPrinter) device).addStatusUpdateListener(this);
+		    			((POSPrinter) device).addErrorListener(this);
+		    			((POSPrinter) device).addOutputCompleteListener(this);
+		    			// Even if using any printer, 0.01mm unit makes it possible to print neatly.
+		    			((POSPrinter) device).setMapMode(POSPrinterConst.PTR_MM_METRIC);
+		    			// Output by the high quality mode
+		    			((POSPrinter) device).setRecLetterQuality(true);
+	    			}
+	    			devices.put(deviceName, device);
+	    			LOGGER.info("device init success: {}", deviceName);
+	    		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
+	    				| NoSuchMethodException | SecurityException | ClassNotFoundException | JposException ex) {
+	    			LOGGER.error("device init error: {}", ex);
+	    			if(ex instanceof JposException && ((JposException)ex).getOrigException()!=null) {
+	    				LOGGER.error(((JposException)ex).getOrigException().getMessage());
+	    			}
+	    			LOGGER.error("check path for dll access:"+ System.getProperty("java.library.path"));
+	    		}
+	    	}
+			
 		}
 	}
+	
+	
+	@Override
+	public void releaseDevices() {
+		if (statusPoll != null && statusPoll.isRunning()) {
+			statusPoll.stop();
+		}
+		if (signatureStatusPoll != null && signatureStatusPoll.isRunning()) {
+			signatureStatusPoll.stop();
+		}
+		if (isRemote) {
+	        HttpPut put;
+	    	put = new HttpPut(String.format("http://%s:%d/devices/release", remoteHost, remotePort));
+	    	put.addHeader("Accept", "application/json");
+	    	try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+	    		CloseableHttpResponse response = httpClient.execute(put);
+	    		LOGGER.info(EntityUtils.toString(response.getEntity()));
+	    	} catch (IOException e) {
+	    		LOGGER.error("{}", e);
+	    	} finally {
+	    		put.releaseConnection();
+	    	}
+		} else {
+			// release all devices that have been initialized
+			for( String d:devices.keySet() ) {
+	    		try {
+	    			devices.get(d).setDeviceEnabled(false);
+	    			SimpleEntry entry = null;
+	    	    	entry = (SimpleEntry) props.getJposEntry(d);
+	    	    	if("POSPrinter".equals(entry.getProp("deviceCategory").getValueAsString() )) {
+	    				((POSPrinter) devices.get(d)).removeStatusUpdateListener(this);
+	    			}
+	    			devices.get(d).release();
+	    			devices.get(d).close();
+	    		} catch (JposException e) {
+	    			LOGGER.error("Error releasing {}", d); 
+	    		}
+			}
+		}
+
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -345,6 +469,214 @@
 		return initDone;
 	}
 
+	public int[] getAllWeights(String deviceName) {
+		int[] weightData = new int[3];
+		if (isRemote) {
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put(DEVICE_NAME, deviceName);
+			String result = doHttpGet("/devices/readAllWeights", params);
+			if( result != null ) {
+				String[] results = result.split(" ");
+				for( int i=0 ; i<(results.length<weightData.length?results.length:weightData.length) ; i++ ) {
+					weightData[i] = Integer.parseInt(results[i]);
+				}
+				LOGGER.debug("readAllWeights: {}, {}, {}", weightData[0], weightData[1], weightData[2]);
+			}
+			return weightData;
+
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return weightData;
+		}
+		try {
+			((Scale) devices.get(deviceName)).readWeight(weightData, 2000);
+		} catch (JposException e) {
+			LOGGER.error("general error readAllWeights for device:{} ex:{}", deviceName, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error readAllWeights for device:{} ex:{}", deviceName, ex);
+		}
+		// net weight in element 0
+		// gross weight in element 1
+		// tare weight in element 2
+		LOGGER.debug("readAllWeights: {}, {}, {}", weightData[0], weightData[1], weightData[2]);
+		return weightData;
+	}
+
+	public Double getReadWeight(String deviceName) {
+		if (isRemote) {
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put(DEVICE_NAME, deviceName);
+			String result = doHttpGet("/devices/readNetWeight", params);
+			if( result != null ) {
+				if( result.contains("status") ) {
+					LOGGER.error("general error readNetWeight for device:{} ex:{}", deviceName, result);
+				} else { 
+					Double result2 = Double.parseDouble(result.replace(",", "."));
+					LOGGER.debug("readNetWeight: {}", result2);
+					return result2;
+				}
+			} 
+			return 0.0;
+
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return 0.0;
+		}
+		int[] weightData = new int[3];
+		try {
+			((Scale) devices.get(deviceName)).readWeight(weightData, 2000);
+		} catch (JposException e) {
+			LOGGER.error("general error readNetWeight for device:{} ex:{}", deviceName, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error readNetWeight for device:{} ex:{}", deviceName, ex);
+		}
+		// net weight in element 0
+		// gross weight in element 1
+		// tare weight in element 2
+		Double result = (1.0*weightData[0]) / 1000.0;
+		LOGGER.debug("readNetWeight: {}", result);
+		return result;
+	}
+
+	public Double getReadTareWeight(String deviceName) {
+		if (isRemote) {
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put(DEVICE_NAME, deviceName);
+			String result = doHttpGet("/devices/readTareWeight", params);
+			if( result != null ) {
+				if( result.contains("status") ) {
+					LOGGER.error("general error getReadTareWeight for device:{} ex:{}", deviceName, result);
+				} else {
+					Double result2 = Double.parseDouble(result.replace(",", "."));
+					LOGGER.debug("readTareWeight: {}", result2);
+					return result2;
+				}
+			}
+			return 0.0;
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return 0.0;
+		}
+		int tareWeight = 0;
+		try {
+			if (((Scale) devices.get(deviceName)).getCapTareWeight()) {
+				tareWeight = ((Scale) devices.get(deviceName)).getTareWeight();
+			}
+		} catch (JposException e) {
+			LOGGER.error("general error readWeight for device:{} ex:{}", deviceName, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error readWeight for device:{} ex:{}", deviceName, ex);
+		}
+		Double result = (1.0*tareWeight) / 1000.0;
+		LOGGER.debug("readTareWeight: {}", result);
+		return result;
+	}
+
+	public String getWeightUnit(String deviceName) {
+		if (isRemote) {
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put(DEVICE_NAME, deviceName);
+			String result = doHttpGet("/devices/weightUnit", params);
+			if( result != null )
+				if( result.contains("status") ) {
+					LOGGER.error("general error getReadTareWeight for device:{} ex:{}", deviceName, result);
+				} else { 
+					LOGGER.debug("getWeightUnit: {}", result);
+					return result;
+				}
+			return null;
+
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return null;
+		}
+		try {
+			String result="";
+			int unitType = ((Scale) devices.get(deviceName)).getWeightUnit();
+			switch (unitType) {
+			case 0:
+				result = "pound 1/8";
+				break;
+			case 1:
+				result = "pound 1/10";
+				break;
+			case 2:
+				result = "pound 1/500";
+				break;
+			case 3:
+				result = "kg";
+				break;
+			case 4:
+				result = "pound";
+				break;
+			case 5:
+				result = "oz";
+				break;
+			}
+			LOGGER.debug("getWeightUnit: {}", result);
+			return result;
+		} catch (JposException e) {
+			LOGGER.error("general error readWeight for device:{} ex:{}", deviceName, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error readWeight for device:{} ex:{}", deviceName, ex);
+		}
+		return null;
+	}
+
+	public void setScaleDisplayText(String deviceName, String displayText) {
+		if (isRemote) {
+			doHttpPut("/devices/scaleDisplayText", DEVICE_NAME, deviceName, "displayText", displayText);
+			return;
+
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return;
+		}
+		try {
+			if (((Scale) devices.get(deviceName)).getCapDisplayText()) {
+				((Scale) devices.get(deviceName)).displayText(displayText);
+			}
+		} catch (JposException e) {
+			LOGGER.error("general error scaleDisplayText for device:{} text:{} ex:{}", deviceName, displayText, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error scaleDisplayText for device:{} text:{} ex:{}", deviceName, displayText, ex);
+		}
+	}
+
+	public void setTareWeight(String deviceName, String tareWeightInGramms) {
+		if(null == tareWeightInGramms)
+			tareWeightInGramms = "0";
+		if (isRemote) {
+			doHttpPut("/devices/tareWeight", DEVICE_NAME, deviceName, "tareWeight", tareWeightInGramms);
+			return;
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return;
+		}
+		try {
+			if (((Scale) devices.get(deviceName)).getCapTareWeight()) {
+				((Scale) devices.get(deviceName)).setTareWeight(Integer.parseInt(tareWeightInGramms));
+			}
+		} catch (JposException e) {
+			LOGGER.error("general error tareWeight for device:{} text:{} ex:{}", deviceName, tareWeightInGramms, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error tareWeight for device:{} text:{} ex:{}", deviceName, tareWeightInGramms, ex);
+		}
+	}
+
+	public void setZeroScale(String deviceName, String dummy) {
+		if (isRemote) {
+			doHttpPost("/devices/zeroScale", DEVICE_NAME, deviceName);
+			return;
+
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return;
+		}
+		try {
+			if (((Scale) devices.get(deviceName)).getCapZeroScale()) {
+				((Scale) devices.get(deviceName)).zeroScale();
+			}
+		} catch (JposException e) {
+			LOGGER.error("general error zeroScale for device:{} ex:{}", deviceName, e);
+		} catch (Exception ex) {
+			LOGGER.error("general error zeroScale for device:{} ex:{}", deviceName, ex);
+		}
+	}
+
 	// line display code
 	/**
 	 * Sets the display line.
@@ -355,10 +687,13 @@
 	 *            the new display line
 	 */
 	public void setDisplayLine(String deviceName, String displayLine) {
-		if(isRemote) {
+		if( null == displayLine ) {
+			displayLine="";
+		}
+		if (isRemote) {
 			doHttpPut("/devices/displayLine", DEVICE_NAME, deviceName, "displayLine", displayLine);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -385,23 +720,24 @@
 	public void setPrinterBitmap(String registerId, String registerBitmapId) {
 		int imgWidth = 200;
 		int imgHeight = 80;
-		if(isRemote) {
-			doHttpPut("/devices/uploadedBitmaps", "uploadedBitmaps", Boolean.toString(ProductConfiguration.hasJavaPosUploadedBitmaps()));
+		if (isRemote) {
+			doHttpPut("/devices/uploadedBitmaps", "uploadedBitmaps",
+					Boolean.toString(ProductConfiguration.hasJavaPosUploadedBitmaps()));
 			byte[] img = statemachine.getBlobService().getByteArrayImage(registerBitmapId, 0);
 			doHttpPost("/devices/printerBitmap", "registerId", registerId, img);
 			return;
 		} else if (!initDone) {
 			return;
 		}
-    	// load the image
+		// load the image
 		BufferedImage img = statemachine.getBlobService().getBufferedImage(registerBitmapId, 0);
 		// convert it to black/white
-        BufferedImage blackWhite = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_BYTE_BINARY);
-        Graphics2D g2d = blackWhite.createGraphics();
-        g2d.drawImage(img, 0, 0, imgWidth, imgHeight, 0, 0, img.getWidth(), img.getHeight(), null);
-        g2d.dispose();
-		
-        // write file in temp dir
+		BufferedImage blackWhite = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_BYTE_BINARY);
+		Graphics2D g2d = blackWhite.createGraphics();
+		g2d.drawImage(img, 0, 0, imgWidth, imgHeight, 0, 0, img.getWidth(), img.getHeight(), null);
+		g2d.dispose();
+
+		// write file in temp dir
 		File tempFile = null;
 		try {
 			tempFile = File.createTempFile("printerBitmap", ".bmp");
@@ -410,24 +746,28 @@
 			LOGGER.error("{}", ioex);
 			return;
 		}
-		
-		for(BaseControl device:devices.values()) {
-			String deviceName = ""; 
+
+		for (BaseControl device : devices.values()) {
+			String deviceName = "";
 			try {
 				int bitmapIndex = Integer.parseInt(registerId);
 				String path = tempFile.getPath();
 				deviceName = device.getPhysicalDeviceName();
-				if(device instanceof POSPrinter && ((POSPrinterControl114) device).getCapRecBitmap()) {
-					if(ProductConfiguration.hasJavaPosUploadedBitmaps()) {
-						((POSPrinterControl114) device).setBitmap(bitmapIndex,POSPrinterConst.PTR_S_RECEIPT, path, (((POSPrinterControl114) device).getRecLineWidth()/2), POSPrinterConst.PTR_BM_CENTER);
+				if (device instanceof POSPrinter && ((POSPrinterControl114) device).getCapRecBitmap()) {
+					if (ProductConfiguration.hasJavaPosUploadedBitmaps()) {
+						((POSPrinterControl114) device).setBitmap(bitmapIndex, POSPrinterConst.PTR_S_RECEIPT, path,
+								(((POSPrinterControl114) device).getRecLineWidth() / 2), POSPrinterConst.PTR_BM_CENTER);
 					} else {
 						printerBitmaps.put(bitmapIndex, path);
 					}
+					printerBitmapIsSet[bitmapIndex] = true;
 				}
 			} catch (JposException jex) {
-				LOGGER.error("jpos error setRegisterBitmap for device:{} and:{} ex:{}", deviceName, registerBitmapId, jex);
+				LOGGER.error("jpos error setRegisterBitmap for device:{} and:{} ex:{}", deviceName, registerBitmapId,
+						jex);
 			} catch (Exception ex) {
-				LOGGER.error("general error registerBitmap for device:{} text:{} ex:{}", deviceName, registerBitmapId,ex);
+				LOGGER.error("general error registerBitmap for device:{} text:{} ex:{}", deviceName, registerBitmapId,
+						ex);
 			}
 		}
 	}
@@ -441,10 +781,11 @@
 	 *            the new device brightness
 	 */
 	public void setDeviceBrightness(String deviceName, Integer deviceBrightness) {
-		if(isRemote) {
-			doHttpPut("/devices/deviceBrightness", DEVICE_NAME, deviceName, "deviceBrightness", deviceBrightness.toString());
+		if (isRemote) {
+			doHttpPut("/devices/deviceBrightness", DEVICE_NAME, deviceName, "deviceBrightness",
+					deviceBrightness.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -464,10 +805,10 @@
 	 *            the new blink rate
 	 */
 	public void setBlinkRate(String deviceName, Integer blinkRate) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/blinkRate", DEVICE_NAME, deviceName, "blinkRate", blinkRate.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -487,10 +828,10 @@
 	 *            see: LineDisplayConst
 	 */
 	public void setCursorType(String deviceName, Integer cursorType) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/cursorType", DEVICE_NAME, deviceName, "cursorType", cursorType.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -510,10 +851,10 @@
 	 *            the new marquee format
 	 */
 	public void setMarqueeFormat(String deviceName, Integer marqueeFormat) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/marqueeFormat", DEVICE_NAME, deviceName, "marqueeFormat", marqueeFormat.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -533,10 +874,11 @@
 	 *            the new marquee repeat wait
 	 */
 	public void setMarqueeRepeatWait(String deviceName, Integer marqueeRepeatWait) {
-		if(isRemote) {
-			doHttpPut("/devices/marqueeRepeatWait", DEVICE_NAME, deviceName, "marqueeRepeatWait", marqueeRepeatWait.toString());
+		if (isRemote) {
+			doHttpPut("/devices/marqueeRepeatWait", DEVICE_NAME, deviceName, "marqueeRepeatWait",
+					marqueeRepeatWait.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -556,10 +898,10 @@
 	 *            the new marquee type
 	 */
 	public void setMarqueeType(String deviceName, Integer marqueeType) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/marqueeType", DEVICE_NAME, deviceName, "marqueeType", marqueeType.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -579,10 +921,11 @@
 	 *            the new marquee unit wait
 	 */
 	public void setMarqueeUnitWait(String deviceName, Integer marqueeUnitWait) {
-		if(isRemote) {
-			doHttpPut("/devices/marqueeUnitWait", DEVICE_NAME, deviceName, "marqueeUnitWait", marqueeUnitWait.toString());
+		if (isRemote) {
+			doHttpPut("/devices/marqueeUnitWait", DEVICE_NAME, deviceName, "marqueeUnitWait",
+					marqueeUnitWait.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -603,10 +946,10 @@
 	 *            the new creates the window
 	 */
 	public void setCreateWindow(String deviceName, String createWindow) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/createWindow", DEVICE_NAME, deviceName, "createWindow", createWindow);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -632,10 +975,10 @@
 	 *            the new destroy window
 	 */
 	public void setDestroyWindow(String deviceName, String destroyWindow) { // NOSONAR
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/destroyWindow", DEVICE_NAME, deviceName, "destroyWindow", destroyWindow);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -658,10 +1001,10 @@
 	 *            encodes a pipe separated tuple: direction, units
 	 */
 	public void setScroll(String deviceName, String scroll) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/scroll", DEVICE_NAME, deviceName, "scroll", scroll);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -685,10 +1028,11 @@
 	 *            the new inter character wait
 	 */
 	public void setInterCharacterWait(String deviceName, Integer interCharacterWait) {
-		if(isRemote) {
-			doHttpPut("/devices/interCharacterWait", DEVICE_NAME, deviceName, "interCharacterWait", interCharacterWait.toString());
+		if (isRemote) {
+			doHttpPut("/devices/interCharacterWait", DEVICE_NAME, deviceName, "interCharacterWait",
+					interCharacterWait.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -709,10 +1053,10 @@
 	 *            attribute
 	 */
 	public void setDisplayTextAt(String deviceName, String displayTextAt) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/displayTextAt", DEVICE_NAME, deviceName, "displayTextAt", displayTextAt);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -741,10 +1085,10 @@
 	 *            is nt used
 	 */
 	public void setClearDisplay(String deviceName, String clearDisplay) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/clearDisplay", DEVICE_NAME, deviceName, "clearDisplay", clearDisplay);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -768,10 +1112,10 @@
 	 *            is ignored
 	 */
 	public void setOpenDrawer(String deviceName, Integer openDrawer) { // NOSONAR
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/openDrawer", DEVICE_NAME, deviceName, "openDrawer", openDrawer.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -791,10 +1135,10 @@
 	 *            text to print
 	 */
 	public void setPrintNormal(String deviceName, String printNormal) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/printNormal", DEVICE_NAME, deviceName, "printNormal", printNormal);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -806,6 +1150,53 @@
 	}
 
 	/**
+	 * start transactional printing
+	 * 
+	 * @param deviceName
+	 *            the device name
+	 */
+	public void setStartTransactionPrint(String deviceName) {
+
+		if (isRemote) {
+			return;
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return;
+		}
+
+		try {
+			POSPrinterControl114 device = (POSPrinterControl114) devices.get(deviceName);
+			if (device.getCapTransaction())
+				device.transactionPrint(POSPrinterConst.PTR_S_RECEIPT, POSPrinterConst.PTR_TP_TRANSACTION);
+		} catch (Exception e) {
+			LOGGER.error("jpos error printCut for device:" + deviceName + " {}", e);
+		}
+	}
+
+	/**
+	 * end transactional printing
+	 * 
+	 * @param deviceName
+	 *            the device name
+	 */
+	public void setEndTransactionPrint(String deviceName) {
+
+		if (isRemote) {
+			return;
+		} else if (!initDone || !devices.containsKey(deviceName)) {
+			return;
+		}
+
+		try {
+			POSPrinterControl114 device = (POSPrinterControl114) devices.get(deviceName);
+			if (device.getCapTransaction())
+				device.transactionPrint(POSPrinterConst.PTR_S_RECEIPT, POSPrinterConst.PTR_TP_NORMAL);
+		} catch (Exception e) {
+			LOGGER.error("jpos error printCut for device:" + deviceName + " {}", e);
+		}
+
+	}
+
+	/**
 	 * prints footer, feeds paper and cuts.
 	 *
 	 * @param deviceName
@@ -814,24 +1205,40 @@
 	 *            the text to print as footer
 	 */
 	public void setPrintCut(String deviceName, String footer) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/printCut", DEVICE_NAME, deviceName, "printCut", footer);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
+		POSPrinterControl114 device = (POSPrinterControl114) devices.get(deviceName);
+
 		try {
 			if (!footer.isEmpty()) {
-				((POSPrinterControl114) devices.get(deviceName)).printNormal(POSPrinterConst.PTR_S_RECEIPT, footer);
+				device.printNormal(POSPrinterConst.PTR_S_RECEIPT, footer);
 			}
-			if (((POSPrinterControl114) devices.get(deviceName)).getCapRecPapercut()) {
-				int linesToPaperCut = ((POSPrinterControl114) devices.get(deviceName)).getRecLinesToPaperCut();
-				((POSPrinterControl114) devices.get(deviceName)).printNormal(POSPrinterConst.PTR_S_RECEIPT, esc + "d" + ((char)(linesToPaperCut+1)));
-				((POSPrinterControl114) devices.get(deviceName)).printNormal(POSPrinterConst.PTR_S_RECEIPT, esc + "i");
+			if (device.getCapRecPapercut()) {
+				linefeedToPapercut(device);
 			}
+			device.cutPaper(99);
+		} catch (JposException eAll) {
+			LOGGER.error("jpos error printCut for device:" + deviceName + " {}", eAll);
+			try {
+				device.printNormal(POSPrinterConst.PTR_S_RECEIPT, esc + "i");
+			} catch (JposException e) {
+				LOGGER.error("retry jpos error printCut for device:" + deviceName + " {}", e);
+			}
+		}
+	}
+
+	private void linefeedToPapercut(POSPrinterControl114 device) throws JposException {
+		int linesToPaperCut = device.getRecLinesToPaperCut() + 1;
+		try {
+			device.printNormal(POSPrinterConst.PTR_S_RECEIPT, esc + "|" + linesToPaperCut + "lF");	// linefeed variant 1
 		} catch (JposException e) {
-			LOGGER.error("jpos error printCut for device:" + deviceName + " {}", e);
+			LOGGER.debug("jpos error linefeedToPapercut - retry variant 2");
+			device.printNormal(POSPrinterConst.PTR_S_RECEIPT, esc + "d" + ((char) (linesToPaperCut))); // linefeed variant 2
 		}
 	}
 
@@ -844,23 +1251,28 @@
 	 *            the bitmap-id to print
 	 */
 	public void setPrintBitmap(String deviceName, Integer printBitmap) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/printBitmap", DEVICE_NAME, deviceName, "printBitmap", printBitmap.toString());
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
 		try {
-			if (((POSPrinterControl114) devices.get(deviceName)).getCapRecBitmap() && printerBitmaps.containsKey(printBitmap)) {
-				if(ProductConfiguration.hasJavaPosUploadedBitmaps()) {
-					((POSPrinterControl114) devices.get(deviceName)).printNormal(POSPrinterConst.PTR_S_RECEIPT, esc+"|"+printBitmap.toString()+"B");
+			if (((POSPrinterControl114) devices.get(deviceName)).getCapRecBitmap()
+					&& printerBitmaps.containsKey(printBitmap)) {
+				if (ProductConfiguration.hasJavaPosUploadedBitmaps()) {
+					((POSPrinterControl114) devices.get(deviceName)).printNormal(POSPrinterConst.PTR_S_RECEIPT,
+							esc + "|" + printBitmap.toString() + "B");
 				} else {
-					((POSPrinterControl114) devices.get(deviceName)).printBitmap(POSPrinterConst.PTR_S_RECEIPT, printerBitmaps.get(printBitmap), POSPrinterConst.PTR_BM_ASIS, POSPrinterConst.PTR_BM_CENTER);
+					((POSPrinterControl114) devices.get(deviceName)).printBitmap(POSPrinterConst.PTR_S_RECEIPT,
+							printerBitmaps.get(printBitmap), POSPrinterConst.PTR_BM_ASIS,
+							POSPrinterConst.PTR_BM_CENTER);
 				}
 			}
 		} catch (JposException e) {
 			LOGGER.error("jpos error setPrintBitmap for device:" + deviceName + " and:" + printBitmap + " {}", e);
+			printerBitmapIsSet[printBitmap] = false;
 		}
 	}
 
@@ -874,10 +1286,10 @@
 	 *            jpos.POSPrinterConst
 	 */
 	public void setPrintBarcode(String deviceName, String data) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/devices/printBarcode", DEVICE_NAME, deviceName, "printBarcode", data);
 			return;
-			
+
 		} else if (!initDone || !devices.containsKey(deviceName)) {
 			return;
 		}
@@ -886,12 +1298,13 @@
 			String value = parts[0];
 			int code = Integer.parseInt(parts[1].trim());
 			int height = 0;
-			if(parts.length > 2) {
+			if (parts.length > 2) {
 				height = Integer.parseInt(parts[2].trim());
 			}
-			if (((POSPrinterControl114) devices.get(deviceName)).getCapRecBarCode()) {
-				((POSPrinterControl114) devices.get(deviceName)).printBarCode(POSPrinterConst.PTR_S_RECEIPT, value,
-						code, height, ((POSPrinterControl114) devices.get(deviceName)).getRecLineWidth(), POSPrinterConst.PTR_BC_CENTER, POSPrinterConst.PTR_BC_TEXT_BELOW);
+			POSPrinterControl114 device = (POSPrinterControl114) devices.get(deviceName);
+			if (device.getCapRecBarCode()) {
+				device.printBarCode(POSPrinterConst.PTR_S_RECEIPT, value, code, height, device.getRecLineWidth()-1,
+						POSPrinterConst.PTR_BC_CENTER, POSPrinterConst.PTR_BC_TEXT_BELOW);
 			}
 		} catch (JposException e) {
 			LOGGER.error("jpos error setPrintBarcode for device:" + deviceName + " and:" + data + " {}", e);
@@ -905,8 +1318,9 @@
 	 *            the new slip notifications enabled
 	 */
 	public void setSlipNotificationsEnabled(boolean slipNotificationsEnabled) {
-		if(isRemote) {
-			doHttpPut("/devices/slipNotificationsEnabled", "slipNotificationsEnabled", Boolean.toString(slipNotificationsEnabled));
+		if (isRemote) {
+			doHttpPut("/devices/slipNotificationsEnabled", "slipNotificationsEnabled",
+					Boolean.toString(slipNotificationsEnabled));
 		} else {
 			this.slipNotificationsEnabled = slipNotificationsEnabled;
 		}
@@ -918,14 +1332,13 @@
 	 * @return true, if is slip notifications enabled
 	 */
 	public boolean isSlipNotificationsEnabled() {
-		if(isRemote) {
+		if (isRemote) {
 			return Boolean.getBoolean(doHttpGet("/devices/isSlipNotificationsEnabled"));
 		} else {
 			return slipNotificationsEnabled;
 		}
 	}
 
-	
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -935,10 +1348,10 @@
 	@Override
 	public void statusUpdateOccurred(StatusUpdateEvent e) { // NOSONAR
 		Object source = e.getSource();
-		if(source instanceof POSPrinterService14) {
+		if (source instanceof POSPrinterService14) {
 			try {
-				String serviceDescription = ((POSPrinterService14)source).getPhysicalDeviceDescription();
-				if(serviceDescription.contains("Cash Drawer")) {
+				String serviceDescription = ((POSPrinterService14) source).getPhysicalDeviceDescription();
+				if (serviceDescription.contains("Cash Drawer")) {
 					decodeCashDrawerStatus(e.getStatus());
 				} else {
 					decodePOSPrinterStatus(e.getStatus());
@@ -969,8 +1382,7 @@
 				break;
 			case POSPrinterConst.PTR_SUE_REC_PAPEROK:
 				statemachine.processEvent(statemachine, new MessageEvent(EventType.MESSAGECLOSE, "receiptEmpty"));
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSCLOSE, "receiptNearEmpty"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSCLOSE, "receiptNearEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_REC_NEAREMPTY:
 				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSOPEN, "receiptNearEmpty"));
@@ -996,8 +1408,7 @@
 				break;
 			case POSPrinterConst.PTR_SUE_JRN_PAPEROK:
 				statemachine.processEvent(statemachine, new MessageEvent(EventType.MESSAGECLOSE, "journalEmpty"));
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSCLOSE, "journalNearEmpty"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSCLOSE, "journalNearEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_JRN_NEAREMPTY:
 				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSOPEN, "journalNearEmpty"));
@@ -1011,20 +1422,17 @@
 						new MessageEvent(EventType.STATUSOPEN, "receiptCartridgeNearEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_REC_HEAD_CLEANING:
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSOPEN, "receiptHeadCleaning"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSOPEN, "receiptHeadCleaning"));
 				break;
 			case POSPrinterConst.PTR_SUE_REC_CARTDRIGE_OK:
 				statemachine.processEvent(statemachine,
 						new MessageEvent(EventType.MESSAGECLOSE, "receiptCartridgeEmpty"));
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSCLOSE, "receiptHeadCleaning"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSCLOSE, "receiptHeadCleaning"));
 				statemachine.processEvent(statemachine,
 						new MessageEvent(EventType.STATUSCLOSE, "receiptCartridgeNearEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_SLP_CARTRIDGE_EMPTY:
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.MESSAGEOPEN, "slipCartridgeEmpty"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.MESSAGEOPEN, "slipCartridgeEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_SLP_CARTRIDGE_NEAREMPTY:
 				statemachine.processEvent(statemachine,
@@ -1034,10 +1442,8 @@
 				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSOPEN, "slipHeadCleaning"));
 				break;
 			case POSPrinterConst.PTR_SUE_SLP_CARTDRIGE_OK:
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.MESSAGECLOSE, "slipCartridgeEmpty"));
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSCLOSE, "slipHeadCleaning"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.MESSAGECLOSE, "slipCartridgeEmpty"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSCLOSE, "slipHeadCleaning"));
 				statemachine.processEvent(statemachine,
 						new MessageEvent(EventType.STATUSCLOSE, "slipCartridgeNearEmpty"));
 				break;
@@ -1050,14 +1456,12 @@
 						new MessageEvent(EventType.STATUSOPEN, "journalCartridgeNearEmpty"));
 				break;
 			case POSPrinterConst.PTR_SUE_JRN_HEAD_CLEANING:
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSOPEN, "journalHeadCleaning"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSOPEN, "journalHeadCleaning"));
 				break;
 			case POSPrinterConst.PTR_SUE_JRN_CARTDRIGE_OK:
 				statemachine.processEvent(statemachine,
 						new MessageEvent(EventType.MESSAGECLOSE, "journalCartridgeEmpty"));
-				statemachine.processEvent(statemachine,
-						new MessageEvent(EventType.STATUSCLOSE, "journalHeadCleaning"));
+				statemachine.processEvent(statemachine, new MessageEvent(EventType.STATUSCLOSE, "journalHeadCleaning"));
 				statemachine.processEvent(statemachine,
 						new MessageEvent(EventType.STATUSCLOSE, "journalCartridgeNearEmpty"));
 				break;
@@ -1180,7 +1584,10 @@
 	 *            the new ptip
 	 */
 	public void setPTIP(String ptIP) {
-		this.ptIP = ptIP;
+		if ("null".equals(ptIP))
+			this.ptIP = "";
+		else
+			this.ptIP = ptIP;
 	}
 
 	/**
@@ -1213,10 +1620,14 @@
 		setPTIP(parts[0]);
 		setPTPort(Integer.parseInt(parts[1]));
 
-		if (POSServiceBinder.getPosService() != null
-				&& !POSServiceBinder.getPosService().openZVTChannel(getPTIP(), getPTPort())) {
-			LOGGER.error("could not open ZVT socket");
+		if (POSServiceBinder.getPosService() != null && !getPTIP().isEmpty() && getPTPort() > 0
+				&& POSServiceBinder.getPosService().openZVTChannel(getPTIP(), getPTPort())) {
+			paymentTerminalIsOpen = true;
+			return;
+
 		}
+		paymentTerminalIsOpen = false;
+		LOGGER.error("could not open ZVT socket at '{}:{}'", getPTIP(), getPTPort());
 	}
 
 	/**
@@ -1226,7 +1637,7 @@
 	 *            the new close payment terminal
 	 */
 	public void setClosePaymentTerminal(String close) { // NOSONAR
-		if (POSServiceBinder.getPosService() != null) {
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
 			POSServiceBinder.getPosService().closeZVTChannel();
 		}
 	}
@@ -1238,7 +1649,7 @@
 	 *            the new payment terminal acknowledge
 	 */
 	public void setPaymentTerminalAcknowledge(String dummey) { // NOSONAR
-		if (POSServiceBinder.getPosService() != null) {
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
 			POSServiceBinder.getPosService().zvtAcknowledge();
 		}
 	}
@@ -1250,10 +1661,8 @@
 	 *            the new payment terminal balance request
 	 */
 	public void setPaymentTerminalBalanceRequest(String request) { // NOSONAR
-		if (POSServiceBinder.getPosService() != null) {
-			/**
-			 * zvt.balanceRequest(); 
-			 */
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
+			// zvt.balanceRequest();
 		}
 	}
 
@@ -1264,10 +1673,10 @@
 	 *            the new payment terminal prepaid top up
 	 */
 	public void setPaymentTerminalPrepaidTopUp(Double amount) { // NOSONAR
-		if (POSServiceBinder.getPosService() != null) {
-		/**
-		 * zvt.prepaidTopUp(amount);
-		 */
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
+			/**
+			 * zvt.prepaidTopUp(amount);
+			 */
 		}
 	}
 
@@ -1278,9 +1687,11 @@
 	 *            the new payment terminal reversal
 	 */
 	public void setPaymentTerminalReversal(String reversal) {
-		String[] parts = reversal.split("\\|");
-		if (POSServiceBinder.getPosService() != null) {
-			POSServiceBinder.getPosService().zvtReversal(parts[0], parts[1]);
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
+			String[] parts = reversal.split("\\|");
+			if (POSServiceBinder.getPosService() != null) {
+				POSServiceBinder.getPosService().zvtReversal(parts[0], parts[1]);
+			}
 		}
 	}
 
@@ -1291,9 +1702,11 @@
 	 *            the new payment terminal registration
 	 */
 	public void setPaymentTerminalRegistration(String registration) {
-		String[] parts = registration.split("\\|");
-		if (POSServiceBinder.getPosService() != null) {
-			POSServiceBinder.getPosService().zvtRegistration(parts[0], parts[1]);
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
+			String[] parts = registration.split("\\|");
+			if (POSServiceBinder.getPosService() != null) {
+				POSServiceBinder.getPosService().zvtRegistration(parts[0], parts[1]);
+			}
 		}
 	}
 
@@ -1304,7 +1717,7 @@
 	 *            the new payment terminal authorization
 	 */
 	public void setPaymentTerminalAuthorization(Double amount) {
-		if (POSServiceBinder.getPosService() != null) {
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
 			POSServiceBinder.getPosService().zvtAuthorization(amount);
 		}
 	}
@@ -1315,7 +1728,7 @@
 	 * @return the payment terminal response
 	 */
 	public String getPaymentTerminalResponse() {
-		if (POSServiceBinder.getPosService() != null) {
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
 			return POSServiceBinder.getPosService().getZvtResponse();
 		}
 		return null;
@@ -1327,7 +1740,7 @@
 	 * @return the payment terminal transaction
 	 */
 	public IZVTTransactionData getPaymentTerminalTransaction() {
-		if (POSServiceBinder.getPosService() != null) {
+		if (POSServiceBinder.getPosService() != null && paymentTerminalIsOpen) {
 			return POSServiceBinder.getPosService().getZvtTransactionData();
 		}
 		return null;
@@ -1362,115 +1775,126 @@
 			}
 		}
 		if (statemachine.getReportProvider() != null) {
-			statemachine.getReportProvider().printReportAsPdf(reportName, statemachine.getEclipseContext(), filterMap, printService);
-		}
-	}
-	
-	public void setSignatureOpen(String dummy) {	// NOSONAR
-		if(isRemote) {
-			doHttpPost("/signature/openTablet");
-			if(signatureStatusPoll == null) {
-				signatureStatusPoll = new Timer(1000, this);
-				signatureStatusPoll.start();
-			} else if(!statusPoll.isRunning()){
-				signatureStatusPoll.restart();
-			}
-		} else if(POSServiceBinder.getSignatureService() != null && POSServiceBinder.getSignatureService().openTablet(statemachine.getBlobService())) {
-			statemachine.schedule(statemachine, 500, new MessageEvent(EventType.TRIGGER, "onSignaturePadOpen"));
+			statemachine.getReportProvider().printReportAsPdf(reportName, statemachine.getEclipseContext(), filterMap,
+					printService);
 		}
 	}
 
-	public void setSignatureCapture(String dummy) {	// NOSONAR
-		if(isRemote) {
+	public void setSignatureOpen(String dummy) { // NOSONAR
+		if (isRemote) {
+			doHttpPost("/signature/openTablet");
+			if (signatureStatusPoll == null) {
+				signatureStatusPoll = new Timer(1000, this);
+				signatureStatusPoll.start();
+			} else if (!statusPoll.isRunning()) {
+				signatureStatusPoll.restart();
+			}
+		} else if (POSServiceBinder.getSignatureService() != null) {
+			try {
+				if (POSServiceBinder.getSignatureService().openTablet(statemachine.getBlobService())) {
+					statemachine.schedule(statemachine, 500, new MessageEvent(EventType.TRIGGER, "onSignaturePadOpen"));
+					signaturePadIsOpen = true;
+					return;
+				}
+			} catch (Exception e) {
+				LOGGER.error("Initialization of signature pad failed - continue without signature pad");
+			}
+			signaturePadIsOpen = false;
+		}
+	}
+
+	public void setSignatureCapture(String dummy) { // NOSONAR
+		if (isRemote) {
 			doHttpPost("/signature/captureTablet");
-		} else if(POSServiceBinder.getSignatureService() != null) {
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
 			POSServiceBinder.getSignatureService().captureTablet();
 			POSServiceBinder.getSignatureService().addListener(this);
 		}
 	}
-	
-	public void setSignatureIdle(String dummy) {	// NOSONAR
-		if(isRemote) {
+
+	public void setSignatureIdle(String dummy) { // NOSONAR
+		if (isRemote) {
 			doHttpPost("/signature/idleTablet");
-		} else if(POSServiceBinder.getSignatureService() != null) {			
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
 			POSServiceBinder.getSignatureService().removeListener(this);
 			POSServiceBinder.getSignatureService().idleTablet();
 		}
 	}
-	
+
 	public void setSignatureCaptureImage(String imageId) {
-		if(isRemote) {
+		if (isRemote) {
 			byte[] img = statemachine.getBlobService().getByteArrayImage(imageId, 0);
 			doHttpPost("/signature/captureImage", null, null, img);
-		} else if(POSServiceBinder.getSignatureService() != null) {			
-			POSServiceBinder.getSignatureService().setCaptureImage(imageId); 
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
+			POSServiceBinder.getSignatureService().setCaptureImage(imageId);
 		}
 	}
-	
+
 	public void setSignatureAddSlide(String slideId) {
-		if(isRemote) {
+		if (isRemote) {
 			byte[] img = statemachine.getBlobService().getByteArrayImage(slideId, 0);
 			doHttpPost("/signature/addSlide", null, null, img);
-		} else if(POSServiceBinder.getSignatureService() != null) {			
-			POSServiceBinder.getSignatureService().addSlideTablet(slideId); 
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
+			POSServiceBinder.getSignatureService().addSlideTablet(slideId);
 		}
 	}
-	
+
 	public void setSignatureSlideDelay(Integer delay) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/signature/slideDelay", "delay", delay.toString());
-		} else if(POSServiceBinder.getSignatureService() != null) {			
-			POSServiceBinder.getSignatureService().setSlideDelay(delay); 
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
+			POSServiceBinder.getSignatureService().setSlideDelay(delay);
 		}
 	}
-	
-	public void setSignatureClose(String dummy) {	// NOSONAR
-		if(isRemote) {
+
+	public void setSignatureClose(String dummy) { // NOSONAR
+		if (isRemote) {
 			doHttpPost("closeTablet");
-			if(signatureStatusPoll != null && signatureStatusPoll.isRunning()) {
+			if (signatureStatusPoll != null && signatureStatusPoll.isRunning()) {
 				signatureStatusPoll.stop();
 			}
-		} else if(POSServiceBinder.getSignatureService() != null) {
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
 			POSServiceBinder.getSignatureService().removeListener(this);
 			POSServiceBinder.getSignatureService().closeTablet();
 		}
 	}
 
 	public void setSignatureLabel(String labels) {
-		if(isRemote) {
+		if (isRemote) {
 			doHttpPut("/signature/addLabels", "labels", labels);
-		} else if(POSServiceBinder.getSignatureService() != null) {			
+		} else if (POSServiceBinder.getSignatureService() != null && signaturePadIsOpen) {
 			POSServiceBinder.getSignatureService().setTabletLabel(labels);
 		}
 	}
-	
+
 	@Override
 	public void notifyFinished(ISignatureEvent event) {
-		if(event.getButtonId() == 1) {
+		if (event.getButtonId() == 1) {
 			penData.clear();
 			penData.addAll(event.getPenData());
 			POSServiceBinder.getSignatureService().removeListener(this);
 			statemachine.processEvent(statemachine, new MessageEvent(EventType.TRIGGER, "onSignatureOk"));
 			POSServiceBinder.getSignatureService().idleTablet();
 		}
-		if(event.getButtonId() == 2 && POSServiceBinder.getSignatureService() != null) {
+		if (event.getButtonId() == 2 && POSServiceBinder.getSignatureService() != null) {
 			POSServiceBinder.getSignatureService().clearTablet();
 		}
-		if(event.getButtonId() == 3) {
+		if (event.getButtonId() == 3) {
 			penData.clear();
 			POSServiceBinder.getSignatureService().removeListener(this);
 			statemachine.processEvent(statemachine, new MessageEvent(EventType.TRIGGER, "onSignatureCancel"));
 			POSServiceBinder.getSignatureService().idleTablet();
 		}
-		
+
 	}
-	
+
 	public List<PenData> getPenData() {
-		if(isRemote) {
-			String jsonString =  doHttpGet("/signature/penData");
+		if (isRemote) {
+			String jsonString = doHttpGet("/signature/penData");
 			ObjectMapper mapper = new ObjectMapper();
 			try {
-				penData = mapper.readValue(jsonString, CollectionType.construct(List.class, SimpleType.construct(PenData.class)));
+				penData = mapper.readValue(jsonString,
+						CollectionType.construct(List.class, SimpleType.construct(PenData.class)));
 			} catch (IOException e) {
 				LOGGER.error("{}", e);
 			}
@@ -1479,53 +1903,59 @@
 	}
 
 	public String getSignatureBlob() {
-		if(isRemote) {
-			String base64String =  doHttpGet("/signature/signature", "width", Integer.toString(statemachine.getSceenWidth()), "height", Integer.toString(statemachine.getScreenHeight()));
-			if(base64String != null) {
+		if (isRemote) {
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put("width", Integer.toString(statemachine.getSceenWidth()));
+			params.put("height", Integer.toString(statemachine.getScreenHeight()));
+			String base64String = doHttpGet("/signature/signature", params);
+			if (base64String != null) {
 				byte[] bytes = Base64.decodeBase64(base64String.getBytes());
-				return statemachine.getBlobService().createBlobMapping(new ByteArrayInputStream(bytes), "", "image/jpeg");
+				return statemachine.getBlobService().createBlobMapping(new ByteArrayInputStream(bytes), "",
+						"image/jpeg");
 			}
-		} else if(POSServiceBinder.getSignatureService() != null) {
-			return POSServiceBinder.getSignatureService().getSignatureBlob(statemachine.getSceenWidth(), statemachine.getScreenHeight());
+		} else if (POSServiceBinder.getSignatureService() != null) {
+			return POSServiceBinder.getSignatureService().getSignatureBlob(statemachine.getSceenWidth(),
+					statemachine.getScreenHeight());
 		}
 		return null;
 	}
 
-    public void setBeeper(String parameters) {
-    	Integer duration;
-    	Integer frequency;
+	public void setBeeper(String parameters) {
+		Integer duration;
+		Integer frequency;
 		String[] parts = parameters.split("\\|");
 		duration = Integer.parseInt(parts[0]);
 		frequency = Integer.parseInt(parts[1]);
 		beeper.beep(duration, frequency);
-    }
+	}
 
-    public void setPlayer(String name) {
-    	video.setSources(statemachine.getThemeResourceService().getThemeResource(name, ThemeResourceType.VIDEO));
+	public void setPlayer(String name) {
+		video.setSources(statemachine.getThemeResourceService().getThemeResource(name, ThemeResourceType.VIDEO));
 		video.play();
-    }
+	}
 
-    public void setSound(String name) { 
-    	audio.setSources(statemachine.getThemeResourceService().getThemeResource(name, ThemeResourceType.SOUND));
-    	audio.play();
-    }
+	public void setSound(String name) {
+		audio.setSources(statemachine.getThemeResourceService().getThemeResource(name, ThemeResourceType.SOUND));
+		audio.play();
+	}
 
 	@Override
 	public void actionPerformed(ActionEvent e) {
-		if(e.getSource().equals(statusPoll)) {
+		if (e.getSource().equals(statusPoll)) {
 			decodeRemoteState(doHttpGet("/devices/states"));
 			decodeRemoteError(doHttpGet("/devices/errors"));
 		}
-		if(e.getSource().equals(signatureStatusPoll)) {
+		if (e.getSource().equals(signatureStatusPoll)) {
 			decodeRemoteSignatureState(doHttpGet("/signature/states"));
 		}
 	}
 
 	private void decodeRemoteError(String responseString) {
-		if(responseString != null) {
-			List<String> errors = Arrays.asList(responseString.replace("[","").replace("]", "").replace("\"", "").split(","));
-			for(String error:errors) {
-				if(error.startsWith(POS_PRINTER_CONST)) {
+		if (responseString != null) {
+			List<String> errors = Arrays
+					.asList(responseString.replace("[", "").replace("]", "").replace("\"", "").split(","));
+			for (String error : errors) {
+				if (error.startsWith(POS_PRINTER_CONST)) {
 					decodeRemoteErrorState(error);
 				}
 			}
@@ -1533,11 +1963,11 @@
 	}
 
 	private void decodeRemoteErrorState(String error) {
-		for ( Field field : posPrinterFields ) {
-			if(field.getName().equals(error.substring(POS_PRINTER_CONST.length()+1))) {
+		for (Field field : posPrinterFields) {
+			if (field.getName().equals(error.substring(POS_PRINTER_CONST.length() + 1))) {
 				field.setAccessible(true);
 				try {
-					decodePOSPrinterErrorField((int)field.get(error));
+					decodePOSPrinterErrorField((int) field.get(error));
 				} catch (IllegalArgumentException | IllegalAccessException e1) {
 					LOGGER.error("{}", e1);
 				}
@@ -1547,7 +1977,7 @@
 	}
 
 	private void decodeRemoteState(String responseString) {
-		if(responseString != null) {
+		if (responseString != null) {
 			List<String> states = Arrays
 					.asList(responseString.replace("[", "").replace("]", "").replace("\"", "").split(","));
 			for (String state : states) {
@@ -1590,10 +2020,11 @@
 	}
 
 	private void decodeRemoteSignatureState(String responseString) {
-		if(responseString != null) {
-			List<String> states = Arrays.asList(responseString.replace("[","").replace("]", "").replace("\"", "").split(","));
-			for(String state:states) {
-				if(!state.isEmpty()) {
+		if (responseString != null) {
+			List<String> states = Arrays
+					.asList(responseString.replace("[", "").replace("]", "").replace("\"", "").split(","));
+			for (String state : states) {
+				if (!state.isEmpty()) {
 					statemachine.schedule(statemachine, 500, new MessageEvent(EventType.TRIGGER, state));
 				}
 			}
diff --git a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachine.java b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachine.java
index 945506e..57c5080 100644
--- a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachine.java
+++ b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachine.java
@@ -34,12 +34,6 @@
 import javax.annotation.PreDestroy;
 import javax.swing.Timer;
 
-import org.apache.http.ParseException;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.util.EntityUtils;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.osbp.dsl.common.datatypes.IDto;
 import org.eclipse.osbp.preferences.ProductConfiguration;
@@ -205,6 +199,7 @@
 		}
 	}
 
+	@Override
 	public void processEvent(final IStateMachine statemachine, final MessageEvent event) {
 		synchronized (queue) {
 			logger.debug("enqueue event {}", event);
@@ -362,6 +357,30 @@
 	}
 
 	@Override
+	public Object get(String id, String parameter) {
+		Object value;
+		for (IEventSource.Enabler listener : enablerList) {
+			value = listener.get(listener, id, parameter);
+			if (value != null) {
+				return value;
+			}
+		}
+		for (IDataProvider.Provider listener : providerList) {
+			value = listener.get(listener, id, parameter);
+			if (value != null) {
+				return value;
+			}
+		}
+		for (IPeripheral.Command listener : peripheralList) {
+			value = listener.get(listener, id, parameter);
+			if (value != null) {
+				return value;
+			}
+		}
+		return null;
+	}
+	
+	@Override
 	public void set(String id, Object content) {
 		for (IEventSource.Enabler listener : enablerList) {
 			listener.set(listener, id, content);
@@ -637,6 +656,7 @@
 		return webBrowser.isSecureConnection();
 	}
 
+	@Override
 	public void start() {
 		active.set(true);
 		final UI ui = getEclipseContext().get(UI.class);
@@ -871,24 +891,4 @@
 		blocking.set(block);
 	}
 	
-	@Override
-	public boolean isJavaPosRemote() {
-		String cmd = String.format("http://%s:%d/devices/posParameters", getHostName(), getRemotePort());
-		HttpGet get = new HttpGet(cmd);
-		get.addHeader("Accept", "application/json");
-		
-		try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
-			CloseableHttpResponse response = httpClient.execute(get);
-			logger.info(EntityUtils.toString(response.getEntity()));
-			if(response.getEntity().getContentLength()==0) {
-				return false;
-			}
-			return true;
-		} catch (ParseException | IOException e) {
-			// it's ok - we have no remote javapos
-		} finally {
-			get.releaseConnection();
-		}
-		return false;
-	}
 }
diff --git a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachineParticipant.java b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachineParticipant.java
index fc2f87a..3dd70b4 100644
--- a/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachineParticipant.java
+++ b/org.eclipse.osbp.abstractstatemachine/src/org/eclipse/osbp/abstractstatemachine/AbstractStateMachineParticipant.java
@@ -101,12 +101,36 @@
 				}
 			}
 		} catch (IntrospectionException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("getter(x,y) exception: ", e);
 		}
 		return null;
 	}
 
 	@Override
+	public Method getter(Object listener, String id, String device) {
+		if (id == null) {
+			return null;
+		}
+		Class<?> clz = listener.getClass();
+		try {
+			BeanInfo info = Introspector.getBeanInfo(clz);
+			String name = "get"+id;
+			for (MethodDescriptor desc : info.getMethodDescriptors()) {
+				if (desc.getName().equalsIgnoreCase(name)) {
+					Method method = desc.getMethod();
+					Class<?>[] paras = method.getParameterTypes();
+					if(paras.length == 1) {
+						return desc.getMethod();
+					}
+				}
+			}
+		} catch (IntrospectionException e) {
+			LOGGER.error("getter(x,y,z) exception: ", e);
+		}
+		return null;
+	}
+	
+	@Override
 	public Method setter(Object listener, String id, Class<?> parameter, int contentIndex) {
 		if (id == null) {
 			return null;
@@ -124,7 +148,7 @@
 				}
 			}
 		} catch (IntrospectionException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("setter(x,y,z) exception: ", e);
 		}
 		return null;
 	}
@@ -158,7 +182,7 @@
 				}
 			}
 		} catch (IntrospectionException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("getReturnType exception: ", e);
 		}
 		return null;
 	}
@@ -168,7 +192,7 @@
 		Object result = get(obj, id);
 		if(result != null) {
 			if(result.getClass().isAssignableFrom(Boolean.class)) {
-				set(obj, id, (Boolean)result);
+				set(obj, id, result);
 			}
 			if(result.getClass().isAssignableFrom(boolean.class)) {
 				set(obj, id, (boolean)result);
@@ -187,7 +211,7 @@
 			}
 		} catch (IllegalAccessException | IllegalArgumentException
 				| InvocationTargetException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("set(x,y,z) exception: ", e);
 		}
 	}
 
@@ -200,7 +224,7 @@
 			}
 		} catch (IllegalAccessException | IllegalArgumentException
 				| InvocationTargetException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("set(w,x,y,z) exception: ", e);
 		}
 	}
 	
@@ -214,12 +238,27 @@
 			return method.invoke(obj);
 		} catch (IllegalAccessException | IllegalArgumentException
 				| InvocationTargetException e) {
-			LOGGER.error("{}", e);
+			LOGGER.error("get(x,y) exception: ", e);
 			return null;
 		}
 	}
 
 	@Override
+	public Object get(Object obj, String id, String device) {
+		Method method = getter(obj, id, device);
+		if (method == null) {
+			return null;
+		}
+		try {
+			return method.invoke(obj, device);
+		} catch (IllegalAccessException | IllegalArgumentException
+				| InvocationTargetException e) {
+			LOGGER.error("get(x,y,z) exception: ", e);
+			return null;
+		}
+	}
+	
+	@Override
 	public void clear(Object obj, String id) {
 		Method method = setter(obj, id, "", 0);
 		if (method != null) {
@@ -228,7 +267,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, 0.0, 0);
@@ -238,7 +277,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, 0, 0);
@@ -248,7 +287,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, 0L, 0);
@@ -258,7 +297,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, IDto.class, 0);
@@ -268,7 +307,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, Date.class, 0);
@@ -278,7 +317,7 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 		method = setter(obj, id, DateTime.class, 0);
@@ -288,8 +327,9 @@
 				return;
 			} catch (IllegalAccessException | IllegalArgumentException
 					| InvocationTargetException e) {
-				LOGGER.error("{}", e);
+				LOGGER.error("clear exception: ", e);
 			}
 		}
 	}
+
 }