got a Problem with my RMI Test...
Server:
LocateRegistry.createRegistry(non-default-port);
obj = new HelloImpl();
Naming.rebind("//ip-of-server/HelloServer", obj);
Client:
RMISocketFactory.setSocketFactory(new sun.rmi.transport.proxy.RMIHttpToCGISocketFactory());
obj = (Hello) LocateRegistry.getRegistry("ip of server", non-default-port).lookup( "HelloServer");
obj.sayHello("test");
All objects are static in the class..
But i get a "java.rmi.NoSuchObjectException: no such object in table"-Exception all the time..
This only happens, if i use the HTTP Tunneling via
RMISocketFactory.setSocketFactory(new sun.rmi.transport.proxy.RMIHttpToCGISocketFactory());
If i try it without the HTTP Tunneling (from a other PC in the normal web), it works fine!
What could be the problem?
You will be getting this from the sayHello() rather than the lookup(). The meaning of the exception is that the stub is 'stale', i.e. the remote object has been unexported, which probably means it has been DGC'd as well. You should try the following, in this order, one at a time:
Keep a static reference to the value returned by createRegistry().
This should be sufficient by itself, but if it isn't:
Keep a static reference to the remote object itself, and no I do not mean its stub. In this case, obj.
I can't explain why it happens via HTTP tunnelling only, but you should do (1) in all cases anyway, so really it is a bug waiting to happen via any means.
Related
I'm facing strange behavior when i request my own ping server with java HttpComponent client.
Sometimes, an unknownHostException is thrown with no reason.
This exception is principally thrown after switching network, for example when i changed the default network route (from eth0 to wifi or from wifi to other mobile NIC)
For information, my wifi connection is enabled through mobile access point. (Could this point reason of my issue ? )
I'm running on a linux OS, in embededded context with limited linux command.
Below, code example:
HttpGet get = new HttpGet("someUri");
if (networkInterfaceName != null) { // used to ping through specific route
get.setConfig(RequestConfig.custom()
.setLocalAddress(networkInterfaceToInetAdress(networkInterfaceName ))
.setConnectionRequestTimeout(15000)
.setConnectTimeout(15000)
.setSocketTimeout(15000).build());
}
HttpResponse response = HttpClientBuilder.create().useSystemProperties().build().execute(get);
So, if a specific interface is provided, local address is set in the requestConfig, otherwise we use the default route.
I'm currently not abled to identify the root cause and some actions are tried to identify the root cause.
First action, i checked on each httpRequest, route and /etc/resolv.conf and everything seems ok. Ping cmd result is also ok when unknown host exception is thrown.
I checked the httpClient code, and it seems that it create a new client on each call, so there is no httpClient cache for me.I used HttpClientBuilder class and it seems that create method call return always a new builder. Also, cloaseableHttpClient is not closed explicitly, should it impact next call ?
I checked httpClient method, it enable setting a dnsResolver, but in my case, but i've no control to remote/targeted ip.
I set JVM system properties in code (and not as Java ARGS directly):
java.security.Security.setProperty("networkaddress.cache.ttl", "0");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("sun.net.inetaddr.ttl", "0");
Also, i'm going to use dnsjava lib when unknowhostexception is thrown as dig/dnslookup are not available in my limited OS.
Any hint about this issue ? or other thing that i need to ckeck ? may be it's not a DNS issue but something in Java socket or connection that i passed by ?
UPDATE
I tried to run same logic in another JVM and httpGet request are ok while httpGet fail in my original program that is running in another JVM
Thanks for your help.
I have a server which allows RMI connections. It exposes a "Server" object on the registry for remote calls, which has a method "authenticate". That method, if successful, returns a "user" object. This user object can then be used by the client to get some data.
It looks like this:
RMIServer server = new RMIServer ();
Naming.rebind("rmi://"+ hostName +"/" + AUTH_OBJECT_BINDING, server);
RMIServer then has a method:
public InterfaceUser Authenticate(String username, String password);
This method checks the username/pw and returns a user object (actually the interface). The user object saves some string which contains the username, and a list of permissions. This can then be checked when calling other methods further down the line.
My question is this:
Someone wants to develop a (another) client for the server, to do this I would give them the interfaces required to interact with it (e.g, the InterfaceUser interface, as well as others). I would need to set up a fake "development" server somewhere to allow them to do this, which they can connect to. Is it possible for that developer to use the interfaces to allow it to get an instance of "InterfaceUser" from the real server without correctly authenticating? For example, Bob logs in to the real server, the server creates a User object which implements InteraceUser. Can Alice, with the interfaces, hijack that object or find it somehow on the registry? All other objects are exported on the same port (if this makes a difference).
Or, can Alice authenticate with the fake server, then somehow use that to access the real server? Let's assume that all usernames/passwords are different on the "real server" and the "development server"
Thanks, any help is appreciated.
Alice can't get any user object unless she can login to a server that provides it.
Any user object Alice does get is bound to the server that created it, and can't be used on another server. It doesn't even survive power cycling of the correct server.
Does that answer your question?
I have created a simple database application using rmi. It works fine with my local wireless network. But now i want to connect my client to the server through the internet. I know that, this can be achieved with setting up port forwarding in the router. But i want it to work in any computer which is connected to the internet using wifi connections, dialup
connections etc. How to do that?
what to write here? Naming.lookup ("rmi://?????????????");
As I am quite new to java, Please give me a detailed answer with a simple code example.
Thanks in advance
I hope you are messed up with Java RMI Concept. Irony is that a few days ago I was also thinking up the same except that I was thinking to connect up on my internal network.
There are two kinds of classes that can be used in Java RMI.
A Remote class is one whose instances can be used remotely. An object
of such a class can be referenced in two different ways:
1. Within the address space where the object was constructed, the object is an ordinary object which can be used like any other object.
2. Within other address spaces, the object can be referenced using an object handle. While there are limitations on how one can use an
object handle compared to an object, for the most part one can use
object handles in the same way as an ordinary object.
A Serializable class is one whose instances can be copied from one
address space to another. An instance of a Serializable class will be
called a serializable object. In other words, a serializable object is
one that can be marshaled.
SO, HERE COMES THE ANSWER TO YOUR QUESTION,ASSUMING YOU ARE TALKING ABOUT REMOTE CLASS ON DIFFERENT SYSTEM(SERVER).
The name of a remote object includes the following information:
The Internet name (or address) of the machine that is running the
Object Registry with which the remote object is being registered. If
the Object Registry is running on the same machine as the one that is
making the request, then the name of the machine can be omitted.
The port to which the Object Registry is listening. If the Object
Registry is listening to the default port, 1099, then this does not
have to be included in the name.
The local name of the remote object within the Object Registry.
The URL for a remote object is specified using the usual host, port and name:
rmi://host:port/name
host = host name of registry (defaults to current host)
port = port number of registry (defaults to the registry port number)
name = name for remote object
Assuming that your code is lying on the server having host-name as "XYZ.edu/home/CLasses"(you can give the DNS/IP-Address of server and include the location of the Class file),port-number="1099"(default) and name of the remote Object="abc" for your ABC.java Class in Server. In this way one will be able to call the Remote Object from different machines. Also, you need to keep the whole Server code on the Internet Address so that Clients can access them from the Internet(one can't access the offline-code present in your machine). Then only it can happen!!!
Here is the example Client program:
/**
* Client program for the "Hello, world!" example.
* #param argv The command line arguments which are ignored.
*/
public static void main (String[] argv) {
try {
HelloInterface hello =
(HelloInterface) Naming.lookup ("//ortles.ccs.neu.edu/Hello"); //see here the address of the server hosting the Server file,you can omit port number,it'll take default port 1099.
System.out.println (hello.say());
} catch (Exception e) {
System.out.println ("HelloClient exception: " + e);
}
}
I am trying to debug http client request. I need to get the local port number that was used when the connection was made. I can use the HttpClientContext to get the connection, and retrieve the local port when the connection is successful. However, in cases where the IOExceptions are thrown, I get a ConnectionShutdownException when retrieving the local port number. Any clue on how I can obtain the local port number for all http requests in case of error.
This is for HTTPClient 4.0.1 (last version I have with me).
I did not find any simple one liner...
The part of http client that actually binds sockets to local host/port and connects to the remote host/port is, unsurprisingly, the SocketFactory. In HTTPClient, the socket factory is associated to a SchemeRegistry, that in turns belongs to the connection manager. Note that the HTTPClient's SocketFactory is NOT a javax.net.SocketFactory, but a wrapper around such an object. You define a scheme like so :
SchemeRegistry schRgstr = new SchemeRegistry();
Scheme httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
schRgstr.register(httpScheme);
Of course, org.apache.http.conn.scheme.SocketFactory is an Interface, so you can decorate it to do anything you want in particular, this will come in handy.
The part of httpclient that calls the socket factory is called the ClientConnectionOperator (which is an interface too). This object is actually also tied to the connection manager, and not the client per se. So if you want to customize the connection operator, you may override the connection manager too, for example, like so (anonymous class) :
ThreadSafeClientConnManager connMngr = new ThreadSafeClientConnManager(httpParams, schRgstr) {
protected ClientConnectionOperator createConnectionOperator(SchemeRegistry schreg) {
return new YourConnectionOperator(schreg);
};
};
The lifecycle model of the socket goes like so:
When the connection manager needs a now connection, it calls createConnection on the operator (which basically does nothing but create an internal object that eventually will hold the actual socket).
Further along the way it calls openConnection
openConnection goes to the SocketFactory and asks for a new Socket, then tries to connect it like so (here, sf is the "httpclient socket factory")
sock = sf.connectSocket(sock, target.getHostName(),
schm.resolvePort(target.getPort()),
local, 0, params);
If this call fails, an exception is thrown and more information will not be accessible. We'll get back to that.
If the connectSocket works, though, the prepareSocket method is called on the connection operator. And so, you can override the method and put the port information into the context, (or anything else you fancy) :
#Override
protected void prepareSocket(Socket sock, HttpContext context, HttpParams params) throws IOException {
super.prepareSocket(sock, context, params);
context.setAttribute("LOCAL PORT INTERCEPTOR", sock.getLocalPort());
}
The HttpContext instance that is used is passed when you invoke HTTPClient, so you can access it even if the call fails later, because of some other exception. When you place your call, make it so:
HttpContext ctx = new BasicHttpContext();
HttpGet get = new HttpGet(targetUrl.getUrl());
HttpResponse resp = client.execute(get, ctx);
In this code, if the client could go as far as step 5, you have your port info accessible, even if an exception occurs later on (connection drop out, timeout, invalid HTTP, ...).
Going further
There is still a dark zone in all this : if the call fails at step 4 (actual opening of the socket, like if you have a DNS error while resolving the destination host name)... I'm not sure this case is actually interesting to you, (I can not see why it would be). Seeing dealing with it starts to get "messy", you should really consider wether or not you need this.
For that we need to start overriding really deep, and that involves lots of work - some of it I would not consider very good design.
The complexity arises because authors of HTTPClient did not provide the necessary methods one could override to get to the information you need. Inside the socket factory, the interesting point is :
sock = createSocket();
InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
sock.bind(isa);
// go on and connect to the server
// like socket.connect...
There is no method to override that splits the local and the server side of the socket openning, so that if any socket exception is thrown on the server side, your access to the socket instance is lost, and the local port info gone with it.
But all is not lost because we do have one entry point we can play with : the createSocket method! Default implementation is
public Socket createSocket() {
return new Socket();
}
But as Socket is not a final class, you can... play with it !
public Socket createSocket() {
return new Socket() {
#Override
public void bind(SocketAddress bindpoint) throws IOException {
super.bind(bindpoint);
// get the local port and give the info back to whomever you like
}
};
}
Problem is : this works with plain sockets (because we can create an anonymous subclass), but this does not work with HTTPS, because you can not simply instanciate a Socket on this case, you have to do :
return (SSLSocket) this.javaxNetSSLSocketFactory.createSocket();
And you can not create an anonymous subclass in that case. And as Socket is no interface either, you can not even proxy it to decorate it. So you could (uglyest code ever) create a Socket subclass that wraps and delegates to the SSLSocket, but that'd be desperate.
So, recap time.
If we only care about sockets that were at some point connected to the server, the solution is fairly simple.
A scheme registry we builb is used in a custom ConnectionManager that overrides the ConnectionOperator. The operator's overriden methods is prepareSocketthat allows us to simply update the HttpContext of any request we send with the port information. Which is an easy way to find the information when everything goes well.
If we want to care about local ports attributed to a socket that never, ever, got connected (which I would argue is of limited use), one need to go deeper.
Our own SchemeRegistry should be designed to have custom SocketFactories. These should probably be decorators or the default ones... the createSocket overriden method allows us to "intercept" the binding on the local port (and store this into maybe a ConcurrentMap<Socket, Integer> or a ThreadLocal), and by overriding 'connectSocket' we trap any exception that may happen, and rethrow it, but not before wrapping it in our own exception type that can hold local port information. That way, if the exceptions passes though when you call the client, by checking the cause chain, you will find your port data. If no exception occurs, we clean or map instance / thread local.
I have to implement a webservice client to a given WSDL file.
I used the SDK's 'wsimport' tool to create Java classes from the WSDL as well as a class that wrap's the webservice's only method (enhanceAddress(auth, param, address)) into a simple java method. So far, so good. The webservice is functional and returning results correcty. The code looks like this:
try {
EnhancedAddressList uniservResponse = getWebservicePort().enhanceAddress(m_auth, m_param, uniservAddress);
//Where the Port^ is the HTTP Soap 1.2 Endpoint
}catch (Throwable e) {
throw new AddressValidationException("Error during uniserv webservice request.", e);
}
The Problem now: I need to get Information about the connection and any error that might occur in order to populate various JMX values (such as COUNT_READ_TIMEOUT, COUNT_CONNECT_TIMEOUT, ...)
Unfortunately, the method does not officially throw any Exceptions, so in order to get details about a ConnectException, i need to use getCause() on the ClientTransportException that will be thrown.
Even worse: I tried to test the read timeout value, but there is none. I changed the service's location in the wsdl file to post the request to a php script that simply waits forever and does not return. Guess what: The web service client does not time out but waits forever as well (I killed the app after 30+ minutes of waiting). That is not an option for my application as i eventually run out of tcp connections if some of them get 'stuck'.
The enhanceAddress(auth, param, address) method is not implemented but annotated with javax.jws.* Annotations, meaning that i cannot see/change/inspect the code that is actually executed.
Do i have any option but to throw the whole wsimport/javax.jsw-stuff away and implement my own soap client?
to setup read-timeout and connect timeouts you can configure the binding parameters when you setup your Service and Port instances:
Service = new Service();
Port = Service.getPort();
((BindingProvider) Port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://localhost:8080/service");
((BindingProvider) Port).getRequestContext().put(
BindingProviderProperties.CONNECT_TIMEOUT,
30);
((BindingProvider) Port).getRequestContext().put(
BindingProviderProperties.REQUEST_TIMEOUT,
30);
now whenever you execute a service via "Port" you will get response timeouts and/or connection timeouts if the backend is slow to respond. the values follow the timeout values of the Socket Class.
when these timeouts are exceeded you will get timeout exeption or a connection exception and you can put counter-code to keep track of how many you get.