Reputation: 33
Sorry for writing but use a translator , I hope you can help me with an example of an RMI I'm testing.
I see the following error when running the client:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: client.Pi
The project structure is as follows.
|-Cliente\
| |-client\ ComputePi (main class) and Pi(Task)
| |-->ComputePi.java
| |-->ComputePi.class
| |-->Pi.java
| |-->Pi.class
| |-compute\
| |-->Compute.java
| |-->Compute.class
| |-->Task.java
| |-->Task.class
| |-public\
| |-classes\
| |-->compute.jar
| |-client\
| |--> Pi.class
|-->client.policy
|-Servidor\
| |-compute\
| |-->Compute.java
| |-->Compute.class
| |-->Task.java
| |-->Task.class
| |-engine\
| |-->ComputeEngine.java
| |-->ComputeEngine.class
| |-public\
| |-classes\
| |-->compute.jar
|-->server.policy
The server starts fine, but when I start the client it sends me the error shown above. When I run the client I do as follows:
java -cp c:\Users\Mauricio\Documents\RMI\Cliente;c:\Users\Mauricio\Documents\RMI\Cliente\public\classes\compute.jar
-Djava.rmi.server.codebase=file:/c:/Users/Mauricio/Documents/RMI/Cliente/public/classes/
-Djava.security.policy=c:/Users/Mauricio/Documents/RMI/Cliente/client.policy
client.ComputePi 127.0.0.1 45
Can you help me understand what is causing this error?
Sorry for not putting before the code.
Class Compute
package compute;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Compute extends Remote {
<T> T executeTask(Task<T> t) throws RemoteException;
}
Class Task
package compute;
public interface Task<T> {
T execute();
}
Class ComputePi
package client;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.math.BigDecimal;
import compute.Compute;
public class ComputePi {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Compute";
Registry registry = LocateRegistry.getRegistry(args[0]);
Compute comp = (Compute) registry.lookup(name);
Pi task = new Pi(Integer.parseInt(args[1]));
BigDecimal pi = comp.executeTask(task);
System.out.println(pi);
} catch (Exception e) {
System.err.println("ComputePi exception:");
e.printStackTrace();
}
}
}
Class Pi
package client;
import compute.Task;
import java.io.Serializable;
import java.math.BigDecimal;
public class Pi implements Task<BigDecimal>, Serializable {
private static final long serialVersionUID = 227L;
/** constants used in pi computation */
private static final BigDecimal FOUR =
BigDecimal.valueOf(4);
/** rounding mode to use during pi computation */
private static final int roundingMode =
BigDecimal.ROUND_HALF_EVEN;
/** digits of precision after the decimal point */
private final int digits;
/**
* Construct a task to calculate pi to the specified
* precision.
*/
public Pi(int digits) {
this.digits = digits;
}
/**
* Calculate pi.
*/
public BigDecimal execute() {
return computePi(digits);
}
/**
* Compute the value of pi to the specified number of
* digits after the decimal point. The value is
* computed using Machin's formula:
*
* pi/4 = 4*arctan(1/5) - arctan(1/239)
*
* and a power series expansion of arctan(x) to
* sufficient precision.
*/
public static BigDecimal computePi(int digits) {
int scale = digits + 5;
BigDecimal arctan1_5 = arctan(5, scale);
BigDecimal arctan1_239 = arctan(239, scale);
BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
arctan1_239).multiply(FOUR);
return pi.setScale(digits,
BigDecimal.ROUND_HALF_UP);
}
/**
* Compute the value, in radians, of the arctangent of
* the inverse of the supplied integer to the specified
* number of digits after the decimal point. The value
* is computed using the power series expansion for the
* arc tangent:
*
* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 +
* (x^9)/9 ...
*/
public static BigDecimal arctan(int inverseX,
int scale)
{
BigDecimal result, numer, term;
BigDecimal invX = BigDecimal.valueOf(inverseX);
BigDecimal invX2 =
BigDecimal.valueOf(inverseX * inverseX);
numer = BigDecimal.ONE.divide(invX,
scale, roundingMode);
result = numer;
int i = 1;
do {
numer =
numer.divide(invX2, scale, roundingMode);
int denom = 2 * i + 1;
term =
numer.divide(BigDecimal.valueOf(denom),
scale, roundingMode);
if ((i % 2) != 0) {
result = result.subtract(term);
} else {
result = result.add(term);
}
i++;
} while (term.compareTo(BigDecimal.ZERO) != 0);
return result;
}
}
Class ComputeEngine
package client;
import compute.Task;
import java.io.Serializable;
import java.math.BigDecimal;
public class Pi implements Task<BigDecimal>, Serializable {
private static final long serialVersionUID = 227L;
/** constants used in pi computation */
private static final BigDecimal FOUR =
BigDecimal.valueOf(4);
/** rounding mode to use during pi computation */
private static final int roundingMode =
BigDecimal.ROUND_HALF_EVEN;
/** digits of precision after the decimal point */
private final int digits;
/**
* Construct a task to calculate pi to the specified
* precision.
*/
public Pi(int digits) {
this.digits = digits;
}
/**
* Calculate pi.
*/
public BigDecimal execute() {
return computePi(digits);
}
/**
* Compute the value of pi to the specified number of
* digits after the decimal point. The value is
* computed using Machin's formula:
*
* pi/4 = 4*arctan(1/5) - arctan(1/239)
*
* and a power series expansion of arctan(x) to
* sufficient precision.
*/
public static BigDecimal computePi(int digits) {
int scale = digits + 5;
BigDecimal arctan1_5 = arctan(5, scale);
BigDecimal arctan1_239 = arctan(239, scale);
BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
arctan1_239).multiply(FOUR);
return pi.setScale(digits,
BigDecimal.ROUND_HALF_UP);
}
/**
* Compute the value, in radians, of the arctangent of
* the inverse of the supplied integer to the specified
* number of digits after the decimal point. The value
* is computed using the power series expansion for the
* arc tangent:
*
* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 +
* (x^9)/9 ...
*/
public static BigDecimal arctan(int inverseX,
int scale)
{
BigDecimal result, numer, term;
BigDecimal invX = BigDecimal.valueOf(inverseX);
BigDecimal invX2 =
BigDecimal.valueOf(inverseX * inverseX);
numer = BigDecimal.ONE.divide(invX,
scale, roundingMode);
result = numer;
int i = 1;
do {
numer =
numer.divide(invX2, scale, roundingMode);
int denom = 2 * i + 1;
term =
numer.divide(BigDecimal.valueOf(denom),
scale, roundingMode);
if ((i % 2) != 0) {
result = result.subtract(term);
} else {
result = result.add(term);
}
i++;
} while (term.compareTo(BigDecimal.ZERO) != 0);
return result;
}
}
Upvotes: 2
Views: 226
Reputation: 311023
java.lang.ClassNotFoundException: client.Pi
The server doesn't have client.Pi
available on its CLASSPATH or via the client's codebase either. file:
codebases don't work unless both server and client are on the same machine, in which case there is little or no point in using the codebase feature at all.
See also @Mario's answer re java.rmi.server.useCodebaseOnly.
Upvotes: 0
Reputation: 2515
I believe the error you're getting is because you're missing the following flag when you launch the server:
-Djava.rmi.server.useCodebaseOnly=false
The problem is with the server, not the client. The client is reporting the server's error.
At the time of my writing this, the Oracle RMI tutorial is missing this flag; so, it's not your fault.
https://docs.oracle.com/javase/tutorial/rmi/running.html
If you're missing the flag, the server will not load any code that it doesn't have in its own code base. In other words, if the client is on a different machine than the server, and the Pi
class exists only on the client, the server will not be able to load it. The error you're seeing is the exact error I was getting until I added the flag.
My understanding is that from JVM v1.7 on, the default value for useCodebaseOnly
is true
. (A true value allows for greater security, but makes for a broken tutorial.)
In short, add the flag set to false
to the server's startup command. Good luck!
Upvotes: 1