Edit: The Java™ Tutorials say that
the server and the client communicate and pass information back and
forth
and that RMI
provides mechanisms for loading an object's class definitions as well
as for transmitting an object's data.
I was hoping that "an object's data" would include a server object's variables (such as Test.value in my code, below) - but the first comments I got indicate that perhaps I was wrong. My original question follows.
I am trying to access a remote object that I am sending over RMI to a client. I am only able to access its methods, but not its instance variables - I get the interface's fields instead. My question is, once I implement and instantiate a class on a server, how do I access its [public] fields, without using getters? I am able to send a stub without any errors or exceptions, but like I said, I am not able to access the server's object's fields, only the interface's. Following is an abbreviated version of my interface, implementation, server, and client.
package test;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface TESTint extends Remote {
double value = -22;
String shortName = "TESTint";
double getValue() throws RemoteException;
}
package test;
import java.rmi.RemoteException;
public class Test implements TESTint {
public double value = -33;
public String shortName = "TestAccount";
public int whole = 1;
public Test(String shortName) {
this.shortName = shortName;
print(shortName);
}
public double getValue() throws RemoteException {
return value;
}
public void print(Object o) {
System.out.println(shortName + ": " + o);
}
}
package test;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RemoteTestMain {
Test test;
public static void main(String[] args) throws InterruptedException {
if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); }
new RemoteTestMain();
} // main
public RemoteTestMain() {
test = new Test("Charlie");
Registry registry;
try {
registry = LocateRegistry.createRegistry(1234);
registry.list( ); // will throw an exception if the registry does not already exist
print(test.shortName); // it gets it right here
print(test.value); // it gets it right here
TESTint r = (TESTint) UnicastRemoteObject.exportObject(test, 0);
registry.rebind("DCregistry", r);
print("test bound");
} catch (java.rmi.RemoteException ex) {
print("Remote Exception at Server");
ex.printStackTrace();;
}
}
public static void print(Object o) {
System.out.println("Server: " + o);
}
}
package test;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
TESTint test;
public static void main(String[] args) {
try {
new Client();
} catch (RemoteException e) {
e.printStackTrace();
}
} // main
private void init(int account) {
print("INITiating Account " + account);
try {
Registry registry = LocateRegistry.getRegistry(1234);
test = (TESTint) registry.lookup("DCregistry");
} catch (Exception e) {
System.err.println("RMI exception:");
e.printStackTrace();
}
print("Short name : " + test.shortName);
print("value: " + test.value);
try {
print("Value through getter is " + test.getValue());
} catch (RemoteException e) {
print("Could not get equity");
e.printStackTrace();
}
} // init(int account)
public Client() throws RemoteException {
if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); }
init(2);
}
private static void print(Object o) {
System.out.println("GUI: " + o);
}
}
P.S. In the Client code above, test.shortName is wiggly-underlined and Eclipse suggests that The static field TESTint.shortName should be accessed in a static way. I understand that the Client does not recognize the implementation, only the interface - but is there a way to access test's fields, not only its methods? I have many fields in my original code and I do not want to write getters for each and every one, if possible.
RMI stands for Remote Method Invocation which means that you can remotely execute a method of an object. The implementation of the method resides in the remote system. You can never access the instance variables of the implementation class which exists in the remote system even if they are public. You can only execute public methods which are exposed by the Inteface. So if you want to access the variables, you need add public gettter methods both in the Inteface and implementation class.
Related
I've tried to create a simple Client and Server applets in java card 2.2.2 using Eclipse 3.7 SDK using the Shareable Interfaces. When the method JCSystem.getAppletShareableInterfaceObject is called it throws an exception and so the return SW sets to 6F00.
This is the Client app code (Test_Client.java):
package client;
import server.Test_ServerInf;
import javacard.framework.AID;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
public class Test_Client extends Applet {
protected static final byte INS1 = (byte)0xE2;
protected static final byte INS2 = (byte)0x21;
byte[] ServerAIDbyte={(byte)0x20,(byte)0x21,(byte)0x22,(byte)0x23,(byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,(byte)0x01};
AID ServerAID;
private Test_Client() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new Test_Client().register();
}
public void process(APDU apdu) throws ISOException {
// TODO Auto-generated method stub
byte[] apduBuffer = apdu.getBuffer();
byte Ins=apduBuffer[ISO7816.OFFSET_INS];
short byteread = apdu.setIncomingAndReceive();
if (selectingApplet())
return;
switch (Ins){
case INS1:
Ins1_Handler(apdu);
return;
case INS2:
Ins2_Handler(apdu,apduBuffer);
return;
default:
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
}
}
private void Ins1_Handler(APDU apdu){
Test_ServerInf sio = null;
ServerAID=JCSystem.lookupAID(ServerAIDbyte,(short) 0,(byte) ServerAIDbyte.length);
if(ServerAID==null)
ISOException.throwIt( (short) 0x6A82);
////server request
try{
sio=(Test_ServerInf)(JCSystem.getAppletShareableInterfaceObject(ServerAID, (byte) 0));
}
catch(SecurityException e)
{
ISOException.throwIt((short)0x12);
}
catch(Exception e)
{
ISOException.throwIt((short)0x10);
}
if(sio==null)
ISOException.throwIt((short)0x6A00);
}
private void Ins2_Handler(APDU apdu,byte[] apduBuffer){
Test_ServerInf sio = null;
////connect to server
ServerAID=JCSystem.lookupAID(ServerAIDbyte,(short) 0,(byte) ServerAIDbyte.length);
if(ServerAID==null)
ISOException.throwIt( (short) 0x6A82);
////server request
try{
sio=(Test_ServerInf)(JCSystem.getAppletShareableInterfaceObject(ServerAID, (byte) 0));
}
catch(SecurityException e)
{
ISOException.throwIt((short)0x12);
}
catch(Exception e)
{
ISOException.throwIt((short)0x10);
}
if(sio==null)
ISOException.throwIt((short)0x6A00);
}
}
And this is Server applet code (Test_Server.java):
package server;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import server.Test_ServerInf;
import javacard.framework.Shareable;
import javacard.framework.AID;
public class Test_Server extends Applet implements Test_ServerInf{
private Test_Server() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new Test_Server().register();
}
public void process(APDU apdu) throws ISOException {
// TODO Auto-generated method stub
}
public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
return this;
}
public short method1(){
return (short)0x01;
}
public short method2(){
return (short)0x02;
}
}
and the shareable interface file (Test_ServerInf.java):
package server;
import javacard.framework.Shareable;
public interface Test_ServerInf extends Shareable {
public short method1();
public short method2();
}
You are trying to store a reference to the shareable interface object in a member field of your client applet class:
sio = (Test_ServerInf)(JCSystem.getAppletShareableInterfaceObject(ServerAID, (byte) 0));
where sio is defined as private member of the applet class instance:
public class Test_Client extends Applet {
private Test_ServerInf sio;
This will result in a SecurityException since the shareable interface object is owned by the server applet (i.e. by a different context). You are not allowed to store objects owned by other contexts in an instance field.
See Accessing Class Instance Object Fields (Section 6.2.8.3), in Runtime Environment Specification, Java Card Platform, Version 2.2.2:
Bytecodes: getfield, putfield
[...] if the object is owned by an applet in the currently active context, access is allowed.
Otherwise, access is denied.
I found the source of this error. I used to load and install applets using an internally developed application instead of GPShell. When I tried to load and install applets using GPShell the problem solved and everything is ok. I don't know how that application compromises the loaded package but it works fine right know (After 2 weeks of debugging).
This question already has answers here:
What are reasons for Exceptions not to be compatible with throws clauses?
(4 answers)
Closed 4 years ago.
I'm running the Lip reading code on Eclipse Indigo from the following link :
https://github.com/sagioto/LipReading/blob/master/lipreading-core/src/main/java/edu/lipreading/WebFeatureExtractor.java
package main.java.edu.lipreading;
import com.googlecode.javacpp.BytePointer;
import com.googlecode.javacv.cpp.opencv_core;
import main.java.edu.lipreading.vision.AbstractFeatureExtractor;
import main.java.edu.lipreading.vision.NoMoreStickersFeatureExtractor;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketHandler;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.logging.Logger;
import static com.googlecode.javacv.cpp.opencv_core.CV_8UC1;
import static com.googlecode.javacv.cpp.opencv_core.cvMat;
import static com.googlecode.javacv.cpp.opencv_highgui.cvDecodeImage;
/**
* Created with IntelliJ IDEA.
* User: Sagi
* Date: 25/04/13
* Time: 21:47
*/
public class WebFeatureExtractor extends Server {
private final static Logger LOG = Logger.getLogger(WebFeatureExtractor.class.getSimpleName());
private final static AbstractFeatureExtractor fe = new NoMoreStickersFeatureExtractor();
public WebFeatureExtractor(int port) {
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(port);
addConnector(connector);
WebSocketHandler wsHandler = new WebSocketHandler() {
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
return new FeatureExtractorWebSocket();
}
};
setHandler(wsHandler);
}
/**
* Simple innerclass that is used to handle websocket connections.
*
* #author jos
*/
private static class FeatureExtractorWebSocket implements WebSocket, WebSocket.OnBinaryMessage, WebSocket.OnTextMessage {
private Connection connection;
public FeatureExtractorWebSocket() {
super();
}
/**
* On open we set the connection locally, and enable
* binary support
*/
#Override
public void onOpen(Connection connection) {
LOG.info("got connection open");
this.connection = connection;
this.connection.setMaxBinaryMessageSize(1024 * 512);
}
/**
* Cleanup if needed. Not used for this example
*/
#Override
public void onClose(int code, String message) {
LOG.info("got connection closed");
}
/**
* When we receive a binary message we assume it is an image. We then run this
* image through our face detection algorithm and send back the response.
*/
#Override
public void onMessage(byte[] data, int offset, int length) {
//LOG.info("got data message");
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
bOut.write(data, offset, length);
try {
String result = convert(bOut.toByteArray());
this.connection.sendMessage(result);
} catch (Exception e) {
LOG.severe("Error in facedetection, ignoring message:" + e.getMessage());
}
}
#Override
public void onMessage(String data) {
LOG.info("got string message");
}
}
public static String convert(byte[] imageData) throws Exception {
opencv_core.IplImage originalImage = cvDecodeImage(cvMat(1, imageData.length, CV_8UC1, new BytePointer(imageData)));
List<Integer> points = fe.getPoints(originalImage);
if(points == null)
return "null";
String ans = "";
for (Integer point : points) {
ans += point + ",";
}
return ans;
}
/**
* Start the server on port 999
*/
public static void main(String[] args) throws Exception {
WebFeatureExtractor server = new WebFeatureExtractor(9999);
server.start();
server.join();
}
}
In the following line :
public static void main(String[] args) throws Exception {
I'm getting the following error :
Exception Exception is not compatible with throws clause in Server.main(String[])
Please help me solve this.
There are two condition you need to check.
1) when declaring a method in interface you need to add throws exception for that method and similarly with the interface implementation class where the method is implemented.
for example
service.java
#Component
public interface UserService {
User getUser(Login login) throws Exception;
}
serviceimpl.java
public User getUser(Login login)throws Exception
{
}
2) by doing the above statement the error still doesn't vanish. make sure to save both the files.
Doest the server API handle all exceptions for itself. Why not try removing the throws in your code. I know its not good programming practice but might solve the problem.
The problem is that the Server class you are extending already contains a public static void main(String[]) method that does not have the same throws declaration. I didn't take a look at it, but I'd bet that method doesn't throw anything at all.
A solution would be to remove your throws clause in your main method and rely on try-catches instead.
EDIT: Why you cannot add a different throws clause in your case.
Let's assume the following scenario:
class A {
public static void foo() throws SomeException { ... }
}
class B extends A {
public static void foo() throws DifferentException { ... }
}
The Java standard says you are hiding the A.foo() method (or at least trying to). Thing is, you're only allowed to do that if the throws clause in B.foo() is already contained in the clause of A.foo(). So for the above scenario, you're perfectly legal only if DifferentException is a subclass of SomeException. Otherwise the compiler will yell.
I had the same issue, in my case I have implemented a method from an interface that did not declared to throw an exception.
In your case, I would guess that Server class also has a main method that didn't throw an exception. To quickly solve it. I would declare Server.main to throw an exception.
This link helped me
What are reasons for Exceptions not to be compatible with throws clauses?
I have 2 projects. One works fine in ever department. I downloaded and modified it to better understand it. The 2nd one is a project in development phase.
Now, both these projects have almost exactly the same RMI package, which works fine in the first project, but not in the 2nd.
My test classes in each package are essentially identical as well.
The main difference is what objects there are attempting to access, which are both interfaces in a database package.
Now, the database package in the 2nd project otherwise works absolutely fine, it just wont work with the RMI.
In short:
database package works fine
RMI package works fine
RMI package and database together does not work fine.
Here is my DBInterface
public interface DB extends Remote {
public String[] read(int recNo) throws RecordNotFoundException;
public void update(int recNo, String[] data, long lockCookie)
throws RecordNotFoundException, SecurityException, IOException;
public void delete(int recNo, long lockCookie)
throws RecordNotFoundException, SecurityException, IOException;
public int[] find(String[] criteria);
public int create(String[] data) throws DuplicateKeyException, IOException;
public long lock(int recNo) throws RecordNotFoundException;
public void unlock(int recNo, long cookie)
throws RecordNotFoundException, SecurityException;
}
and here is my RMIInterface
public interface RMIInterface extends Remote{
public DB getClient() throws RemoteException;
}
My RMIImplementation
public class RMIImplementation extends UnicastRemoteObject
implements RMIInterface {
private static String dbLocation = null;
private DB a;
public RMIImplementation() throws RemoteException{
}
public RMIImplementation(String dbLocation) throws RemoteException{
System.out.println(dbLocation);
this.dbLocation = dbLocation;
}
public static DB getRemote(String hostname, String port)
throws RemoteException {
String url = "rmi://" + hostname + ":" + port + "/DvdMediator";
try {
RMIInterface factory
= (RMIInterface) Naming.lookup(url);
// at this point factory equals Proxy[RMIInterface,................etc
// i want the return to equal Proxy[DB,..............etc
return (DB) factory.getClient();
} catch (NotBoundException e) {
throw new RemoteException("Dvd Mediator not registered: ", e);
}
catch (java.net.MalformedURLException e) {
throw new RemoteException("cannot connect to " + hostname, e);
}
}
public DB getClient() throws RemoteException {
try {
a = new ContractorDatabase(dbLocation);
}
catch(Exception e){
System.out.println("NewClass exception: " + e.toString());
}
return a;
}
And my the RMI registry
public class RegDvdDatabase {
private RegDvdDatabase() {
}
public static void register()
throws RemoteException {
register(".", java.rmi.registry.Registry.REGISTRY_PORT);
}
public static void register(String dbLocation, int rmiPort)
throws RemoteException {
Registry r = java.rmi.registry.LocateRegistry.createRegistry(rmiPort);
r.rebind("DvdMediator", new RMIImplementation(dbLocation));
}
}
Getting these two to work together throws a
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to sjdproject.remote.RMIImplementation
Can u please help me find the database issue that prevents it from working.
You must cast it to the remote interface.
EDIT The Registry reference r in your server code must be static. I can't see any good reason for locating the client lookup code inside the implementation class. That class should only exist at the server, not the client.
If you dont have a debugger, I would suggest using reflection on the provided object and see which interfaces it implements. It appears to be a proxy object, so must implement some interfaces.
for(Class clazz : factory.getClass().getInterfaces()) {
System.out.println(clazz.getSimpleName());
}
My suspicion with multiple deployments is of course the jvm version and the classpath. Can you verify that they match?
I'm learning Java RMI so that i'm writing and testing this code, the problem here is that the client (notificationSink class) send a message and register itself with the server but the server (notificationSource class) doesn't do anything.
This is RemoteThingInterface that extends Remote class:
public interface RemoteThingInterface extends Remote{
public void register(NotificationSink sink) throws RemoteException;
public void notifySink(String text) throws RemoteException;
}
This is NotificationSink class:
public class NotificationSink{
private String name;
private static String hostName = "Shine";
private static int serverPort = 2712;
private static String text = (new Date()).toString();
public NotificationSink(String name){
name = this.name;
}
public static void main(String [] args){
RemoteThingInterface rmiserver;
Registry reg;
System.out.println("Sending "+text+" to "+hostName+" through port "+serverPort);
try{
reg = LocateRegistry.getRegistry(hostName, serverPort);
rmiserver = (RemoteThingInterface) reg.lookup("server");
NotificationSink s = new NotificationSink("Eagle 1");
rmiserver.register(s);
rmiserver.notifySink(text);
}catch(RemoteException ex){} catch (NotBoundException ex) {
ex.printStackTrace();
}
}
}
This is NotificationSource class:
public class NotificationSource extends UnicastRemoteObject implements RemoteThingInterface{
private ArrayList sinks = new ArrayList<>();
int port;
Registry registry;
public NotificationSource() throws RemoteException{
try{
port = 2712;
registry = LocateRegistry.createRegistry(port);
registry.rebind("server", this);
}catch(RemoteException ex){
ex.printStackTrace();
}
}
#Override
public void register(NotificationSink sink) {
sinks.add(sink);
}
public ArrayList getSinks(){
return sinks;
}
#Override
public void notifySink(String text){
System.out.println("new sink registered, he is "+getSinks().get(0));
System.out.println(text);
}
public static void main(String [] args){
try{
NotificationSource s = new NotificationSource();
}catch(Exception e){
e.printStackTrace();
}
}
}
Please help to explain where i'm wrong and how to fix this. I tried to add some code to find the size of arraylist in server, it find out successfully, but other methods don't work .... codes are below:
adding this line to remotethinginterface: ArrayList getArray() throws RemoteException;
adding this line to notiSource:
#Override
public ArrayList getArray() throws RemoteException {
return sinks;
}
adding this line to notiSink: System.out.println(rmiserver.getArray().size()); (before rmiserver.register()
the client (notificationSink class) send a message
No it doesn't.
and register itself with the server
No it doesn't.
but the server (notificationSource class) doesn't do anything.
Why should it? There is no client request to do anything with. There can't be. It's impossible.
catch(RemoteException ex){}
The first major problem is here. You are ignoring RemoteException. Don't do that. Log it, print it, never ignore an exception unless you really know what you're doing. In this case you will therefore have ignored the nested NotSerializableException that was thrown when you called register().
The second major problem is that NotificationSink needs to either:
Implement Serializable, if you want it to execute at the server, or
Implement a remote interface and extend UnicastRemoteObject, if you want it to execute at the client.
How is it possible to export a java method or object using dbus?
I am writing this because the official documentation is very poor and it took me hours to figure out how to do it.
Ideally the DBus interface should go in a java package
DBus.java
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusInterfaceName;
#DBusInterfaceName("org.printer")
public interface DBus extends DBusInterface {
//Methods to export
public void Print(String message);
}
Main.java
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
public class Main {
public static void main(String[] args) {
Printer p = new Printer();
try {
DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
//Creates a bus name, it must contain some dots.
conn.requestBusName("org.printer");
//Exports the printer object
conn.exportObject("/org/printer/MessagePrinter", p);
} catch (DBusException DBe) {
DBe.printStackTrace();
conn.disconnect();
return;
}
}
}
//Printer object, implements the dbus interface and gets
//called when the methods are invoked.
class Printer implements DBus {
public boolean isRemote() {
return false;
}
public void Print(String message) {
System.out.println(message);
}
}
You can try this out with qdbus from the shell, running:
qdbus org.printer /org/printer/MessagePrinter org.printer.Print test