Просто пытаетесь записать данные в последовательный порт из Java-апплета? - PullRequest
3 голосов
/ 03 ноября 2011

Я рвал на себе волосы уже несколько дней, пытаясь понять, почему, черт возьми, это никогда не работает!Во-первых, вот мой конфиг:

Windows 7 x64
JDK 7 x86
JRE 7 x86
Firefox x86
Rails 3, обслуживаемые Thin
Настройки Java таковы, что«Плагин следующего поколения» не активен (но он продолжает каким-то образом снова активироваться !!!)

Сначала я попробовал RXTX, но продолжал получать ошибки «класс не найден».Теперь я перешел на winjcom.Ошибка, которую я сейчас получаю, такова: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "loadLibrary.winjcom").

Я также заметил, что журналы моего сервера различаются в зависимости от того, какой браузер я использую.Если я использовал Firefox, журналы GET не отображаются, когда браузер пытается загрузить апплет (т. Е. Больше ничего не загружается при сбое загрузки апплета).Если я попытаюсь в IE9, там будут все журналы, кроме журнала GET «PortWriter.class» ... что означает, что он не получен по какой-то причине.

Когда я избегаю использования JNLP, я получаювсплывающее предупреждение о безопасности и никаких ошибок ... за исключением, конечно, ошибки доступа к безопасности, когда я запускаю метод "Отправляет".Однако, когда я действительно использую JNLP, IE загружает его нормально и все равно выдает ошибку ... но вылетает, когда я его закрываю (мне нужно завершить процесс iexplorer).Firefox просто не загружает страницу ... он останавливается на индикаторе выполнения.

ОБНОВЛЕНИЕ - У меня есть вещи до такой степени, что если я обойду безопасность через файл политики безопасности java, то апплетбуду работать.Однако JNLP не будет работать - я думаю, поэтому обычно возникает ошибка безопасности при запуске через тег апплета.Когда я получаю доступ к файлу JNLP напрямую, я получаю сообщение об ошибке, в котором говорится, что он не может найти класс «PortWriter».Что-то не так с моей банкой?Я заметил, что другие jar-файлы имеют свои макеты папок, так что структура каталогов точно соответствует их макету пакета (например, «com \ myname \ serialport \ PortWriter.jar», если пакет должен быть com.myname.serialport.PortWriter).,Однако мой макет jar повторяет мой физический макет папки (например, «D: \ Files \ Websites \ pos \ assets \ java \ PortWriter.jar»).Это то, что вызывает ошибку?Я вручную изменил содержимое jar-файла (включая файлы манифеста), чтобы он соответствовал root, но, возможно, я сделал что-то не так.Я также обновил свой макет JNLP в этой проблеме, чтобы проиллюстрировать свои последние изменения, которые были проверены JaNeLa.

Это мой файл .java:

import com.engidea.comm.CommPort;
import com.engidea.comm.CommPortIdentifier;
import com.engidea.comm.SerialPort;
import com.engidea.comm.SerialPortEvent;
import com.engidea.comm.SerialPortEventListener;
import com.engidea.win32jcom.WinjcomIdentifier;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.applet.*;
import java.security.*;

/*
  WinJcom is a native interface to serial ports in java.
  Copyright 2007 by Damiano Bolla, Jcomm@engidea.com

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  This can be used with commercial products and you are not obliged 
  to share your work with anybody.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * Simple class that can list system ports and allow IO
 */
public class PortWriter extends Applet
  {

  private CommPortIdentifier portIdentifier;
  private SerialPort serport;

  public void init () {System.out.println("Booting...");}
  @SuppressWarnings("unchecked")
  public void Sends(String port, String message) throws Exception
    {

    final String com_port = port;
    final String send_message = message;

    AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {

        System.out.println("Begin...");
        portIdentifier = new WinjcomIdentifier(0);
        System.out.println("Selecting Port...");
        selectComport(com_port);
        new Thread(new PortReader()).start();
        System.out.println("Sending...");
        typeSendBytes(send_message);

    return true;}
    });
    }

  private void typeSendBytes( String message )
    {  
    try
      {
      System.out.println("Trying To Send...");
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      String aStr = "";
      while (aStr != null) 
        {
        aStr = message + "\r\n";
        // WARNING: be careful, you shoulod select the encoding !
        // This will timeout if you have FLOW CONTROL and theline is stuck !
        byte []buf = aStr.getBytes();
        serport.write(buf,0,buf.length );
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }

  private SerialPort openPort ( String portName )
    {
    try 
      {
      CommPort aPort = portIdentifier.getCommPort(portName);
      aPort.open();
      return (SerialPort)aPort;
      }
    catch ( Exception exc )
      {
      System.out.println("exc="+exc);
      exc.printStackTrace();
      }

    return null;
    }

  private void selectComport ( String portName )
    {
    try 
      {
      serport = openPort(portName);
      serport.setSerialPortParams(9600,8, SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);
      serport.enableReceiveTimeout(20000);
      serport.setEventListener(new EventListener());

      serport.notifyOnDSR(true);
      serport.notifyOnCarrierDetect(true);
      serport.notifyOnCTS(true);
      } 
    catch (IOException exc) 
      {
      System.out.println("Exc="+exc);
      exc.printStackTrace();
      }
    }


private final class EventListener implements SerialPortEventListener
  {
  public void serialEvent(SerialPortEvent ev)
    {
    System.out.println("Got event="+ev);
    }
  }


private final class PortReader implements Runnable
  {
  public void run()
    {
    try
      {
      // This will timeout if nothing is received in the specified time.
      byte []buff = new byte[1];
      while (  serport.read(buff,0,buff.length) > 0 )
        {
        // NOTE: you should be checking the encoding !
        System.out.print(new String(buff));
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }
  }


}

... и мой JNLPfile:

<?xml version="1.0" encoding="utf-8"?>
<jnlp codebase="http://localhost/assets/" href="PortWriter.jnlp">
    <information>
        <title>RS232 Communication Applet</title>
        <vendor>My Company</vendor>
        <description>RS232 Applet for communicating with POS Display Pole</description>
        <offline-allowed />
    </information>
    <security>
    <all-permissions/>
    </security>
    <update check="background" />
    <resources>
    <jar href="PortWriter.jar" part="com" main="true" />
    <jar href="winjcom.jar" part="com" />
    <nativelib href="jcomport.jar" part="com" />
    </resources>
    <applet-desc
         name="RS232 Communication Applet"
         main-class="PortWriter"
         width="1" height="1" />
</jnlp>

... и мой HTML:

<applet id="SerialPort" width="1" height="1" codebase="/assets/" code="PortWriter.class" archive="PortWriter.jar">
        <param name="jnlp_href" value="PortWriter.jnlp" />
    </applet>

Как мне заставить этот материал работать?Я новичок в Java, но я просто хочу получить рабочее решение.Это для POS моей компании, которые я делаю в Rails.

Конечные файлы:

На сервере в / assets / java /:
1) jcomport.jar (не подписано)...)
2) PortWriter.class (и все связанные файлы классов)
3) PortWriter.jar
4) PortWriter.jnlp

На локальном жестком диске в% java home% /
1) /lib/ext/jcomport.jar (не подписано)
2) /bin/winjcom.dll

Ответы [ 2 ]

2 голосов
/ 06 ноября 2011

Ну святая вечная чушь. Первоначально решив отключить опцию «плагин следующего поколения» в консоли Java с целью заставить мой апплет работать в Firefox, я случайно отключил JNLP. Я узнал об этом только в крайнем случае, чтобы «попробовать что-нибудь ... НИЧЕГО». После включения jnlp отлично работает в IE. Firefox - это, конечно, браузер, который мне нужно использовать для моей POS (из-за аддона jsprint) ... но, конечно, он не работает. Он не будет загружать файл JNLP или, если это так, что-то идет не так. Это просто висит. Ничего не появляется, но в журналах моего сервера написано, что загружаются все изображения и HTML. Не JNLP или любой из файлов JAR, хотя. Так что либо отключите плагин следующего поколения и у вас будут проблемы с безопасностью, либо включите его и не сможете использовать Firefox. Есть ли что-нибудь, что я могу сделать, не прибегая к изменению файла политики?

FWIW, я отмечу это как решение и начну новую тему где-то еще о моей последней проблеме. Вот самое актуальное содержимое для всего, что нужно, чтобы эта проклятая вещь работала (кроме Firefox):


Прежде всего, убедитесь, что переменные окружения PATH и CLASSPATH установлены в Windows. PATH должен быть C:\Program Files (x86)\Java\jdk1.7.0_01\bin (перейдите в свой собственный каталог jdk, если у вас другая версия). CLASSPATH должен быть там, где вы делаете свои Java-классы. Мой D:\Files\Java\Classes. Если вы не установите переменную PATH, вы не сможете запустить «java», «javac» или «jarsigner» из любого каталога. Вы должны быть в каталоге bin JDK. Сделайте эти переменные для вашей учетной записи пользователя ... не для системы (так как уже могут быть переменные env с такими именами).


Далее, для подписи ваших апплетов создайте хранилище ключей:

keytool -genkey -dname "cn=My Company, ou=Whatever, o=My Company, c=CA" -alias mycompany -keystore "D:\Files\Java\Certificates\certfile" -storepass MY_PASSWORD -validity 180

Просмотрите онлайн-руководства, чтобы убедиться, что вы знаете, для чего предназначен каждый из этих аргументов.


.BAT файл, который я сделал, чтобы легко создать необходимый файл .jar из файла .java и подписать его. Просто сделайте ярлык или запустите файл .bat вместо того, чтобы делать это вручную каждый раз, когда вы вносите изменения в файл .java

@echo off

set certificate_password=MY_PASSWORD
set certificate_alias=myalias
set package=mycompany
set class_file=PortWriter
rem class_path is where my .java file resides (...\java\Classes\mycompany\PortWriter.java)
set class_path=D:\Files\Java\Classes
set certificate_loc=D:\Files\Java\Certificates\certfile
rem final_loc is the assets folder where the .jar file will reside
set final_loc=D:\Files\Websites\pos\app\assets\java

cd "%class_path%"
rem Change to "D:" otherwise Windows won't *actually* change directories from C: to D:
D:

javac -Xlint:unchecked "%package%\%class_file%.java"
pause
jar cfm "%final_loc%\%class_file%.jar" "%package%\Mainfest.txt" "%package%\*.class"
pause
del "%package%\*.class"
jarsigner -keystore "%certificate_loc%" -storepass %certificate_password% "%final_loc%\%class_file%.jar" %certificate_alias%
pause

Mainfest.txt (убедитесь, что после строки «Main-Class» есть возврат каретки. Вам не нужен этот файл Manifest.txt, если вы хотите указать основной класс в вашем JNLP.): Основной класс: mycompany.PortWriter


Файл Java:

package mycompany;

import com.engidea.comm.CommPort;
import com.engidea.comm.CommPortIdentifier;
import com.engidea.comm.SerialPort;
import com.engidea.comm.SerialPortEvent;
import com.engidea.comm.SerialPortEventListener;
import com.engidea.win32jcom.WinjcomIdentifier;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.applet.*;
import java.security.*;

/*
  WinJcom is a native interface to serial ports in java.
  Copyright 2007 by Damiano Bolla, Jcomm@engidea.com

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  This can be used with commercial products and you are not obliged 
  to share your work with anybody.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * Simple class that can list system ports and allow IO
 */
public class PortWriter extends Applet {

    private CommPortIdentifier portIdentifier;
    private SerialPort serport;

    public static void main(String[] args) {}
    public void init() {
    System.out.println("Booting RS232 Java Applet...");
    }

    public void Sends(String port, String message) {

    final String com_port = port;
    final String send_message = message;

    AccessController.doPrivileged(new PrivilegedAction<Object>() {
        public Object run() {

        try {
            portIdentifier = new WinjcomIdentifier(0);
            try {
            selectComport(com_port);
            new Thread(new PortReader()).start();
            try {
                System.out.println(com_port + ": " + send_message);
                typeSendBytes(send_message);
            } catch (Exception e) {
                System.out.println("Couldn't send data to " + com_port);
            }
            } catch (IOException e) {
            System.out.println("Couldn't connect to " + com_port);
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
        }
    });
    }

    private void typeSendBytes( String message ) {  
    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String aStr = "";
        if (aStr != null) {
        aStr = message + "\r\n";
        // WARNING: be careful, you shoulod select the encoding !
        // This will timeout if you have FLOW CONTROL and theline is stuck !
        byte []buf = aStr.getBytes();
        serport.write(buf,0,buf.length);
        }
    } catch ( Exception exc ) {
        exc.printStackTrace();
    }
    }

    private SerialPort openPort ( String portName ) throws IOException {
    try {
        CommPort aPort = portIdentifier.getCommPort(portName);
        aPort.open();
        return (SerialPort)aPort;
    }
    catch ( Exception exc ) {
        //System.out.println("exc="+exc);
        //exc.printStackTrace();
        throw exc;
    }
    }

    private void selectComport ( String portName ) throws IOException {

    try {
        serport = openPort(portName);
        serport.setSerialPortParams(9600,8, SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);
        serport.enableReceiveTimeout(20000);
        serport.setEventListener(new EventListener());

        serport.notifyOnDSR(true);
        serport.notifyOnCarrierDetect(true);
        serport.notifyOnCTS(true);
    } catch (IOException exc) {
        //System.out.println("Exc="+exc);
        //exc.printStackTrace();
        throw exc;
    }

    }


private final class EventListener implements SerialPortEventListener
  {
  public void serialEvent(SerialPortEvent ev)
    {
    System.out.println("Got event="+ev);
    }
  }


private final class PortReader implements Runnable
  {
  public void run()
    {
    try
      {
      // This will timeout if nothing is received in the specified time.
      byte []buff = new byte[1];
      while (  serport.read(buff,0,buff.length) > 0 )
        {
        // NOTE: you should be checking the encoding !
        System.out.print(new String(buff));
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }
  }


}

Файл JNLP:

<?xml version="1.0" encoding="utf-8"?>
<jnlp>
    <information>
        <title>RS232 Communication Applet</title>
        <vendor>My Company</vendor>
        <description>RS232 Applet for communicating with POS Display Pole</description>
        <offline-allowed />
    </information>
    <security>
    <all-permissions/>
    </security>
    <resources>
    <j2se version="1.7.0+" />
    <jar href="PortWriter.jar" part="com" main="true" />
    <jar href="jcomport.jar" part="com" />
    <nativelib href="winjcom.jar" part="com" />
    </resources>
    <applet-desc
         name="RS232 Communication Applet"
         main-class="mycompany.PortWriter"
         width="1" height="1" />
</jnlp>

HTML:

<applet id="SerialPort" width="1" height="1" codebase="/assets/">
    <param name="jnlp_href" value="PortWriter.jnlp">
</applet>

Я взял файл winjcom.dll, «собрал» его и подписал тем же сертификатом. Я удостоверился, что cd находится в том же каталоге, в котором находится winjcom, чтобы он находился в корне файла .jar. Я также взял файл jcomport.jar, предоставленный автором winjcom, и переподписал его тем же сертификатом. При этом все файлы .jar были подписаны одним и тем же сертификатом.

Надеюсь, это поможет всем, у кого столько же проблем, сколько и у меня.

0 голосов
/ 04 ноября 2011

Чтобы использовать пакет Java (что рекомендуется), поместите PortWriter.java внутри java / x / y / z и введите первую строку:

package x.y.z;

Везде, где используется имя класса:

x.y.z.PortWriter

На сервере я бы ожидал только jar с классом PortWriter.Вы можете добавить Test.java без использования DLL, чтобы убедиться, что он работает.

...