There are two classes Compute.java and Task.java in the compute package. Both are used by the server and the client. The server ComputeEngine.java resides in the engine package.
nbRMIoracleClient project has the client package. There are two classesComputePi.java and Pi.java in the client package.
IMPORTANT NOTE: Copyright notice given below covers all the source code lines in this blog article.
Task.java
-------------
/* * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: *
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. *
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. *
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission. *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
package compute;
public interface Task
Compute.java:
--------------------
package
compute;
import
java.rmi.Remote;
import
java.rmi.RemoteException;
public
interface Compute extends Remote {
}
Compute java
has a single function executeTask which has the param t of type Task.
ComputeEngine.java
---------------------------
package
engine;
import
java.rmi.RemoteException;
import
java.rmi.registry.LocateRegistry;
import
java.rmi.registry.Registry;
import
java.rmi.server.UnicastRemoteObject;
import
compute.Compute;
import
compute.Task;
public class
ComputeEngine implements Compute {
public ComputeEngine() {
super();
}
public T
executeTask(Task t) {
return t.execute();
}
public static void main(String[] args) {
if (System.getSecurityManager() ==
null) {
System.setSecurityManager(new
SecurityManager());
}
try {
String name = "Compute";
Compute engine = new
ComputeEngine();
Compute stub =
(Compute)
UnicastRemoteObject.exportObject(engine, 0);
Registry registry =
LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("ComputeEngine
bound");
} catch (Exception e) {
System.err.println("ComputeEngine exception:");
e.printStackTrace();
}
}
}
ComputeEngine
implements the Compute interface. So it
implements the executeTask function.
executeTask
function simply executes the execute() function of the Task that is passed to
it as param.
The main
function of ComputeEngine sets the security manager first then creates an instance
of itself. Then exports this object cast
as Compute to the variable stub. After
this it locates registry and binds the name compute to the object stub.
To run this
program you must first define the classpath as given below.
Secondly you must set the vm options as given below:
-Djava.security.debug=access,failure
-Djava.security.manager
-Djava.security.policy="C:\Users\ars\Desktop\nbRMIoracle\src\engine\server.policy"
-Djava.rmi.server.codebase=file:/C:\Users\ars\Desktop\nbRMIoracle\build\classes/
The OUTPUT:
-------------------
ComputeEngine
bound
Pi.java
---------
package
client;
import
compute.Task;
import
java.io.Serializable;
import
java.math.BigDecimal
public class
Pi implements Task, 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;
}
}
Pi
implements task with the template type BigDecimal. There are original comments in the code that
provides sufficient info. The crucial
function is computePi which returns the BigDecimal value of Pi.
arctan is a
utility function and used by the computePi.
public static BigDecimal computePi(int
digits) {
ComputePi.java
---------------------
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();
}
}
}
ComputePi
sets theSecurity Manager first. Then sets
the stub name to the name var. It gets
the registry name from the program params.
It looks up the name in the registry and gets the interface compliant
Compute object, comp. It creates a
Pitask task using the number of digits passes in the programs vars, 2nd var. It runs the executeTask of the comp object.
To run this
client program: You must first run the
server with success.
Namely it
should write: ComputeEngine bound
Then you
should specify the classpath as given below:
You should specify the vm options and arguments as below:
-Djava.security.debug=access,failure
-Djava.security.manager
-Djava.security.policy="C:\Users\ars\Desktop\nbRMIoracleClient\src\client\client.policy"
-Djava.rmi.server.codebase=file:/C:\Users\ars\Desktop\nbRMIoracleClient\build\classes/
The OUTPUT:
3.141592653589793238462643383279502884197169399
BUILD SUCCESSFUL
(total time: 0 seconds)
The security
issue:
------------------------
You must
specify the security policy for the server and client seperately. If you check the first picture in this blog
article you will notice server.policy and the client.policy:
Server.policy:
-----------------
grant
codeBase "file:/C:/Users/ars/Desktop/nbRMIoracle/src/-" {
permission java.security.AllPermission;
};
grant
codeBase "file:/C:/Users/ars/Desktop/nbRMIoracle/build/-" {
permission java.security.AllPermission;
};
The location
of the server.policy is specified in the vm options as below:
-Djava.security.debug=access,failure
-Djava.security.manager
-Djava.security.policy="C:\Users\ars\Desktop\nbRMIoracle\src\engine\server.policy"
-Djava.rmi.server.codebase=file:/C:\Users\ars\Desktop\nbRMIoracle\build\classes/
The first
line produces debug info. The third line
specifies the location of the server policy.
The fourth
line specifies where the binary executables reside.
Client.policy:
---------------
grant
codeBase "file:/C:/Users/ars/Desktop/nbRMIoracleClient/src/-" {
permission java.security.AllPermission;
};
grant
codeBase
"file:/C:/Users/ars/Desktop/nbRMIoracleClient/build/classes/-" {
permission java.security.AllPermission;
};
Similar to
the server:
-Djava.security.debug=access,failure
-Djava.security.manager
-Djava.security.policy="C:\Users\ars\Desktop\nbRMIoracleClient\src\client\client.policy"
-Djava.rmi.server.codebase=file:/C:\Users\ars\Desktop\nbRMIoracleClient\build\classes/
Be carefull,
many difficulties related to RMI are not RMI related but the problems of
specifying these VM options. URL and
simple dir specifications may cause large difficulties. One simpleway to get around these is to use
the policyTool that you can find in:
C:\Program
Files\Java\jdk1.6.0_26\bin
Using this
tool if you check the below policy:
C:\Program
Files\Java\jre6\lib\security\java.policy
You may have a realistic idea of what your system does and how to specify the params.
Otherwise
you will first get:
access
denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve)
Then:
Server
exception: java.rmi.ServerException: RemoteException
occurred in server thread; nested exception is:
java.rmi.UnmarshalException:
error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: compute.Compute
Cheers.
Ali R+