I'm newer in Java Card Platform so please be patient with me. I'm trying to develop an RMI application for the Java Card 3 Platform. My IDE is Eclipse and my OS is Windows 10. I start by creating a simple interface IContor.java responsible for increasing, decreasing, etc. certain values.
Here is my interface:
package sid;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javacard.framework.UserException;
public interface IContor extends Remote{
public void Incrementer()throws RemoteException,UserException;
public void Decrementer()throws RemoteException,UserException;
public byte GetValue()throws RemoteException,UserException;
public void Init(byte value)throws RemoteException,UserException;
}
Then I provide an implementation for this interface which I named Contor.java:
package sid;
import java.rmi.RemoteException;
import javacard.framework.UserException;
import javacard.framework.service.CardRemoteObject;
public class Contor extends CardRemoteObject implements IContor {
private byte contor = 0;
#Override
public void Incrementer() throws RemoteException, UserException {
++contor;
}
#Override
public void Decrementer() throws RemoteException, UserException {
--contor;
}
#Override
public byte GetValue() throws RemoteException, UserException {
return contor;
}
#Override
public void Init(byte value) throws RemoteException, UserException {
contor = value;
}
}
My Test applet worked ok. Below I wrote that peace of code:
package sid;
import javacard.framework.*;
import javacard.framework.service.Dispatcher;
import javacard.framework.service.RMIService;
public class Test extends Applet {
Dispatcher dispatcher;
public static void install(byte[] bArray, short bOffset, byte bLength) {
new Test().register();
}
protected Test() {
RMIService rmiService = new RMIService(new Contor());
dispatcher = new Dispatcher((short)1);
dispatcher.addService(rmiService,Dispatcher.PROCESS_COMMAND);
}
#Override
public void process(APDU apdu) {
dispatcher.process(apdu);
}
}
This is a standard piece of code. However I want to create a client which uses that interface which implements the interface Remote. So I create a Java application in which I copied the IContor.java interface. Then I opened a command prompt and do the following things:
Go into the directory where the source files of the first project is located (cd bla_bla/Contor/src)
Go a directory up (cd ..)
Go into bin directory (cd bin)
Here I have located the name of the package ( sid) and into package sid I have those three files (Contor.class, IContor.class and Test.class).
Then I typed the following command on the command prompt:
rmic -v1.2 -classpath .;%JC_CLASSIC_HOME%lib/tools.jar -sid/Contor
but I got the following error:
Class javacard.framework.service.CardRemoteObject not found in class sid.Contor.
I replace the tools.jar with api_classic.jar but I still get the same error .
The %JC_CLASSIC_HOME% contains the path to the Java Card 3 development kit. tools.jar contains compiled implementations of packages javacard.framework, javacard.security, javacardx.biometry, javacardx.external and javacardx.framework.tlv . My bout is to generate a client application in bin/sid directory.My %JC_CLASSIC_HOME% value is C:\Program Files (x86)\Oracle\Java Card Development Kit 3.0.5ga\ and I'm using JDK 1.8
Here is my Package Explorer from Eclipse :
What does the error "Class javacard.framework.service.CardRemoteObject not found in class sid.Contor." mean?
This means that you reference the class CardRemoteObject from within your class Contor (as Contor extends CardRemoteObject). However, the class path that you use to compile the RMI stub does not contain this class.
The class javacard.framework.service.CardRemoteObject is located in lib/api_classic.jar. Hence, the correct class path for the Java Card Classic API (which is what you need to generate the stub class for RMI) is lib/api_classic.jar. lib/tools.jar is the Java archive that you later need to compile your client applications against. lib/tools.jar only contains the Java Card related exception classes. However, for compiling the remote interface stub you need the whole Java Card API (at least those classes that are referenced from your interface classes).
How does -classpath work?
The parameter -classpath is a list of directories and/or Java archives (.jar files) that contain all the relevant classes to compile a given Java source file (for javac, the Java compiler) or to compile an RMI interface stub from a given Java class file (for rmic, the Java RMI compiler).
For instance, the parameter -classpath .;"%JC_CLASSIC_HOME%/lib/api_classic.jar" specifies two paths (multiple paths are separated by semicolons (";")):
. specifies the current directory (in your case the bin directory).
"%JC_CLASSIC_HOME%/lib/api_classic.jar" specifiees the Java archive api_classic.jar from your Java Card Development Kit.
Within those paths, classes are organized in directories mapping to the components of the Java package names (e.g. a class sid.Contor would be located in a file sid/Contor.class; a class javacard.framework.service.CardRemoteObject would be located in a file javacard/framework/service/CardRemoteObject.class).
How to compile the RMI stub?
Goto your src directory.
Compile the Java classes of the applet. In your case, you could use something like:
javac -classpath .;"%JC_CLASSIC_HOME%/lib/api_classic.jar" -d ../bin sid/IContor.java sid/Contor.java sid/Test.java
Goto your bin directory: cd ../bin
Compile the Java RMI stub. In your case, you could use something like:
rmic -v1.2 -classpath .;"%JC_CLASSIC_HOME%/lib/api_classic.jar" sid.Contor
The class must be specified without a trailing dash ("-") and using dots (".") instead of slashes ("/"). If the value of the environment variable JC_CLASSIC_HOME contains spaces, you need to surround the whole path of the api_classic.jar file with quotation marks.
Related
I've the following two source files
File World.java
package planets;
public class World {
public static void main(String[] args) {
Mars.land();
}
}
File Moon.java
package planets;
public class Moon {
public static void land() {
System.out.println("Hello Moon");
}
}
class Mars {
public static void land() {
System.out.println("Hello Mars");
}
}
As we can see, the Moon.java contains two classes: the public Moon class and the nonpublic Mars class.
The files are located inside planets directory, below is showed the directory tree
+current-dir:
+----+planets:
+----+World.java
+----+Moon.java
Now, if I try to compile from Windows command prompt (I'm inside current-dir folder) typing
javac planets\World.java
I receive this error message:
planets\World.java:5: error: cannot find symbol
Mars.land();
^
symbol: variable Mars
location: class World
1 error
It's very strange, because I know that the compiler searches for nonpublic classes inside all the source files of the current package.
Also Cay Horstmann's Core Java Vol 1, 10th ed. at pp. 192-193 says that:
[...]you can import nonpublic classes from the current package. These
classes may be defined in source files with different names. If you
import a class from the current package, the compiler searches all
source files of the current package to see which one defines the
class.
In addition I tried to write these files using Eclipse Oxygen and it compile without problems. But I know that Eclipse use a different compiler.
Why does javac compiler fail?
EDIT: I have not set CLASSPATH variable. So by default compiler looks inside current directory.
you need to type the following commands in order (inside your 'current-dir')
javac planets\Moon.java
javac -cp . planets\World.java
java -cp . planets.World
This is first of my question .I have got two classes and an interface .i am not able to compile the following code.Can anyone please help we out why the code is not compiling and running.
public interface Animals {
public void run();
public void eat();
public void excreate();
public void mate();
}
public abstract class Mammals implements Animals {
public void run() {
System.out.println("Run with Four Legs");
}
public void eat() {
System.out.println("Eat Grass");
}
public void excreate() {
System.out.println("Excreate Excreata");
}
public void mate() {
System.out.println("Mammals Mate with a Mammal");
}
public abstract void giveBirth();
}
public class Horse extends Mammals {
public void mate() {
System.out.println("Horse Mates With A Mare");
}
public void giveBirth() {
System.out.println("Giving Birth To Foal");
}
public static void main(String[] args) {
Horse h1 = new Horse();
h1.eat();
h1.run();
h1.mate();
h1.giveBirth();
}
}
The Animal code Compiles successfully while the mammals and Horse class is not compiling .
The error is attached in the screen shot below
scrren1
The issue is that you're compiling files one by one, and javac can't find Animals when compiling Mammals. From the javac docs,
When compiling a source file, the compiler often needs information about a type whose definition did not appear in the source files given on the command line.
When the compiler needs type information, it looks for a source file or class file which defines the type. The compiler searches for class files first in the bootstrap and extension classes, then in the user class path (which by default is the current directory). The user class path is defined by setting the CLASSPATH environment variable or by using the -classpath command line option. (For details, see Setting the Class Path).
If you set the -sourcepath option, the compiler searches the indicated path for source files; otherwise the compiler searches the user class path for both class files and source files.
As you can see from your screenshot, the directory you're compiling in isn't being searched for source or class files. javac is effectively unaware of what Animals is.
You can either set the source path/class path to contain your source folder or directly compile multiple source files, as the javac docs show:
Compiling Multiple Source Files
This example compiles all the source files in the package greetings.
C:\>dir /B
greetings
C:\>dir greetings /B
Aloha.java
GutenTag.java
Hello.java
Hi.java
C:\>javac greetings\*.java
C:\>dir greetings /B
Aloha.class
Aloha.java
GutenTag.class
GutenTag.java
Hello.class
Hello.java
Hi.class
Hi.java
I have successfully compiled this file and saved.
class A
{
public static void main(String[] args)
{
System.out.println("Hey!");
}
}
using
javac a.java
java A
but when I compile this file:
package B;
class A
{
public static void main(String[] args)
{
System.out.println("Hey!");
}
}
now, again using the same commands it do compile but never run
javac a.java
java A
// could not find or load main class
Please guide me the exact command for the terminal to run the file.
Note: The file is named "a.java".
You need to specify the fully-qualified name, i.e. packageName.ClassName:
java B.A
you have to change the directory to the directory wich contains the path 'B' (your package name) and than call java B.A
As mentioned above, You need to specify the fully-qualified name, i.e. packageName.ClassName:
>> javac a.java
>> java B.A
But you need to create the directory named "packageName" yourself as jdk does not create one for you implicitly.
I can't get the Service Provider Interface to load an implementation from another JAR in the same directory. It only works when I use -Djava.ext.dirs=. on the command line. Should it not work without?
I have the following interface:
package playground;
public interface TestIface {
public String test();
}
which is implemented here:
package playground;
public class TestImpl implements TestIface {
public String test() {
return "TEST";
}
}
Here I try to load the implementation:
package playground;
import java.util.Iterator;
import java.util.ServiceLoader;
public class Lalala {
public static void main(String[] args) {
ServiceLoader<TestIface> loader = ServiceLoader.load(TestIface.class);
Iterator<TestIface> it = loader.iterator();
while (it.hasNext()) {
TestIface a = it.next();
System.out.println(a.test());
}
System.out.println("DONE");
}
}
The interface and the last class are packaged in main.jar, the implementation in impl.jar.
main.jar has the Main class set and impl.jar has the META-INF/services/playground.TestIface file which contains "playground.TestImpl". Both JARs are in the same directory.
Running
java -jar main.jar
only prints "DONE", the implementation apparently is not found.
If I instead run
java -Djava.ext.dirs=. -jar main.jar
it also prints "TEST" as it should.
What am I doing wrong? Why is the implementation from the other JAR not loaded unless I change the java.ext.dirs setting?
The java.ext.dirs setting automatically adds all jar-files found in the specified directory to the main classloader, which is why the ServiceLoader can find and load TestIface.class (from the Apidocs: "Creates a new service loader for the given service type, using the current thread's context class loader.").
But you should not use java.ext.dirs for this (see here for one of the dangers). And when you use java -jar you cannot use java -cp to set a classpath (you can only use one of them). This leaves you the option to use the URLClassLoader to load additional jars and then call ServiceLoader.load(class from another jar).
Tip: to load other jar-files, use the location of the main.jar file as explained in the answers of this question. Other variables (like startup directory) depend on how and from where Java was started and can easily result in not finding the other jar-files.
When preparing for the SCJP exam, we were going through the following code:
package certificaton;
public class OtherClass
{
public void testIt()
{
System.out.println("otherclass");
}
}
And this:
package somethingElse;
import certification.OtherClass;
public class AccessClass
{
public static void main( String args[])
{
OtherClass o= new OtherClass();
o.testIt();
}
}
I placed both the above files in the following directory: C:\scjp\temp8 ; and the strange thing is that, the .java files are compiling and results in two .class files being created in the same directory. The thing I want to ask, is that, the difference between packages and directory. Isn't it true that the class files could be created in a directory other than the one stated in the package declaration? And the package declaration is something 'virtual', and disregards the windows directory structure. In addition, isn't it also true that, by executing the following command:
javac -d . OtherClass.java
The directories are created conforming to the package declaration, which isn't always mandatory?
The directories are created conforming
to the package declaration, which
isn't always mandatory?
No, the package and directory structures must match. It's mandatory, not optional.