Download Note - first

Document related concepts
no text concepts found
Transcript
Lesson 3
Advanced RMI
JNI
Assorted real-world RMI
issues
Review of rmi basics
 rmi is a relatively very simple D.O. framework.
 Major limitations
– Only java to java
 Major advantages
– Clean, easy to deploy, robust
– Maps very cleanly to java language semantics
 Competing frameworks/technologies
– CORBA
– Web Services
rmi approach
 Distributed objects have look-and-feel of local objects, but
can be called across machines.
 A distributed object is a regular object augmented with the
following:
–
–
–
–
Extends UnicastRemoteObject
Have public distributed methods that throw RemoteException
Have parameters that implement Serializable
Have a constructor that throws RemoteException (it need not
directly call super)
– Have a separate interface file that lists the remote methods and
extents java.rmi.Remote.
Today’s naming convention for rmi
Naming
convention
Example
No Suffix
Foo
Impl Suffix
FooImpl
Server
suffix
Client
Suffix
FooServer
FooClient
File type
Remote
interface
“Business
Logic”
Program that
creates objs
Client
program
Creating stubs
 Layout of most simple rmi application before stub
generation looks like
– Server
•
•
•
•
StoreImpl.java (implementation)
Store.java
(interface)
StoreServer.java (to bootstrap)
Other local classes
– Client
• StoreClient.java
• Store.java
 Must compile client and server before using rmic!
Stub Class Generation
 Recall that the _stub class contains the glue
messaging code on both the client and the server.
 There are three ways to create the stubs depending
on which version of java you are using:
– As of jdk5.0, stubs generated automatically.
– As of jdk1.2, stubs are generated as
• rmic –v1.2 StoreImpl
– Before jdk1.2, stubs and skeletons are creates as
• rmic –v1.1 StoreImpl
 This creates StoreImpl_stub.class
Creating stubs
 Layout of most simple rmi application before stub
generation looks like
– Server
•
•
•
•
•
StoreImpl.class (implementation)
Store.class
(interface)
StoreServer.class (to bootstrap)
Other local classes
StoreImpl_stub.class
– Client
• StoreClient.class
• Store.class
• StoreImpl_stub.class
Make sure these are same!
 Must compile client and server before using rmic!
Deployment issues
 A couple of more sophisticated issues arise in deployment
– How to have client automatically download stubs and update class
defintions
– How to handle security issues
 There are pretty simple approaches for each described in
book.
 For now, we will assume in our assignments that client has
all updated class files and that security is not an issue.
 I will give a quick pointer to security issues later in this
lecture.
More complex issues
Callbacks
Typical model of callback
class Client{
Client(){
Server x = new Server();
x.doIt(…, this);
}
doIt(…){
….
}
}
class Foo{
public void doIt(…, Client client){
…
client.doIt();
}
}
Callback example – timer class
 At specified time interval, server sends you e.g.
current time, which you display locally.
 Design
– Server contains register method and receives remote
reference to client
– Client contains update method which recieves current
time and displays
– Consider how both all rmi and rmi + sockets version of
this program would look
Another callback example
 TicTacToe game is another good example of a
callback.
 Client accesses server object to place next move.
 Once new move is placed and accepted, server
must contact other player with updated move.
 In this sense, server become client and client
server for this particular call
 How to architect this with rmi?
Tic-tac-toe with RMI
 Pure rmi implementation
– TicTacToeClient is adorned as D.O. also!
– Contains method such as otherPlayerMove
– TicTacToeClient calls server register method
and passes copy of this
– TicTacToeImpl stores this and uses for D.O.
call to inform other player of current players
move.
– Note that notion of server and client is only
meaningful for a particular method!
Tic-tac-toe with RMI
 RMI + sockets implementation
– In this example, each client runs a socket server
and gets a direct socket connection from the
game server
– TicTacToeClient is not a remote object
– Game server still runs as remote object in
regular way
 Examples all posted on web site
Handling many server objects
Bootstrapping registry
Binding many objects to registry
 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 single factory method (good)
Bootstrapping
 For tic-tac-toe example, we could have a method:
TicTacToe 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!
 See examples under bootstrap directory
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. to lookup on port 99 at host yourserver.com
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>”);
Other changes in jdk5.0
Naming service
Security issues
 Recall that client needs up-to-date stub functions.
 No problem if these are available locally on client.
 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).
A few notes about
security/deployment
RMISecurityManager
 Easiest way to do this
System.setSecurityManager(new RMISecurityManager());
 By default prohibits any 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.
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 dynamically load classes
remotely.
 RMI provides such a mechanism built on
top of standard server protocols
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 appropriate URL
 This is done as:
java WhateverImp
-Djava.rmi.server.codebase=http://whatever
ftp, file, etc. can also be used
 See deployment directory in class examples
 Proper remote deployment will be required
on the next assignment.
Remote Objects and object
methods
Clone, equals, etc.
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.
Non-remote objects
 Note that all objects which are not remote
are fully copied to client
 This is very different from local method
call, where objects are passed as references.
 Thus, only remote objects can change state
across client-server call
 Also, performance issues can arise for very
deep object graphs
Remote Objects and
Inheritance
Using inheritance with rmi
 Stubs are generated only from classes that
implement a remote interface (and only for
methods in that interface).
 Subclasses of remote classes can be defined
and used in place of superclass in remote
method call.
 However, only superclass remote methods
will be available, not any other defined in
subclass!
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 controlled 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.
Object 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.
Modifying object fields
 What if we want to go beyond number and
string parameters?
 One such case is a method that manipulates
object state
 It is cumbersome but but not conceptually
difficult to write native methods that
manipulate object state.
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:
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);
}
Manipulating static fields
 Similar to object fields, but must get class
using a different method, e.g. to access the
static out object in the System class:
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);
Callbacks on 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
 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
 Invocation API (C calls java directly).
 Calling constructors from native code
 throwing java exceptions