Download Lesson4 - People.cs.uchicago.edu

Document related concepts
no text concepts found
Transcript
Lesson 4
Advanced RMI
JNI
Some Misc real-world issues
Posting many objects
 What if many people logon to play tic-tac-
toe? How do we give each pair their own
game?
 What if we have many objects in general to
post?
 There are two ways to deal with this
– give each their own name in registry (not good)
– bootstrap off a singe factory method (good)
Bootstrapping
 For tic-tac-toe example, we could have a method:
TicTacToeImpl getGame() throws RemoteException;
 As long as both getGame and TicTacToeImpl are
setup up as remote, only one remote object need
get posted to the registry.
 Can create a pool of tic-tac-toe games and assign
as they come in.
 Will be required for hw2, recommended for hw1.
 This is a great simplification vs. binding multiple
objects!
Contacting rmi registry
 In our simplified application, to get a remote
reference we called:
Naming.lookup(“tic-tac-toe”);
 This assumes the default rmi port (1099) on
localhost.
 To change ports, run rmiregistery <port>
 The more general rmi URL is
Naming.lookup(“rmi://host:port/name”);
e.g.
Naming.lookup(“rmi://yourserver.com:99/tic-tac-toe”);
Listing objects in the registery
 Note that the Naming class has a method list
which returns a listing of all objects bound
to the registry.
 It is called from the client as:
– String[] bindings = Naming.list(“<rmi url goes
here”);
Security issues
 Recall that client needs auto-generated up-to-date
stub functions.
 If these are available locally on the client, there is
no security issue.
 However, keeping a local installation can be
cumbersome. Often stubs are downloaded via
other servers (we’ll see how to do this).
 In this case, a SecurityManager needs to be
installed to ensure that the stubs are not hostile
(unless applet is used, which has its own
SecurityManager).
RMISecurityManager
 Easiest way to do this is to use
java.rmi.RMISecurityManager as:
System.setSecurityManager(new RMISecurityManager());
 This by default restricts all code from making
socket connections.
 Obviously this is too strict. Need a policy file to
allow client to make network connection to rmi
port. It would look something like:
grant{ permission java.net.SocketPermission
“*:1024-65535”, “connect”}
java Client –Djava.security.policy=client.policy
Server-side security/firewalls
 For this class we assume you have control
over the server security configuration.
Deployment
RMI application deployment
 Very simple if client/server both have up-to-
date copies of all class files
 However, this is unrealistic and impractical.
 Better if client can load dynamically load
classes remotely.
 RMI provides such a mechanism built on
top of standard servers.
Deployment, cont.
 For server, following classes must be available to
its classloader:
–
–
–
–
Remote service interface definitions
Remote service implementations
Stubs
All other server classes
 For client
– Remote service interface definitions
– Stubs
– Server classes for objects used by the client (e.g. return
values)
– All other client classes
RMIClassLoader
 RMI support remote class loading by
specfying the java.rmi.server.codebase
property with an apprpriate URL
 This is done as:
java WhateverImp
-Djava.rmi.server.codebase=http://whatever
ftp, file, etc. can also be used
 Proper remote deployment will be required
on the next assignment.
Remote Objects and
Collections
Using Remote Objects in Sets
 Recall that equals() and hashcode must be
overridden to use Sets.
 For remote objects, this would require a network
call to the server, which could fail.
 Since equals does not throw RemoteException, it
cannot be overridden and used remotely.
 Thus, must use equals and hashCode methods in
RemoteObject class.
 These unfortunately only compare stubs, not
contents.
 Probably not a great idea to do this unless
necessary
clone() method
 Can not call at all directly for stubs
 If you want to clone, simply define a new
remote method (e.g. remoteClone), have it
call clone locally, and return copy as
parameter.
Remote Objects and
Inheritance
Synchronized RMI calls
Using synchronized methods in
rmi
 Recall that remote objects are passed by reference
(stub).
 Thus, when many users request the same object,
they are manipulating a single copy.
 If the object is immutable, there is no need to
synchronize.
 Otherwise, proper synchronization should be done
in the regular way – using synchronized methods
where appropriate, and synchronized blocks if
necessary.
RMI calling semantics
Native Data Types
 Native data types
– pass by value – parameter copied before remote
transmission
– exactly like single jvm behavior
– machine-independent format used
Objects
 Calling sequence for object parameters
– pass by value also!
– this differs from single-jvm behavior
– All objects are completely serialized (deep
copy) and sent to remote location.
– This can be hugely inefficient. Be very careful
when performance is at a premium!
Remote Objects
 Java defines a third type of parameter – a
remote object.
 Remote objects must be setup as rmi
distributed objects in the regular way
(extend UnicastRemoteObject and
implement Remote interface)
 Remote objects are pass-by-reference.
proxies rather than serialized objects are
returned.
Distributed Garbage
Collection
Distributed garbage collection
 Server keeps track of clients that have requested
object.
 When client disconnects, they are removed from
the list.
 Also a timeout mechanism controld by
java.rmi.dgc.leaveValue.
 Remote object can implement
java.rmi.server.Unfererenced to get notification
when clients no longer hold live reference.
 Bottom line: not much to worry about here.
Client-side callbacks
RMI callbacks
 Frequently, a server will need to inform a client
asynchronously when an event occurs. e.g.
– a player moved in a board game
– a certain amount of time passed (ticker)
 In such a case, the client has to behave like an rmi
server.
 There is nothing special about such situations. The
client can export a remote object and make it
available for the server to use for callback.
 See class TimeMonitor example
Activation
Creating objects remotely
 What we have learned about RMI requires
the server to instantiate one or more objects
and post them to the registry
 What if objects do not exists. Is it possible
for the client to remotely create an object on
the server?
 This can be useful occasionally and is now
possible with java Activation framework.
 We will not discuss Activation in this class.
RMI inter-language calls
indirectly using JNI
JNI
 Recall that CORBA allows inter-language
remote object calls; RMI does not!
 However, JNI allows one to call “native
code” directly from java.
 Thus, the two together give more CORBAlike capabilities.
– rmi calls java remote method, which locally
calls C code, which returns java parameter(s),
and rmi sends back to client.
What exactly does JNI do?
 Provides the glue between java – C/C++
(but no other languages)
 Provides the machinery for mapping
datatypes.
 Can be used to call C/C++ from Java
(typical), or Java from C (invocation API)
 Does NOT provide network transparency!
Reasons for using JNI
 Feature not available in java language.
 Code already written in another language,
don’t want to rewrite.
 Java is slow.
 Other language has no additional features
per se, but has much better syntax for
handling certain operations (Fortran for
math).
Problems with JNI
 Only provides C/C++ bindings. Going to
Fortran, COBOL, Ada, etc. requires extra
step.
 Not portable
 Mapping is not trivial
 No built-in security
Basic steps to calling native code
1. Write java class with a method declared with
native keyword. Provide no implementation
–
–
public native void sayHello();
Example above is most simple, but method may pass
any parameters or have any return type.
2. Add a call to System.loadLibrary(“libname”) in
the class that declares the native method:
–
static{
System.loadLibrary(“hello”);}//static means called only once.
Steps, cont.
3. Compile the class
–
javac Hello.java
4. Produce the C/C++ header files using the javah
utility:
– javah Hello
– This produces the header file Hello.h
5. Write your implementation file by first copying
the function signature produced in the include
file. Also, #include the header file.
#include “Hello.h”
Steps, cont.
6. Write the implementation in C/C++. This will
require using JNI methods to access the data or
possibly casts to convert to basic C/C++ types
7. Best technique: Break into two steps. Think of
your C/C++ function as a wrapper which accesses
the Java data and maps it to C data using JNI
methods, then shoves the converted data into a
prewritten standalone C program.
Steps, cont.
8. Compile your native method(s) as a shared object
(or DLL on Windows).
– WARNING: Be sure to point your linker to the include
files in /jdk1.3/include and jdk1.3/include/linux (for
example).
– WARNING: Mixing languages is much easier using a
straight C wrapper rather than C++.
9. Set the environment variable
LD_LIBRARY_PATH to the shared object
directory
 Run main Java class.
Mapping of datatypes
 C datatypes are platform-dependent. Those
in java aren’t.
 Thus, JNI defines its own portable C
datatypes.
 See next slide for mapping of native types.
Native java/c data mappings
Java
boolean
byte
char
short
int
long
float
double
C
jboolean
jbyte
jchar
jshort
jint
jlong
jfloat
jdouble
Bytes
1
1
2
2
4
8
4
8
String mappings
 Java and C strings are very different
(Unicode vs. 8-bit null terminated).
 Thus, JNI cannot simply pass memory from
java to C.
 Some mapping must occur.
 This is handled via C utility functions
provided with JNI.
 jstring is opaque type, and methods operate
directly on/create jstring types.
What does Java pass to my C
function?
 How are these utility functions provided?
 JNIEnv* : A pointer to the the JNI environment.
This pointer is a handle to the current thread in the
JVM, and contains mapping functions and other
housekeeping information.
 jobject : A reference to the object that called the
native code (this) for non-static methods
– or
jclass: A descriptor of the class which contains the method
for static methods
 Any arguments specified by the method.
String functions
 The string functions look like this:
– jstring NewStringUTF(JNIEnv*, const char[]);
– jsize GetStringUTFLength(JNIEnv*, jstring);
– void REleaseStringUTFChars(JNIEnv*, jstring, const
jbyte[]);
– void ReleaseStringChars(JNIEnv*, jstring, const
jchar[]);
etc.
etc.
Object fields
 What if we want to go beyond number and string
parameters?
 It is cumbersome but but not conceptually difficult
to call methods that manipulate object state.
 The designers of JNI made it difficult in order not
to hide the inner layout of java data structures.
 Thus, many method calls are required, outlined on
the next page.
Test case – Employee class
 Imagine the following simple Employee
class:
public class Employee{
public void raiseSalary(double percent){
this.salary *= 1 + percent / 100;
}
private double salary;
}
 We want to write this as a native method
Making raiseSalary native
 To make raiseSalary native, we hit the
signature with javah and get the following:
JNIEXPORT void JNICALL Java_Employee_raiseSalary
(JNIEnv*, jobject, jdouble);
 Note that second argument is of type jobject
since method is non-static. It is like this.
 We need to access, change, and set the
salary field of the implicit parameter.
 This is a several step process.
How to access the fields of
implicit parameter
 General syntax is:
x = (*env)->GetXxxField(env, class, fieldID);
 To get the object class, do:
jclass class_Employee = (*env)->GetObjectClass(env, obj_this);
 To get the fieldID, do:
jfieldID id_salary = (*env)->GetFieldID(env,class_Employee,
“salary”, “D”);
(string D denotes the type – double)
 Finally, call SetXxxField to affect change.
Source code for example
JNIEXPORT void JNICALL Java_Employee_raiseSalary(
JNIEnv* env, jobject obj_this, jdouble byPercent){
jclass class_Employee = (*env)->GetObjectClass(env, obj_this);
jfieldID id_salary = (*env)->GetFieldID(env, class_Employee,
“salary”, “D”);
jdouble salary = (*env)->GetDoubleField(env, obj_this, id_salary);
salary *= 1 + byPercent / 100;
(*env)->SetDoubleField(env, obj_this, id_salary, salary);
}
Accessing static fields
 Similar to object fields, but must get class
using a different method, e.g.:
jclass class_System = (*env)->FindClass(env, “java/lang/System”);
 To get the fieldID
jfieldID id_out = (*env)->GetStaticFieldID(env, class_System, “out”,
“Ljava/io/PrintStream;”
 To get static object field
jobject obj_out = (*env)->GetStaticObjectField(env, class_System,
id_out);
Calling java methods
 This is possible and quite straightforward as well.
 Simple use (*env)->CallXxxMethod(env, implicit
parameter, methodID, explicit parameters).
 Xxx can be Void, Int, Object, etc. depending on
return type of method.
 MethodID is like fieldID – use GetMethodID
function to access.
 Note that GetMethodID requires class name,
method name, AND signature. How to specify
signature is detailed in Horstmann ch 11.
Encoding scheme for method
signatures in JNI
B
C
D
F
I
J
Lclassname;
S
V
Z
byte
char
double
float
int
long
a class type
short
void
boolean
More on signatures
 Example:
– Employee(java.lang.String; double; java.util.Date)
has signature encoding:
“(Ljava/lang/String;DLjava/util/Date;)V”
 Note that String is wrapped in parentheses, there is
no separator between types (other than ‘;’ for class
types), and return type is appended).
 What does (II)I describe?
 What does (Ljava/lang/String;)V describe?
 Note: Arrays of any type simply begin with ‘[‘
 What does ([I[I)I describe?
javap tool
 Java contains a tool called javap that can be
run on a class file to produce the field
signatures. e.g.
javap –s –private Classname
 This is fun and useful to play with to
learn/save time.
Static Methods
 Calling static methods is similar to object
methods.
 There are two differences:
– Use GetStaticMethodID and CallStaticXxxMethod
– Supply class object rather than implicit parameter
object.
Arrays
 Arrays in java are mapped as opaque C
types: Here are a few; others obvious
Java type
C type
boolean[]
jbooleanArray
int[]
jintArray
double[]
jdoubleArray
Object[]
jobjectArray
Some Array methods
jsize GetArrayLength(JNIEnv, jarray)
jobject GetObjectArrayElement(JNIEnv, jobjectArray, jsize);
void SetObjectArrayElement(JNIEnv, jobjectArray, jsize, jobject)
Xxx* GetXxxArrayElements(JNIEnv, jarray, jboolean* isCopy);
void ReleaseXxxArrayElements(JNIEnv, jarray, Xxx elems[], jint mode)
etc.
etc.
Examples on union
 HelloWorld Example: No data passed
– Hello.java
– Hello.cc
 Max example : Only native dataypes
– Utils.java
– utils.cc
 Advanced Max example: Arrays
– Utils.java
– utils.cc
 Max Java-C-Fortran: max.f
A simple alternative – spawning a
system executable
 Advantages
– Infinitely simpler
– Portable
– Can use any native language
 Disadvantages
– Can only pass data to and from vi stdout
– Must reload executable for each invocation
Spawning Executable -technique
 Process p = Runtime.exec(“some_exec”);
 Use p to manage process:
– p.getInputStream();
– p.getOutputStream();
– p.kill();
– p.halt();
Other topics/coming attractions
 Invocation API (C calls java directly).
 Calling constructors from native code
 throwing java exceptions