尝试声明已声明的打印机时 JVM 崩溃 JavaPOS EPSON 热敏打印机

JVM crashes when trying to claim a claimed printer JavaPOS EPSON Thermal Printer

我正在使用 Epson_JavaPOS_ADK_11414_for_Linux_x64 安装 JavaPOS with pcs ( sh installJavaPOSFull-64.sh )

我运行这个程序在不同的shell中一个接一个地运行,第二个进程由于某种原因崩溃:

import jpos.JposException;
import jpos.POSPrinter;
import jpos.util.JposPropertiesConst;

import java.time.Duration;
import java.time.Instant;

public class POSPrinterClaimTest {
  static POSPrinter posPrinter;

  private static Boolean isOpen = false;
  private static Boolean isClaimed = false;
  private static Boolean isEnabled = false;



  static {
    System.setProperty(
        JposPropertiesConst.JPOS_POPULATOR_FILE_PROP_NAME, "jpos.xml");
  }

  public static void main(String[] args) {
    try {
      posPrinter = new POSPrinter();
      Instant start = Instant.now();
      Instant finish = null;
      Long timeElapsed = null;
      openConnection("POSPrinter1");
      finish = Instant.now();
      timeElapsed = Duration.between(start, finish).toMillis();
      System.out.println("Time taken to connect : " + timeElapsed.toString());
      Thread.sleep(100000L);
      terminate();
      System.out.println("terminated from try block");
    } catch (JposException | InterruptedException e) {
      e.printStackTrace();
      try {
        terminate();
        System.out.println("terminated from catch block");
        Thread.sleep(5000);
      } catch (JposException | InterruptedException jposException) {
        jposException.printStackTrace();
      }
    } catch(Throwable t){
      t.printStackTrace();
    } finally {
      posPrinter = null;
    }
  }

  private static void openConnection(String printerName) throws JposException {
    try {

      String printerNamesss = printerName;
      /**
       * open the printer object according to the device logical name defined in jpos.xml
       */
      posPrinter.open(printerName);
      isOpen = true;
      System.out.println("opened");
      /**
       * Get the exclusive control right for the opened device.
       * Then the device is disable from other application.
       * */
      posPrinter.claim(3000);
      isClaimed = true;
      System.out.println("claimed");
      /**
       *  enable the device for input and output
       */
      posPrinter.setDeviceEnabled(true);
      isEnabled = true;
      System.out.println("enabled");

    } catch (JposException jposException) {
      System.out.println("jpos exception in open : " + jposException.getMessage());
      throw jposException;
    } catch(Throwable t) {
      System.out.println("unknown throwable open: " + t.getMessage());
    }
  }


  public static void terminate() throws JposException {
    try {
        if(isOpen && isClaimed) {
          posPrinter.clearOutput();
          System.out.println("cleared output");
        }

        if(isEnabled) {
          posPrinter.setDeviceEnabled(false);
          isEnabled = false;
          System.out.println("setDeviceEnabled false");
        }

        if(isClaimed) {
          posPrinter.release();
          isClaimed = false;
          System.out.println("released");
        }

        if(isOpen) {
          posPrinter.close();
          isOpen = false;
          System.out.println("closed");
        }
    } catch (JposException jposException) {
      jposException.printStackTrace();
      throw jposException;
    } catch(Throwable t) {
      System.out.println("unknown throwable terminate: " + t.getMessage());
    }
  }
}


第一个过程输出

opened
claimed
enabled
Time taken to connect : 7928 --> now I start the second process.
cleared output
setDeviceEnabled false
released
closed
terminated from try block

第二个过程输出

opened
jpos exception in open : The port is already open.
jpos.JposException: The port is already open.
    at jp.co.epson.upos.core.v1_14_0001.pntr.CommonUPOSExceptionCreator.createJposException(CommonUPOSExceptionCreator.java:138)
    at jp.co.epson.upos.core.v1_14_0001.pntr.CommonUPOSExceptionCreator.createJposException(CommonUPOSExceptionCreator.java:99)
    at jp.co.epson.upos.core.v1_14_0001.pntr.CommonPrinterService.openPort(CommonPrinterService.java:3341)
    at jp.co.epson.upos.core.v1_14_0001.pntr.CommonPrinterService.claim(CommonPrinterService.java:3103)
    at jpos.BaseJposControl.claim(Unknown Source)
    at POSPrinterClaimTestThreads.openConnection(POSPrinterClaimTestThreads.java:73)
    at POSPrinterClaimTestThreads.test(POSPrinterClaimTestThreads.java:36)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
closed
terminated from catch block
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f43880ea9df, pid=12119, tid=0x00007f43690b0700
#
# JRE version: OpenJDK Runtime Environment (8.0_252-b09) (build 1.8.0_252-b09)
# Java VM: OpenJDK 64-Bit Server VM (25.252-b09 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libethernetio31.so+0x1f9df]  CCommonPort::PortEvent(unsigned int, unsigned int, unsigned int*, unsigned int, unsigned char*)+0xf
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /POSPrinterTest/JavaPOS/hs_err_pid12119.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
Aborted

如果您看到第二个进程抛出 JposException,然后启动它的捕获并关闭连接。然后它突然崩溃而不是休眠 5 秒。

有什么帮助吗?

看来JavaPOS Service Object的独占控制处理不太好

您应该收到超时错误,而不是端口已打开的错误。

不过,你的程序也很烂
一次尝试的范围太广了。

JposException采取异常的形式,但它实际上只是一个错误代码通知。
仅仅因为发出 JposException 信号并不意味着它崩溃了。
大多数情况下,如果您消除错误原因并重试,它就会成功。

为了正确起见,请尝试捕获每个方法调用和 属性 访问。

Epson_JavaPOS_ADK示例程序应该是那样做的。
请和示例程序一样编码。


另外:

你看到的有什么不同吗?
它确实为每个方法和 属性 以小单位尝试和捕获,并且不会使用 throw.
将其传播到顶部 我的一些来源是:

来自“Epson_JavaPOS_ADK_11414_for_Linux_x64\Sample\Samples\Printer\PrinterSample_Step15\src\printersample_step15\Step15Frame.java”

// JavaPOS's code for Step7
// Set OutputCompleteEvent listener
ptr.addOutputCompleteListener(this);
// JavaPOS's code for Step7--END

// JavaPOS's code for Step10
try {
    //Open the device.
    //Use the name of the device that connected with your computer.
    ptr.open("POSPrinter");

}
catch(JposException ex){
    JOptionPane.showMessageDialog(this, "This device has not been registered, or cannot use.",
            "",JOptionPane.WARNING_MESSAGE);
    //Nothing can be used.
    changeButtonStatus();
    return;
}

try {
    //Get the exclusive control right for the opened device.
    //Then the device is disable from other application.
    ptr.claim(1000);
    bCoverSensor = ptr.getCapCoverSensor();
}
catch(JposException ex){
    JOptionPane.showMessageDialog(this, "Fails to get the exclusive access for the device.",
            "",JOptionPane.WARNING_MESSAGE);
    //Nothing can be used.
    changeButtonStatus();
    return;
}

从评论中提取情况并发布:

嗯,Claim 报告的错误可能是错误的,那么为什么不联系 EPSON 支持并提供有关这种情况的详细信息呢?

来自 OP:

Done that already but we don't know if they will respond back. So trying to find answer here; somewhere. :D

来自 OP:

I ran the same program in a single process with multiple threads in two pulses. I do now get the timeout error as you said. Only in different processes scenario, I am getting a crash

如果是这样,可能是JavaPOS服务对象的进程间独占控制有问题。这就是它的问题,但正如我之前评论的那样,崩溃可能是异常结束时的清理问题。当 Claim 方法出现异常时,不是通过传播异常来结束进程,而是调用 Close 方法并尝试其他清理以正常结束。

来自 OP:

I wrote the posPrinter.close() in claim catch block. It worked and crash frequency reduced significantly when doing with two processes single threads. Still the crash happened once or twice. But in two processes each with 10 threads trying to claim printer results in one process able to claim and the other process crashing. try{ posPrinter.claim(3000); } catch(JposException ex) { posPrinter.close();}

看来EPSON的JavaPOS服务对象独占控制的问题可能依然存在。请根据此类调查信息向爱普生追加查询。

在与 EPSON 团队讨论此问题后,他们能够使用新的 libepsonjpos.so 和 epsonjpos.jar

提供相同的解决方案

它为我解决了两个问题:

  1. post 中的原始声明问题 - 使用最新的 libepsonjpos.so
  2. 后已解决
  3. 非安装模式单进程多线程打印(No-SetupPOS-insall)
    • 爱普生团队表示要在所有线程中同步 POSPrinter.open() 并使用他们的修复更新 epsonjpos.jar

爱普生团队对这个问题的引用。

多线程问题 - “更改历史记录 已应用的修复在设备共享逻辑中。仅影响精简模式(No-SetupPOS 版本) 不同的对象被错误地认为是相等的。结果只使用了第一台连接的打印机。 该修复更正了该比较逻辑。"

索赔问题 - “我们很高兴能为您提供帮助。 至于问题的背景。非安装模式下的多进程使用是我们 JavaPOS ADK 的一个极端情况。在您的帮助下,我们可以改进我们的测试用例。"

爱普生团队表示会在下个版本发布补丁