Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,21 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

public class DeviceListener implements DataListener, ErrorListener, StatusUpdateListener, OutputCompleteListener {

private final EventSynchronizer eventSynchronizer;
private static final Logger LOGGER = LoggerFactory.getLogger(DeviceListener.class);
private static final StructuredEventLogger log = StructuredEventLogger.of(StructuredEventLogger.getCommonServiceName(), "DeviceListener", LOGGER);

private static final long ERROR_LOG_DUP_MS = 1000;

private final AtomicReference<String> lastErrorKey = new AtomicReference<>("");
private final AtomicLong lastErrorLogTime = new AtomicLong(0);

public DeviceListener(EventSynchronizer eventSynchronizer) {
if (eventSynchronizer == null) {
throw new IllegalArgumentException("eventSynchronizer cannot be null");
Expand All @@ -36,11 +45,33 @@ public void dataOccurred(DataEvent dataEvent) {

@Override
public void errorOccurred(ErrorEvent errorEvent) {
log.failure("errorOccurred(): errCode=" + errorEvent.getErrorCode()
+ " errCodeExt=" + errorEvent.getErrorCodeExtended()
+ " errLocus=" + errorEvent.getErrorLocus()
+ " errResponse=" + errorEvent.getErrorResponse(), 17, null);
int errorCode = errorEvent.getErrorCode();
int errorExt = errorEvent.getErrorCodeExtended();
int errorLocus = errorEvent.getErrorLocus();
int errorResponse = errorEvent.getErrorResponse();

String currentKey = errorCode + ":" + errorExt + ":" + errorLocus + ":" + errorResponse;
long now = System.currentTimeMillis();

String previousKey = lastErrorKey.get();
long previousTime = lastErrorLogTime.get();

boolean shouldLog = !currentKey.equals(previousKey) || (now - previousTime) > ERROR_LOG_DUP_MS;

if (shouldLog) {
lastErrorKey.set(currentKey);
lastErrorLogTime.set(now);

log.failure(
"errorOccurred(): errCode=" + errorCode
+ " errCodeExt=" + errorExt
+ " errLocus=" + errorLocus
+ " errResponse=" + errorResponse,
17,
null
);
}

if (errorCode == JposConst.JPOS_E_OFFLINE || errorCode == JposConst.JPOS_E_NOHARDWARE) {
BaseService jposService = (BaseService) errorEvent.getSource();
try {
Expand All @@ -49,6 +80,11 @@ public void errorOccurred(ErrorEvent errorEvent) {
log.failure("close failed", 17, jposException);
}
}

if (errorLocus == JposConst.JPOS_EL_OUTPUT) {
errorEvent.setErrorResponse(JposConst.JPOS_ER_CLEAR);
}

eventSynchronizer.triggerEvent(errorEvent);
}

Expand Down Expand Up @@ -113,6 +149,22 @@ public void waitForOutputToComplete() throws JposException {
log.success("waitForOutputToComplete(out)", 1);
}

// This is waitForOutputToComplete with a timeout, which allows the caller to recover and release locks if the device is not responding. Currently only used by printer
public void waitForOutputToComplete(long timeout, TimeUnit unit) throws JposException {
log.success("waitForOutputToComplete(timeout=" + unit.toMillis(timeout) + "ms, in)", 1);
JposEvent jposEvent = eventSynchronizer.waitForEvent(timeout, unit);
if (jposEvent instanceof ErrorEvent) {
throw jposExceptionFromErrorEvent((ErrorEvent) jposEvent);
}
if (jposEvent instanceof StatusUpdateEvent) {
throw jposExceptionFromStatusUpdateEvent((StatusUpdateEvent) jposEvent);
}
if (!(jposEvent instanceof OutputCompleteEvent)) {
throw new JposException(JposConst.JPOS_E_FAILURE);
}
log.success("waitForOutputToComplete(timeout, out)", 1);
}

public StatusUpdateEvent waitForStatusUpdate() throws JposException {
JposEvent jposEvent = eventSynchronizer.waitForEvent();
if (jposEvent instanceof ErrorEvent) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.target.devicemanager.common;

import jpos.JposConst;
import jpos.JposException;
import jpos.events.ErrorEvent;
import jpos.events.JposEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

Expand Down Expand Up @@ -62,6 +65,32 @@ public JposEvent waitForEvent() {
return tmpEvent;
}

// Waits for an event up to the specified timeout.
public JposEvent waitForEvent(long timeout, TimeUnit unit) throws JposException {
try {
phaser.awaitAdvanceInterruptibly(waitingPhase.get(), timeout, unit);
} catch (TimeoutException timeoutException) {
synchronized (this) {
areEventsActive.set(false);
}
log.failure("waitForEvent timed out after " + unit.toMillis(timeout) + "ms", 18, null);
throw new JposException(JposConst.JPOS_E_TIMEOUT);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
synchronized (this) {
areEventsActive.set(false);
}
log.failure("waitForEvent interrupted", 17, interruptedException);
throw new JposException(JposConst.JPOS_E_TIMEOUT);
}
JposEvent tmpEvent;
synchronized (this) {
areEventsActive.set(false);
tmpEvent = lastEvent;
}
return tmpEvent;
}

public synchronized void stopWaitingForEvent() {
this.lastEvent = new ErrorEvent(this, JposConst.JPOS_E_TIMEOUT, 0, 0, 0);
phaser.arrive();
Expand Down
Loading