diff --git a/src/qz/communication/DeviceException.java b/src/qz/communication/DeviceException.java
deleted file mode 100644
index ddf803ab9..000000000
--- a/src/qz/communication/DeviceException.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package qz.communication;
-
-public class DeviceException extends Exception {
-
- public DeviceException(String message) {
- super(message);
- }
-
- public DeviceException(Throwable cause) {
- super(cause);
- }
-
-}
diff --git a/src/qz/communication/DeviceIO.java b/src/qz/communication/DeviceIO.java
index 2fbcce886..49ce50316 100644
--- a/src/qz/communication/DeviceIO.java
+++ b/src/qz/communication/DeviceIO.java
@@ -7,11 +7,11 @@ public interface DeviceIO {
String getProductId();
- void open() throws DeviceException;
+ void open() throws UsbException;
boolean isOpen();
- void close() throws DeviceException;
+ void close() throws UsbException;
void setStreaming(boolean streaming);
@@ -19,12 +19,12 @@ public interface DeviceIO {
boolean isStreaming();
- byte[] readData(int responseSize, Byte exchangeConfig) throws DeviceException;
+ byte[] readData(int responseSize, Byte exchangeConfig) throws UsbException;
- void sendData(byte[] data, Byte exchangeConfig) throws DeviceException;
+ void sendData(byte[] data, Byte exchangeConfig) throws UsbException;
- byte[] getFeatureReport(int responseSize, Byte reportId) throws DeviceException;
+ byte[] getFeatureReport(int responseSize, Byte reportId) throws UsbException;
- void sendFeatureReport(byte[] data, Byte reportId) throws DeviceException;
+ void sendFeatureReport(byte[] data, Byte reportId) throws UsbException;
}
diff --git a/src/qz/communication/H4J_HidIO.java b/src/qz/communication/H4J_HidIO.java
index fc575dab0..49f396e6d 100644
--- a/src/qz/communication/H4J_HidIO.java
+++ b/src/qz/communication/H4J_HidIO.java
@@ -11,13 +11,14 @@ public class H4J_HidIO implements DeviceIO {
private boolean streaming;
- public H4J_HidIO(DeviceOptions dOpts) throws DeviceException {
+ public H4J_HidIO(UsbOptions dOpts) throws UsbException {
this(H4J_HidUtilities.findDevice(dOpts));
}
- public H4J_HidIO(HidDevice device) throws DeviceException {
+ public H4J_HidIO(HidDevice device) throws UsbException {
if (device == null) {
- throw new DeviceException("HID device could not be found");
+ // FIXME: This shouldn't generate a general exception up the stack, but it does
+ throw new UsbException("HID device could not be found");
}
this.device = device;
@@ -49,45 +50,45 @@ public String getProductId() {
return UsbUtil.toHexString(device.getProductId());
}
- public byte[] readData(int responseSize, Byte unused) throws DeviceException {
+ public byte[] readData(int responseSize, Byte unused) throws UsbException {
byte[] response = new byte[responseSize];
int read = device.read(response);
if (read == -1) {
- throw new DeviceException("Failed to read from device");
+ throw new UsbException("Failed to read from device");
}
return response;
}
- public void sendData(byte[] data, Byte reportId) throws DeviceException {
+ public void sendData(byte[] data, Byte reportId) throws UsbException {
if (reportId == null) { reportId = (byte)0x00; }
int wrote = device.write(data, data.length, reportId);
if (wrote == -1) {
- throw new DeviceException("Failed to write to device");
+ throw new UsbException("Failed to write to device");
}
}
- public byte[] getFeatureReport(int responseSize, Byte reportId) throws DeviceException {
+ public byte[] getFeatureReport(int responseSize, Byte reportId) throws UsbException {
if (reportId == null) { reportId = (byte)0x00; }
byte[] response = new byte[responseSize];
int read = device.getFeatureReport(response, reportId);
if (read == -1) {
- throw new DeviceException("Failed to read from device");
+ throw new UsbException("Failed to read from device");
}
return response;
}
- public void sendFeatureReport(byte[] data, Byte reportId) throws DeviceException {
+ public void sendFeatureReport(byte[] data, Byte reportId) throws UsbException {
if (reportId == null) { reportId = (byte)0x00; }
int wrote = device.sendFeatureReport(data, reportId);
if (wrote == -1) {
- throw new DeviceException("Failed to write to device");
+ throw new UsbException("Failed to write to device");
}
}
diff --git a/src/qz/communication/H4J_HidUtilities.java b/src/qz/communication/H4J_HidUtilities.java
index 989d678a2..fb9f2f551 100644
--- a/src/qz/communication/H4J_HidUtilities.java
+++ b/src/qz/communication/H4J_HidUtilities.java
@@ -54,7 +54,7 @@ public static JSONArray getHidDevicesJSON() throws JSONException {
return devicesJSON;
}
- public static HidDevice findDevice(DeviceOptions dOpts) {
+ public static HidDevice findDevice(UsbOptions dOpts) {
if (dOpts.getVendorId() == null) {
throw new IllegalArgumentException("Vendor ID cannot be null");
}
diff --git a/src/qz/communication/PJHA_HidIO.java b/src/qz/communication/PJHA_HidIO.java
index 9da8123a5..7a6471d67 100644
--- a/src/qz/communication/PJHA_HidIO.java
+++ b/src/qz/communication/PJHA_HidIO.java
@@ -24,13 +24,13 @@ public class PJHA_HidIO implements DeviceIO {
private boolean streaming;
- public PJHA_HidIO(DeviceOptions dOpts) throws DeviceException {
+ public PJHA_HidIO(UsbOptions dOpts) throws UsbException {
this(PJHA_HidUtilities.findDevice(dOpts));
}
- public PJHA_HidIO(HidDeviceInfo deviceInfo) throws DeviceException {
+ public PJHA_HidIO(HidDeviceInfo deviceInfo) throws UsbException {
if (deviceInfo == null) {
- throw new DeviceException("HID device could not be found");
+ throw new UsbException("HID device could not be found");
}
this.deviceInfo = deviceInfo;
@@ -46,7 +46,7 @@ public synchronized boolean add(byte[] e) {
};
}
- public void open() throws DeviceException {
+ public void open() throws UsbException {
if (!isOpen()) {
try {
device = PureJavaHidApi.openDevice(deviceInfo);
@@ -60,7 +60,7 @@ public void onInputReport(HidDevice source, byte id, byte[] data, int len) {
});
}
catch(IOException ex) {
- throw new DeviceException(ex);
+ throw new UsbException(ex);
}
}
}
@@ -85,7 +85,7 @@ public String getProductId() {
return UsbUtil.toHexString(deviceInfo.getProductId());
}
- public byte[] readData(int responseSize, Byte unused) throws DeviceException {
+ public byte[] readData(int responseSize, Byte unused) throws UsbException {
byte[] response = new byte[responseSize];
if (dataBuffer.isEmpty()) {
return new byte[0]; //no data received yet
@@ -101,30 +101,30 @@ public byte[] readData(int responseSize, Byte unused) throws DeviceException {
return response;
}
- public void sendData(byte[] data, Byte reportId) throws DeviceException {
+ public void sendData(byte[] data, Byte reportId) throws UsbException {
if (reportId == null) { reportId = (byte)0x00; }
int wrote = device.setOutputReport(reportId, data, data.length);
if (wrote == -1) {
- throw new DeviceException("Failed to write to device");
+ throw new UsbException("Failed to write to device");
}
}
- public byte[] getFeatureReport(int responseSize, Byte unused) throws DeviceException {
+ public byte[] getFeatureReport(int responseSize, Byte unused) throws UsbException {
byte[] response = new byte[responseSize];
int read = device.getFeatureReport(response, responseSize);
if (read == -1) {
- throw new DeviceException("Failed to read from device");
+ throw new UsbException("Failed to read from device");
}
return response;
}
- public void sendFeatureReport(byte[] data, Byte reportId) throws DeviceException {
+ public void sendFeatureReport(byte[] data, Byte reportId) throws UsbException {
if (reportId == null) { reportId = (byte)0x00; }
int wrote = device.setFeatureReport(reportId, data, data.length);
if (wrote == -1) {
- throw new DeviceException("Failed to write to device");
+ throw new UsbException("Failed to write to device");
}
}
diff --git a/src/qz/communication/PJHA_HidUtilities.java b/src/qz/communication/PJHA_HidUtilities.java
index e8e868271..eacbde8f8 100644
--- a/src/qz/communication/PJHA_HidUtilities.java
+++ b/src/qz/communication/PJHA_HidUtilities.java
@@ -32,7 +32,7 @@ public static JSONArray getHidDevicesJSON() throws JSONException {
return devicesJSON;
}
- public static HidDeviceInfo findDevice(DeviceOptions dOpts) {
+ public static HidDeviceInfo findDevice(UsbOptions dOpts) {
if (dOpts.getVendorId() == null) {
throw new IllegalArgumentException("Vendor ID cannot be null");
}
diff --git a/src/qz/communication/UsbException.java b/src/qz/communication/UsbException.java
new file mode 100644
index 000000000..c779dff78
--- /dev/null
+++ b/src/qz/communication/UsbException.java
@@ -0,0 +1,13 @@
+package qz.communication;
+
+public class UsbException extends Exception {
+
+ public UsbException(String message) {
+ super(message);
+ }
+
+ public UsbException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/src/qz/communication/UsbIO.java b/src/qz/communication/UsbIO.java
index 2d553a5ef..b781ebce1 100644
--- a/src/qz/communication/UsbIO.java
+++ b/src/qz/communication/UsbIO.java
@@ -13,11 +13,11 @@ public class UsbIO implements DeviceIO {
private boolean streaming;
- public UsbIO(DeviceOptions dOpts) throws DeviceException {
+ public UsbIO(UsbOptions dOpts) throws UsbException {
UsbDevice device = UsbUtilities.findDevice(dOpts.getVendorId().shortValue(), dOpts.getProductId().shortValue());
if (device == null) {
- throw new DeviceException("USB device could not be found");
+ throw new UsbException("USB device could not be found");
}
if (dOpts.getInterfaceId() == null) {
throw new IllegalArgumentException("Device interface cannot be null");
@@ -27,7 +27,7 @@ public UsbIO(DeviceOptions dOpts) throws DeviceException {
this.iface = device.getActiveUsbConfiguration().getUsbInterface(dOpts.getInterfaceId());
}
- public void open() throws DeviceException {
+ public void open() throws UsbException {
try {
iface.claim(new UsbInterfacePolicy() {
@Override
@@ -37,8 +37,8 @@ public boolean forceClaim(UsbInterface usbInterface) {
}
});
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
@@ -66,32 +66,32 @@ public String getInterface() {
return UsbUtil.toHexString(iface.getUsbInterfaceDescriptor().iInterface());
}
- public byte[] readData(int responseSize, Byte endpoint) throws DeviceException {
+ public byte[] readData(int responseSize, Byte endpoint) throws UsbException {
try {
byte[] response = new byte[responseSize];
exchangeData(endpoint, response);
return response;
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
- public void sendData(byte[] data, Byte endpoint) throws DeviceException {
+ public void sendData(byte[] data, Byte endpoint) throws UsbException {
try {
exchangeData(endpoint, data);
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
- public byte[] getFeatureReport(int responseSize, Byte reportId) throws DeviceException {
- throw new DeviceException("USB feature reports are not supported");
+ public byte[] getFeatureReport(int responseSize, Byte reportId) throws UsbException {
+ throw new UsbException("USB feature reports are not supported");
}
- public void sendFeatureReport(byte[] data, Byte reportId) throws DeviceException {
- throw new DeviceException("USB feature reports are not supported");
+ public void sendFeatureReport(byte[] data, Byte reportId) throws UsbException {
+ throw new UsbException("USB feature reports are not supported");
}
/**
@@ -100,7 +100,7 @@ public void sendFeatureReport(byte[] data, Byte reportId) throws DeviceException
* @param endpoint Endpoint on the usb device interface to pass data across
* @param data Byte array of data to send, or to be written from a receive
*/
- private synchronized void exchangeData(Byte endpoint, byte[] data) throws UsbException {
+ private synchronized void exchangeData(Byte endpoint, byte[] data) throws javax.usb.UsbException {
if (endpoint == null) {
throw new IllegalArgumentException("Interface endpoint cannot be null");
}
@@ -116,13 +116,13 @@ private synchronized void exchangeData(Byte endpoint, byte[] data) throws UsbExc
}
}
- public void close() throws DeviceException {
+ public void close() throws UsbException {
if (iface.isClaimed()) {
try {
iface.release();
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
streaming = false;
diff --git a/src/qz/communication/DeviceOptions.java b/src/qz/communication/UsbOptions.java
similarity index 83%
rename from src/qz/communication/DeviceOptions.java
rename to src/qz/communication/UsbOptions.java
index a4fbf0075..8ab8cc8e0 100644
--- a/src/qz/communication/DeviceOptions.java
+++ b/src/qz/communication/UsbOptions.java
@@ -4,7 +4,7 @@
import org.codehaus.jettison.json.JSONObject;
import qz.utils.UsbUtilities;
-public class DeviceOptions {
+public class UsbOptions {
public enum DeviceMode {
HID,
@@ -24,6 +24,9 @@ public static DeviceMode parse(String callName) {
private DeviceMode deviceMode;
+ private String vendorIdString;
+ private String productIdString;
+
private Integer vendorId;
private Integer productId;
@@ -37,11 +40,13 @@ public static DeviceMode parse(String callName) {
private Integer usagePage;
private String serial;
- public DeviceOptions(JSONObject parameters, DeviceMode deviceMode) {
+ public UsbOptions(JSONObject parameters, DeviceMode deviceMode) {
this.deviceMode = deviceMode;
- vendorId = UsbUtilities.hexToInt(parameters.optString("vendorId"));
- productId = UsbUtilities.hexToInt(parameters.optString("productId"));
+ vendorIdString = parameters.optString("vendorId");
+ vendorId = UsbUtilities.hexToInt(vendorIdString);
+ productIdString = parameters.optString("productId");
+ productId = UsbUtilities.hexToInt(productIdString);
if (!parameters.isNull("interface")) {
interfaceId = UsbUtilities.hexToByte(parameters.optString("interface"));
@@ -71,6 +76,14 @@ public Integer getProductId() {
return productId;
}
+ public String getVendorIdString() {
+ return vendorIdString;
+ }
+
+ public String getProductIdString() {
+ return productIdString;
+ }
+
public Byte getInterfaceId() {
return interfaceId;
}
@@ -97,9 +110,9 @@ public String getSerial() {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof DeviceOptions)) { return false; }
+ if (obj == null || !(obj instanceof UsbOptions)) { return false; }
- DeviceOptions that = (DeviceOptions)obj;
+ UsbOptions that = (UsbOptions)obj;
if (this.getVendorId().equals(that.getVendorId()) && this.getProductId().equals(that.getProductId())) {
if (deviceMode == DeviceMode.USB
diff --git a/src/qz/exception/WebsocketError.java b/src/qz/exception/WebsocketError.java
new file mode 100644
index 000000000..c54966ce6
--- /dev/null
+++ b/src/qz/exception/WebsocketError.java
@@ -0,0 +1,122 @@
+package qz.exception;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import qz.ws.SocketMethod;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static qz.exception.WebsocketError.WebsocketErrorType.*;
+
+public enum WebsocketError {
+ // Websocket
+ CONNECTION_BLOCKED(WEBSOCKET_ERROR, "Connection blocked by client", 0),
+ REQUEST_BLOCKED(WEBSOCKET_ERROR, "Request blocked", 1),
+ MESSAGE_EMPTY(WEBSOCKET_ERROR, "Message is empty", 2),
+
+ // Printing
+ PRINTER_NOT_SPECIFIED(PRINTING_ERROR, "A printer must be specified before printing", 10),
+ PRINTER_NOT_FOUND(PRINTING_ERROR, "Specified printer could not be found.", 11),
+ PRINTER_NOT_LISTENING(PRINTING_ERROR, "No printer listeners started for this client.", 14),
+ PRINTING_FAILED(PRINTING_ERROR, "Failed to print", 17),
+ PRINTING_CANCELLED(PRINTING_ERROR, "Printing cancelled", 18),
+
+ // Serial
+ SERIAL_PORT_NOT_OPEN(SERIAL_ERROR, "Serial port [%s] is not open.", 20),
+ SERIAL_PORT_NOT_FOUND(SERIAL_ERROR, "Serial port [%s] not found", 21),
+ SERIAL_PORT_OPEN_FAILED(SERIAL_ERROR, "Unable to open serial port [%s]", 22),
+ SERIAL_PORT_ALREADY_OPEN(SERIAL_ERROR, "Serial port [%s] is already open.", 23),
+
+ // Socket
+ SOCKET_NOT_OPEN(SOCKET_ERROR, "Socket [%s] is not open.", 30),
+ SOCKET_OPEN_FAILED(SOCKET_ERROR, "Unable to open socket [%s]", 32),
+ SOCKET_ALREADY_OPEN(SOCKET_ERROR, "Socket [%s] is already open", 33),
+
+ // USB/HID (The word "HID" or "USB" will be determined by the SocketMethod)
+ USB_NOT_CLAIMED(USB_ERROR, "USB Device [v:%s p:%s] is not claimed.", 40),
+ USB_CLAIM_FAILED(USB_ERROR, "Failed to open connection to %s device", 42),
+ USB_ALREADY_CLAIMED(USB_ERROR, "%s Device [v:%s p:%s] is already claimed", 43),
+ USB_ALREADY_LISTENING(USB_ERROR, "Already listening %s device events", 44),
+ USB_NOT_LISTENING(USB_ERROR, "Not already listening %s device events", 45),
+ USB_NOT_STREAMING(USB_ERROR, "USB Device [v:%s p:%s] is not streaming data.", 46),
+ USB_ALREADY_STREAMING(USB_ERROR, "USB Device [v:%s p:%s] is already streaming data", 47),
+
+ // FileIO
+ FILE_PATH_NOT_EXIST(FILE_ERROR, "Path does not exist", 51),
+ FILE_ALREADY_LISTENING(FILE_ERROR, "Already listening to path events", 54),
+ FILE_NOT_LISTENING(FILE_ERROR, "Not already listening to path events", 55),
+ FILE_PATH_NOT_READABLE(FILE_ERROR, "Path is not readable", 56),
+ FILE_NOT_DIRECTORY(FILE_ERROR, "Path is not a directory", 58),
+ FILE_EXCEPTION(FILE_ERROR, "FileIO exception occurred: %s: %s", 59),
+
+ // Misc
+ INVALID_FUNCTION_CALL(GENERAL_ERROR, "Invalid function call: %s", 998),
+ UNHANDLED(GENERAL_ERROR, "An unhandled exception has occurred: %s", 999);
+
+ private static final Logger log = LogManager.getLogger(WebsocketError.class);
+
+ public enum WebsocketErrorType {
+ GENERAL_ERROR,
+ WEBSOCKET_ERROR,
+ PRINTING_ERROR,
+ FILE_ERROR,
+ USB_ERROR,
+ SERIAL_ERROR,
+ SOCKET_ERROR;
+ }
+
+ private WebsocketErrorType type;
+ private String description;
+ private int id;
+
+ WebsocketError(WebsocketErrorType type, String description, int id) {
+ this.type = type;
+ this.description = description;
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Prepends socket method prefix (e.g. "HID", "USB"), to list of arguments
+ */
+ public String format(SocketMethod method, String ... args) {
+ ArrayList argsList = new ArrayList<>(args == null ? 1 : args.length + 1);
+ argsList.add(method == null ? "null" : method.name().split("_")[0]);
+ if(args != null) {
+ argsList.addAll(Arrays.asList(args));
+ }
+ return format(argsList.toArray(new String[argsList.size()]));
+ }
+
+ /**
+ * Appends the exception message (or class name if missing) to the list of arguments
+ */
+ public String format(Throwable t, String ... args) {
+ ArrayList argsList = new ArrayList<>(args == null ? 1 : args.length + 1);
+ if(args != null) {
+ argsList.addAll(Arrays.asList(args));
+ }
+ // If empty, send class name; it's better than nothing
+ String message = t == null ? "null" : t.getLocalizedMessage();
+ argsList.add(message == null ? t.getClass().getSimpleName() : message);
+ log.error(t);
+ // FIXME: Why does this print "%s" in the logs/UI?
+ return format(argsList.toArray(new String[argsList.size()]));
+ }
+
+
+ public String format(String ... args) {
+ try {
+ if(args != null) {
+ return String.format(description, args);
+ }
+ } catch(Throwable t) {
+ log.error(t);
+ } finally {
+ return description;
+ }
+ }
+}
diff --git a/src/qz/utils/PrintingUtilities.java b/src/qz/utils/PrintingUtilities.java
index 3877a8b00..dc4804343 100644
--- a/src/qz/utils/PrintingUtilities.java
+++ b/src/qz/utils/PrintingUtilities.java
@@ -8,6 +8,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import qz.common.Constants;
+import qz.exception.WebsocketError;
import qz.printer.PrintOptions;
import qz.printer.PrintOutput;
import qz.printer.action.PrintProcessor;
@@ -154,12 +155,10 @@ public static void processPrintRequest(Session session, String UID, JSONObject p
PrintSocketClient.sendResult(session, UID, null);
}
catch(PrinterAbortException e) {
- log.warn("Printing cancelled");
- PrintSocketClient.sendError(session, UID, "Printing cancelled");
+ PrintSocketClient.sendError(session, UID, WebsocketError.PRINTING_CANCELLED);
}
catch(Exception e) {
- log.error("Failed to print", e);
- PrintSocketClient.sendError(session, UID, e);
+ PrintSocketClient.sendError(session, UID, WebsocketError.PRINTING_FAILED, e);
}
finally {
PrintingUtilities.releasePrintProcessor(processor);
diff --git a/src/qz/utils/SerialUtilities.java b/src/qz/utils/SerialUtilities.java
index e488f688d..263b6da57 100644
--- a/src/qz/utils/SerialUtilities.java
+++ b/src/qz/utils/SerialUtilities.java
@@ -11,6 +11,7 @@
import org.apache.logging.log4j.Logger;
import qz.communication.SerialIO;
import qz.communication.SerialOptions;
+import qz.exception.WebsocketError;
import qz.ws.PrintSocketClient;
import qz.ws.SocketConnection;
import qz.ws.StreamEvent;
@@ -228,7 +229,7 @@ public static int parseBaudRate(String rate) {
public static void setupSerialPort(final Session session, String UID, SocketConnection connection, JSONObject params) throws JSONException {
final String portName = params.getString("port");
if (connection.getSerialPort(portName) != null) {
- PrintSocketClient.sendError(session, UID, String.format("Serial port [%s] is already open.", portName));
+ PrintSocketClient.sendError(session, UID, WebsocketError.SERIAL_PORT_ALREADY_OPEN, portName);
return;
}
@@ -253,7 +254,7 @@ public static void setupSerialPort(final Session session, String UID, SocketConn
PrintSocketClient.sendResult(session, UID, null);
} else {
- PrintSocketClient.sendError(session, UID, String.format("Unable to open serial port [%s]", portName));
+ PrintSocketClient.sendError(session, UID, WebsocketError.SERIAL_PORT_OPEN_FAILED, portName);
}
}
catch(SerialPortException e) {
diff --git a/src/qz/utils/SocketUtilities.java b/src/qz/utils/SocketUtilities.java
index 0be3563e6..ff87fbb63 100644
--- a/src/qz/utils/SocketUtilities.java
+++ b/src/qz/utils/SocketUtilities.java
@@ -6,6 +6,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import qz.communication.SocketIO;
+import qz.exception.WebsocketError;
import qz.ws.PrintSocketClient;
import qz.ws.SocketConnection;
import qz.ws.StreamEvent;
@@ -24,7 +25,7 @@ public static void setupSocket(final Session session, String UID, SocketConnecti
final String location = String.format("%s:%s", host, port);
if (connection.getNetworkSocket(location) != null) {
- PrintSocketClient.sendError(session, UID, String.format("Socket [%s] is already open", location));
+ PrintSocketClient.sendError(session, UID, WebsocketError.SOCKET_ALREADY_OPEN, location);
return;
}
@@ -66,7 +67,7 @@ public static void setupSocket(final Session session, String UID, SocketConnecti
PrintSocketClient.sendResult(session, UID, null);
} else {
- PrintSocketClient.sendError(session, UID, String.format("Unable to open socket [%s]", location));
+ PrintSocketClient.sendError(session, UID, WebsocketError.SOCKET_OPEN_FAILED, location);
}
}
catch(IOException e) {
diff --git a/src/qz/utils/UsbUtilities.java b/src/qz/utils/UsbUtilities.java
index 44a4c754b..d2163c676 100644
--- a/src/qz/utils/UsbUtilities.java
+++ b/src/qz/utils/UsbUtilities.java
@@ -7,9 +7,10 @@
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import qz.communication.DeviceException;
+import qz.communication.UsbException;
import qz.communication.DeviceIO;
-import qz.communication.DeviceOptions;
+import qz.communication.UsbOptions;
+import qz.exception.WebsocketError;
import qz.ws.PrintSocketClient;
import qz.ws.SocketConnection;
import qz.ws.StreamEvent;
@@ -42,12 +43,12 @@ public static Byte hexToByte(String hex) {
}
- public static List getUsbDevices(boolean includeHubs) throws DeviceException {
+ public static List getUsbDevices(boolean includeHubs) throws UsbException {
try {
return getUsbDevices(UsbHostManager.getUsbServices().getRootUsbHub(), includeHubs);
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
@@ -71,7 +72,7 @@ private static List getUsbDevices(UsbHub hub, boolean includeHubs) {
return devices;
}
- public static JSONArray getUsbDevicesJSON(boolean includeHubs) throws DeviceException, JSONException {
+ public static JSONArray getUsbDevicesJSON(boolean includeHubs) throws UsbException, JSONException {
List devices = getUsbDevices(includeHubs);
JSONArray deviceJSON = new JSONArray();
@@ -89,12 +90,12 @@ public static JSONArray getUsbDevicesJSON(boolean includeHubs) throws DeviceExce
return deviceJSON;
}
- public static UsbDevice findDevice(Short vendorId, Short productId) throws DeviceException {
+ public static UsbDevice findDevice(Short vendorId, Short productId) throws UsbException {
try {
return findDevice(UsbHostManager.getUsbServices().getRootUsbHub(), vendorId, productId);
}
- catch(UsbException e) {
- throw new DeviceException(e);
+ catch(javax.usb.UsbException e) {
+ throw new UsbException(e);
}
}
@@ -125,11 +126,11 @@ private static UsbDevice findDevice(UsbHub hub, Short vendorId, Short productId)
return null;
}
- public static List getDeviceInterfaces(Short vendorId, Short productId) throws DeviceException {
+ public static List getDeviceInterfaces(Short vendorId, Short productId) throws UsbException {
return findDevice(vendorId, productId).getActiveUsbConfiguration().getUsbInterfaces();
}
- public static JSONArray getDeviceInterfacesJSON(DeviceOptions dOpts) throws DeviceException {
+ public static JSONArray getDeviceInterfacesJSON(UsbOptions dOpts) throws UsbException {
JSONArray ifaceJSON = new JSONArray();
List ifaces = getDeviceInterfaces(dOpts.getVendorId().shortValue(), dOpts.getProductId().shortValue());
@@ -143,7 +144,7 @@ public static JSONArray getDeviceInterfacesJSON(DeviceOptions dOpts) throws Devi
return ifaceJSON;
}
- public static List getInterfaceEndpoints(Short vendorId, Short productId, Byte iface) throws DeviceException {
+ public static List getInterfaceEndpoints(Short vendorId, Short productId, Byte iface) throws UsbException {
if (iface == null) {
throw new IllegalArgumentException("Device interface cannot be null");
}
@@ -151,7 +152,7 @@ public static List getInterfaceEndpoints(Short vendorId, Short productId, Byte i
return findDevice(vendorId, productId).getActiveUsbConfiguration().getUsbInterface(iface).getUsbEndpoints();
}
- public static JSONArray getInterfaceEndpointsJSON(DeviceOptions dOpts) throws DeviceException {
+ public static JSONArray getInterfaceEndpointsJSON(UsbOptions dOpts) throws UsbException {
JSONArray endJSON = new JSONArray();
List endpoints = getInterfaceEndpoints(dOpts.getVendorId().shortValue(), dOpts.getProductId().shortValue(), dOpts.getInterfaceId());
@@ -167,7 +168,7 @@ public static JSONArray getInterfaceEndpointsJSON(DeviceOptions dOpts) throws De
// shared by usb and hid streaming
- public static void setupUsbStream(final Session session, String UID, SocketConnection connection, final DeviceOptions dOpts, final StreamEvent.Stream streamType) {
+ public static void setupUsbStream(final Session session, String UID, SocketConnection connection, final UsbOptions dOpts, final StreamEvent.Stream streamType) {
final DeviceIO usb = connection.getDevice(dOpts);
if (usb != null) {
@@ -201,7 +202,7 @@ public void run() {
usb.setStreaming(false);
log.error("USB stream error", e);
}
- catch(DeviceException e) {
+ catch(UsbException e) {
usb.setStreaming(false);
log.error("USB stream error", e);
@@ -214,10 +215,10 @@ public void run() {
PrintSocketClient.sendResult(session, UID, null);
} else {
- PrintSocketClient.sendError(session, UID, String.format("USB Device [v:%s p:%s] is already streaming data.", dOpts.getVendorId(), dOpts.getProductId()));
+ PrintSocketClient.sendError(session, UID, WebsocketError.USB_ALREADY_STREAMING, dOpts.getVendorIdString(), dOpts.getProductIdString());
}
} else {
- PrintSocketClient.sendError(session, UID, String.format("USB Device [v:%s p:%s] must be claimed first.", dOpts.getVendorId(), dOpts.getProductId()));
+ PrintSocketClient.sendError(session, UID, WebsocketError.USB_NOT_CLAIMED, dOpts.getVendorIdString(), dOpts.getProductIdString());
}
}
diff --git a/src/qz/ws/PrintSocketClient.java b/src/qz/ws/PrintSocketClient.java
index e9765651d..49241fe29 100644
--- a/src/qz/ws/PrintSocketClient.java
+++ b/src/qz/ws/PrintSocketClient.java
@@ -17,6 +17,7 @@
import qz.common.Constants;
import qz.common.TrayManager;
import qz.communication.*;
+import qz.exception.WebsocketError;
import qz.printer.PrintServiceMatcher;
import qz.printer.status.StatusMonitor;
import qz.printer.status.StatusSession;
@@ -37,6 +38,8 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeoutException;
+import static qz.exception.WebsocketError.*;
+
@WebSocket
public class PrintSocketClient {
@@ -99,7 +102,7 @@ public void onMessage(Session session, Reader reader) throws IOException {
String message = IOUtils.toString(reader);
if (message == null || message.isEmpty()) {
- sendError(session, null, "Message is empty");
+ sendError(session, null, MESSAGE_EMPTY);
return;
}
if (Constants.PROBE_REQUEST.equals(message)) {
@@ -137,7 +140,7 @@ public void onMessage(Session session, Reader reader) throws IOException {
findDialogPosition(session, json.optJSONObject("position")))) {
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Connection blocked by client");
+ sendError(session, UID, CONNECTION_BLOCKED);
session.disconnect();
}
@@ -169,7 +172,7 @@ public void onMessage(Session session, Reader reader) throws IOException {
}
catch(InvalidPathException | FileSystemException e) {
log.error("FileIO exception occurred", e);
- sendError(session, UID, String.format("FileIO exception occurred: %s: %s", e.getClass().getSimpleName(), e.getMessage()));
+ sendError(session, UID, FILE_EXCEPTION, e.getClass().getSimpleName(), e.getMessage());
}
catch(Exception e) {
log.error("Problem processing message", e);
@@ -191,7 +194,7 @@ private boolean validSignature(Certificate certificate, JSONObject message) thro
* @param session WebSocket session
* @param json JSON received from web API
*/
- private void processMessage(Session session, JSONObject json, SocketConnection connection, RequestState request) throws JSONException, SerialPortException, DeviceException, IOException, ListenerNotFoundException {
+ private void processMessage(Session session, JSONObject json, SocketConnection connection, RequestState request) throws JSONException, SerialPortException, UsbException, IOException, ListenerNotFoundException {
String UID = json.optString("uid");
SocketMethod call = SocketMethod.findFromCall(json.optString("call"));
JSONObject params = json.optJSONObject("params");
@@ -210,14 +213,14 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
if (pr != null) {
prompt = String.format(prompt, pr.optString("name", pr.optString("file", pr.optString("host", "an undefined location"))));
} else {
- sendError(session, UID, "A printer must be specified before printing");
+ sendError(session, UID, PRINTER_NOT_SPECIFIED);
return;
}
}
if (call.isDialogShown()
&& !allowedFromDialog(request, prompt, findDialogPosition(session, json.optJSONObject("position")))) {
- sendError(session, UID, "Request blocked");
+ sendError(session, UID, REQUEST_BLOCKED);
return;
}
@@ -226,7 +229,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
}
// used in usb calls
- DeviceOptions dOpts = new DeviceOptions(params, DeviceOptions.DeviceMode.parse(call.getCallName()));
+ UsbOptions dOpts = new UsbOptions(params, UsbOptions.DeviceMode.parse(call.getCallName()));
//call appropriate methods
@@ -241,7 +244,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
if (name != null) {
sendResult(session, UID, name);
} else {
- sendError(session, UID, "Specified printer could not be found.");
+ sendError(session, UID, PRINTER_NOT_FOUND);
}
} else {
JSONArray services = PrintServiceMatcher.getPrintersJSON();
@@ -267,7 +270,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
if (connection.hasStatusListener()) {
StatusMonitor.sendStatuses(connection);
} else {
- sendError(session, UID, "No printer listeners started for this client.");
+ sendError(session, UID, PRINTER_NOT_LISTENING);
}
sendResult(session, UID, null);
break;
@@ -302,7 +305,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
serial.sendData(params, opts);
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("Serial port [%s] must be opened first.", params.optString("port")));
+ sendError(session, UID, SERIAL_PORT_NOT_OPEN, params.optString("port"));
}
break;
}
@@ -313,7 +316,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
connection.removeSerialPort(params.optString("port"));
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("Serial port [%s] is not open.", params.optString("port")));
+ sendError(session, UID, SERIAL_PORT_NOT_OPEN, params.optString("port"));
}
break;
}
@@ -328,7 +331,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
socket.sendData(params);
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("Socket [%s] is not open.", location));
+ sendError(session, UID, SOCKET_NOT_OPEN, location);
}
break;
}
@@ -340,7 +343,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
connection.removeNetworkSocket(location);
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("Socket [%s] is not open.", location));
+ sendError(session, UID, SOCKET_NOT_OPEN, location);
}
break;
}
@@ -370,7 +373,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
}
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Already listening HID device events");
+ sendError(session, UID, USB_ALREADY_LISTENING, call);
}
break;
case HID_STOP_LISTENING:
@@ -378,7 +381,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
connection.stopDeviceListening();
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Not already listening HID device events");
+ sendError(session, UID, USB_NOT_LISTENING, call);
}
break;
@@ -403,10 +406,10 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
if (device.isOpen()) {
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Failed to open connection to device");
+ sendError(session, UID, USB_CLAIM_FAILED, call);
}
} else {
- sendError(session, UID, String.format("USB Device [v:%s p:%s] is already claimed.", params.opt("vendorId"), params.opt("productId")));
+ sendError(session, UID, USB_ALREADY_CLAIMED, call, params.optString("vendorId"), params.optString("productId"));
}
break;
@@ -430,7 +433,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("USB Device [v:%s p:%s] must be claimed first.", params.opt("vendorId"), params.opt("productId")));
+ sendError(session, UID, USB_NOT_CLAIMED, call, params.optString("vendorId"), params.optString("productId"));
}
break;
@@ -455,7 +458,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
}
sendResult(session, UID, hex);
} else {
- sendError(session, UID, String.format("USB Device [v:%s p:%s] must be claimed first.", params.opt("vendorId"), params.opt("productId")));
+ sendError(session, UID, USB_NOT_CLAIMED, call, params.optString("vendorId"), params.optString("productId"));
}
break;
@@ -473,7 +476,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
usb.setStreaming(false);
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("USB Device [v:%s p:%s] is not streaming data.", params.opt("vendorId"), params.opt("productId")));
+ sendError(session, UID,USB_NOT_STREAMING, call, params.optString("vendorId"), params.optString("productId"));
}
break;
@@ -487,7 +490,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
sendResult(session, UID, null);
} else {
- sendError(session, UID, String.format("USB Device [v:%s p:%s] is not claimed.", params.opt("vendorId"), params.opt("productId")));
+ sendError(session, UID, USB_NOT_CLAIMED, call, params.optString("vendorId"), params.optString("productId"));
}
break;
@@ -504,7 +507,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
FileUtilities.setupListener(fileIO);
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Already listening to path events");
+ sendError(session, UID, FILE_ALREADY_LISTENING);
}
break;
@@ -523,7 +526,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
connection.removeFileListener(absPath);
sendResult(session, UID, null);
} else {
- sendError(session, UID, "Not already listening to path events");
+ sendError(session, UID, FILE_NOT_LISTENING);
}
}
@@ -539,11 +542,11 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
sendResult(session, UID, new JSONArray(files));
} else {
log.error("Failed to list '{}' (not a directory)", absPath);
- sendError(session, UID, "Path is not a directory");
+ sendError(session, UID, FILE_NOT_DIRECTORY);
}
} else {
log.error("Failed to list '{}' (does not exist)", absPath);
- sendError(session, UID, "Path does not exist");
+ sendError(session, UID, FILE_PATH_NOT_EXIST);
}
break;
@@ -555,11 +558,11 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
sendResult(session, UID, new String(Files.readAllBytes(absPath)));
} else {
log.error("Failed to read '{}' (not readable)", absPath);
- sendError(session, UID, "Path is not readable");
+ sendError(session, UID, FILE_PATH_NOT_READABLE);
}
} else {
log.error("Failed to read '{}' (does not exist)", absPath);
- sendError(session, UID, "Path does not exist");
+ sendError(session, UID, FILE_PATH_NOT_EXIST);
}
break;
@@ -581,7 +584,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
sendResult(session, UID, null);
} else {
log.error("Failed to remove '{}' (does not exist)", absPath);
- sendError(session, UID, "Path does not exist");
+ sendError(session, UID, FILE_PATH_NOT_EXIST);
}
break;
@@ -619,7 +622,7 @@ private void processMessage(Session session, JSONObject json, SocketConnection c
break;
case INVALID:
default:
- sendError(session, UID, "Invalid function call: " + json.optString("call", "NONE"));
+ sendError(session, UID, INVALID_FUNCTION_CALL, json.optString("call", "NONE"));
break;
}
}
@@ -687,13 +690,22 @@ public static void sendResult(Session session, String messageUID, Object returnV
* @param messageUID ID of call from web API
* @param ex Exception to get error message from
*/
- public static void sendError(Session session, String messageUID, Exception ex) {
- String message = ex.getMessage();
- if (message == null || message.isEmpty()) {
- message = ex.getClass().getSimpleName();
+ public static void sendError(Session session, String messageUID, WebsocketError errorType, Exception ex) {
+ try {
+ log.error(errorType.format(ex));
+ JSONObject reply = new JSONObject();
+ reply.putOpt("uid", messageUID);
+ reply.put("errorId", errorType.getId());
+ reply.put("error", errorType.format(ex));
+ send(session, reply);
}
+ catch(JSONException e) {
+ log.error("Send error failed", e);
+ }
+ }
- sendError(session, messageUID, message);
+ public static void sendError(Session session, String messageUID, Exception ex) {
+ sendError(session, messageUID, UNHANDLED, ex);
}
/**
@@ -701,13 +713,15 @@ public static void sendError(Session session, String messageUID, Exception ex) {
*
* @param session WebSocket session
* @param messageUID ID of call from web API
- * @param errorMsg Error from method call
+ * @param errorType Preestablished WebSocketError matching Method Call
*/
- public static void sendError(Session session, String messageUID, String errorMsg) {
+ public static void sendError(Session session, String messageUID, WebsocketError errorType, String ... args) {
try {
+ log.warn(errorType.format(args));
JSONObject reply = new JSONObject();
reply.putOpt("uid", messageUID);
- reply.put("error", errorMsg);
+ reply.put("errorId", errorType.getId());
+ reply.put("error", errorType.format(args));
send(session, reply);
}
catch(JSONException e) {
@@ -715,6 +729,28 @@ public static void sendError(Session session, String messageUID, String errorMsg
}
}
+ /**
+ * Send JSON error reply to web API for call {@code messageUID}
+ *
+ * @param session WebSocket session
+ * @param messageUID ID of call from web API
+ * @param errorType Preestablished WebSocketError matching Method Call
+ */
+ public static void sendError(Session session, String messageUID, WebsocketError errorType, SocketMethod method, String ... args) {
+ try {
+ log.warn(errorType.format(args));
+ JSONObject reply = new JSONObject();
+ reply.putOpt("uid", messageUID);
+ reply.put("errorId", errorType.getId());
+ reply.put("error", errorType.format(method, args));
+ send(session, reply);
+ }
+ catch(JSONException e) {
+ log.error("Send error failed", e);
+ }
+ }
+
+
/**
* Send JSON data to web API, to be retrieved by callbacks.
* Used for data sent apart from API calls, since UID's correspond to a single response.
diff --git a/src/qz/ws/SocketConnection.java b/src/qz/ws/SocketConnection.java
index dbadd164d..bcdf14019 100644
--- a/src/qz/ws/SocketConnection.java
+++ b/src/qz/ws/SocketConnection.java
@@ -31,8 +31,8 @@ public class SocketConnection {
// absolute path -> open file listener
private final HashMap openFiles = new HashMap<>();
- // DeviceOptions -> open DeviceIO
- private final HashMap openDevices = new HashMap<>();
+ // UsbOptions -> open DeviceIO
+ private final HashMap openDevices = new HashMap<>();
public SocketConnection(Certificate cert) {
@@ -129,19 +129,19 @@ public void removeAllFileListeners() {
}
- public void addDevice(DeviceOptions dOpts, DeviceIO io) {
+ public void addDevice(UsbOptions dOpts, DeviceIO io) {
openDevices.put(dOpts, io);
}
- public DeviceIO getDevice(DeviceOptions dOpts) {
+ public DeviceIO getDevice(UsbOptions dOpts) {
return openDevices.get(dOpts);
}
- public void removeDevice(DeviceOptions dOpts) {
+ public void removeDevice(UsbOptions dOpts) {
openDevices.remove(dOpts);
}
- public synchronized void openDevice(DeviceIO device, DeviceOptions dOpts) throws DeviceException {
+ public synchronized void openDevice(DeviceIO device, UsbOptions dOpts) throws UsbException {
device.open();
if (device.isOpen()) {
addDevice(dOpts, device);
@@ -151,7 +151,7 @@ public synchronized void openDevice(DeviceIO device, DeviceOptions dOpts) throws
/**
* Explicitly closes all open serial and usb connections setup through this object
*/
- public synchronized void disconnect() throws SerialPortException, DeviceException, IOException {
+ public synchronized void disconnect() throws SerialPortException, UsbException, IOException {
log.info("Closing all communication channels for {}", certificate.getCommonName());
for(SerialIO sio : openSerialPorts.values()) {