问题
I've been tearing my hair out for several days now trying to figure out just why the heck this never seems to work! First off, here is my config:
Windows 7 x64
JDK 7 x86
JRE 7 x86
Firefox x86
Rails 3 served by Thin
Java settings are such that the "next generation plugin" isn't active (but it keeps reactivating itself somehow!!!)
At first I tried RXTX but I kept on getting "no class found" errors. I've now moved on to winjcom. The error I'm now getting is this: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "loadLibrary.winjcom")
.
I've also noticed that my server logs vary depending on what browser I'm using. If I used Firefox, no GET logs are displayed when the browser attempts to load the applet (i.e., nothing further is downloaded when the applet load fails). If I try in IE9, all the logs are there except for the "PortWriter.class" GET log...which means it isn't being retrieved for some reason.
When I avoid using JNLP I get the security warning popup and there aren't any errors...except of course for the security access error when I run the "Sends" method. However when I DO use the JNLP, IE loads it fine and still gives the error...but crashes when I close it (I have to end the iexplorer process). Firefox just doesn't load the page...it stalls at the progress bar.
UPDATE - I have things to the point where if I bypass security through java's security policy file the applet will work. However, the JNLP won't work - which I think is why normally the security error occurs when running through the applet tag. When I access the JNLP file directly, I get an error stating it can't find the "PortWriter" class. Is there something wrong with my jar? I've noticed that other jars have their folder layouts such that the directory structure exactly matches their package layout (ex., "com\myname\serialport\PortWriter.jar" if the package were to be com.myname.serialport.PortWriter). However MY jar layout replicates my physical folder layout (ex., "D:\Files\Websites\pos\assets\java\PortWriter.jar"). Is this what's causing the error? I've manually changed the jar contents (including the manifest files) to match to root but maybe I've done something wrong. I've also updated my JNLP layout in this problem to illustrate my latest changes which were verified by JaNeLa.
This is my .java file:
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();
}
}
}
}
...and my JNLP file:
<?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>
...and my HTML:
<applet id="SerialPort" width="1" height="1" codebase="/assets/" code="PortWriter.class" archive="PortWriter.jar">
<param name="jnlp_href" value="PortWriter.jnlp" />
</applet>
How do I get this stuff to work? I'm a Java newb but I just want to get a working solution. This is for my company's POS which I'm making in Rails.
Final files are:
On server at /assets/java/:
1) jcomport.jar (not signed...)
2) PortWriter.class (and all associated class files)
3) PortWriter.jar
4) PortWriter.jnlp
On local hd at %java home%/
1) /lib/ext/jcomport.jar (not signed)
2) /bin/winjcom.dll
回答1:
Well holy everlasting crap. Upon originally deciding to turn off the "next generation plug-in" option in the Java console with the intent of making my applet work in Firefox, I've inadvertently disabled JNLP. I only found this out by a last resort effort to "try something...ANYTHING". After turning it back on, the jnlp runs perfectly in IE. Firefox is of course the browser I need to use for my POS (because of a jsprint addon)...but of course it's not working. It won't download the JNLP file or if it is, something's going wrong. It just hangs. Nothing shows up, but my server logs say all the images and html is being downloaded. Not the jnlp or any of the jar files though. So it's either turn off the next generation plug-in and have security issues or turn it on and not be able to use Firefox. Is there ANYTHING I can do without having to resort to changing the policy file?
FWIW, I'll mark this as the solution and start a new thread somewhere else about my latest problem. Here's the most updated contents for everything needed to get the damned thing working (except in Firefox):
First off, make sure the PATH and CLASSPATH environment variables are set in Windows. PATH should be C:\Program Files (x86)\Java\jdk1.7.0_01\bin
(change to your own jdk directory if you have a different version). CLASSPATH should be wherever you make your java classes. Mine is D:\Files\Java\Classes
. If you don't set the PATH variable, you can't run 'java', 'javac' or 'jarsigner' from any directory. You'd have to be in the bin directory of jdk. Make these variables for your User account...not System (as there could already be env variables named like these).
Next, for signing your applets, create your keystore:
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
Check online tutorials to make sure you know what each of these arguments are for.
.BAT file I made to easily create necessary .jar file from .java file and sign it. Just make a shortcut or run the .bat file instead of having to do this by hand every time you make a change to the .java file
@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 (make sure there is a carriage return after the "Main-Class" line. You shouldn't need this Manifest.txt file if you want to specify the main-class in your JNLP.): Main-Class: mycompany.PortWriter
Java File:
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 File:
<?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>
I had taken the winjcom.dll file and "jarred" it and signed it with the same certfile. I made sure to cd to the same directory in which winjcom was so that it would be in the root of the .jar file. I also took the jcomport.jar file provided by the author of winjcom and re-signed it with the same certfile. That being said, all .jar files have been signed by the same certfile.
I hope this helps out anyone who's having as much trouble as I did.
回答2:
In order to use Java's package (which is recommended) place PortWriter.java inside java/x/y/z and have a first line:
package x.y.z;
Everywhere use as class name:
x.y.z.PortWriter
On the server I would expect only a jar with the PortWriter class. You can add some Test.java without DLL usage, to see that it works.
来源:https://stackoverflow.com/questions/7998523/just-trying-to-write-data-to-a-serial-port-from-a-java-applet