EDIT: removed reference to C# as the only accepted answer is about Java. If someone needs information about websocket server implementation in C#, ask a new question.
Do you know "production ready" framework for creating WebSockets Server in Java? I found one library http://nugget.codeplex.com/ but i did not know how it is stable and fast.
The accepted answer is 3 years old, with the recent release of JEE7, now every Web Containers that implement servert 3.1 will support websocket via standard API (javax.websocket) package.
The following code show example how to implement websocket using JEE7:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/chat")
public class ChatServer {
private static final Logger LOGGER =
Logger.getLogger(ChatServer.class.getName());
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
}
#OnMessage
public String onMessage(String message, Session session) {
LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
new Object[] {session.getId(), message});
return "Server received [" + message + "]";
}
#OnClose
public void onClose(Session session) {
LOGGER.log(Level.INFO, "Close connection for client: {0}",
session.getId());
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
}
Example in details here.
Web Container that support Websocket:
Tomcat 8
WildFly (Previously Jboss AS)
Glassfish 4.0
and much more
For Java, check out this informative post. Copy-paste from there:
Jetty WebSocket Server – Jetty has supported WebSockets since last September. This seems to be a good option.
Caucho Resin
jWebSocket
GlassFish/Grizzly (see a DZone posting on it here)
JBoss Netty (see patch here)
Webbit
Out of these options, I guess Jetty and Resin are the most mature and stable. However, always good to do your own testing.
The Vert.x option is also worth considering.
Creating a ws server can be as simple as
vertx.websocketHandler(new Handler<ServerWebSocket>() {
public void handle(ServerWebSocket ws) {
// A WebSocket has connected!
}
}).listen(8080);
or
vertx.createHttpServer().websocketHandler(new Handler<ServerWebSocket>() {
#Override
public void handle(final ServerWebSocket ws) {
logger.info("ws connection established with " + ws.remoteAddress());
ws.dataHandler(new Handler<Buffer>() {
#Override
public void handle(Buffer data) {
JsonObject item = new JsonObject(data.toString());
logger.info("data in -> " + item.encodePrettily());
// if you want to write something back in response to the client
//ws.writeTextFrame(...);
}
});
}
}).listen(port, new Handler<AsyncResult<HttpServer>>() {
#Override
public void handle(AsyncResult<HttpServer> event) {
logger.info("ws server is up and listening on port " + port);
}
});
For more details look here http://vertx.io/docs/vertx-core/java/#_websockets
So one can write his own WebSocket server with Vert.x, package it as FatJar, and run it on its own.
Or you can embed Vert.x env. in your app, and deploy your verticle (that implements the ws server) programmatically.
Another alternative is JBoss's web server Undertow. Which is easily embeddable in applications.
Add these dependencies:
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${version.io.undertow}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>${version.io.undertow}</version>
</dependency>
And here's a sample ws server:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(path()
.addPrefixPath("/myapp", websocket(new WebSocketConnectionCallback() {
#Override
public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) {
channel.getReceiveSetter().set(new AbstractReceiveListener() {
#Override
protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
final String messageData = message.getData();
for (WebSocketChannel session : channel.getPeerConnections()) {
WebSockets.sendText(messageData, session, null);
}
}
});
channel.resumeReceives();
}
}))
.build();
server.start();
Take a look at the Bristleback Framework. It is a high level overlay for commonly used Java Websocket Servers, like Jetty, Netty or Tomcat. If you like Spring Framework, you must definitely try Bristleback!
Disclaimer: I'm a contributor in Bristleback Framework project.
Apache Tomcat 8.0 implements WebSockets 1.1 API (JSR-356). You can even play with examples after installing by navigating to examples folder: there are echo chat and snake game.
JETTY
I've spent the past week mauling over how to make a WebSocket server. Finally got something to work hope this helps. It uses libraries from Jetty (jars).
File WebRTC_IceServer.java
package com.evanstools;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.websocket.server.*;
public class WebRTC_IceServer{
public static void main(String[] args){
try{
////////////////////////
if(args.length == 0){
System.out.printf("%s%n","WebRTC_IceServer [port]");
return;
}
Server server = new Server(Integer.parseInt(args[0]));
WebSocketHandler.Simple webSocketHandlerSimple = new WebSocketHandler.Simple(WebsocketPOJO.class);
server.setHandler(webSocketHandlerSimple);
server.start();
server.join();
////////////////////////
}catch(Exception w){w.printStackTrace();}
}
}
File WebsocketPOJO.java
package com.evanstools;
import org.eclipse.jetty.websocket.api.annotations.*;
import org.eclipse.jetty.websocket.api.Session;
//The class must be not abstract and public.
#WebSocket
public class WebsocketPOJO{
//Flags one method in the class as receiving the On Connect event.
//Method must be public, not abstract, return void, and have a single Session parameter.
#OnWebSocketConnect
public void onWebSocketConnect(Session session){
System.out.printf("%s%n","test client connected");
}
//Flags one method in the class as receiving the On Close event.
//Method signature must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
////int closeCode (required)
////String closeReason (required)
#OnWebSocketClose
public void OnWebSocketClose(Session session,int closeCode,String closeReason){}
//Flags up to 2 methods in the class as receiving On Message events.
//You can have 1 method for TEXT messages, and 1 method for BINARY messages.
//Method signature must be public, not abstract, and return void.
//The method parameters for Text messages:
////Session (optional)
////String text (required)
//The method parameters for Binary messages:
////Session (optional)
////byte buf[] (required)
////int offset (required)
////int length (required)
#OnWebSocketMessage
public void onWebSocketMessageString(Session session, String text){}
//Flags one method in the class as receiving Error events from the WebSocket implementation.
//Method signatures must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
////Throwable cause (required)
//#OnWebSocketError
//Flags one method in the class as receiving Frame events from the WebSocket implementation after they have been processed by any extensions declared during the Upgrade handshake.
//Method signatures must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
///Frame (required)
//The Frame received will be notified on this method, then be processed by Jetty, possibly resulting in another event, such as On Close, or On Message. Changes to the Frame will not be seen by Jetty.
//#OnWebSocketFrame
}
Related
I am having trouble finding the source of this error. I implemented a simple service using protobuf:
syntax = "proto3";
package tourism;
service RemoteService {
rpc Login(LoginUserDTO) returns (Response) {}
}
message AgencyDTO{
int32 id=1;
string name=2;
string email=3;
string password=4;
}
message LoginUserDTO{
string password=1;
string email=2;
}
message SearchAttractionsDTO{
string name=1;
int32 start_hour=2;
int32 start_minute=3;
int32 stop_hour=4;
int32 stop_minute=5;
AgencyDTO loggedUser=6;
}
message AttractionDTO{
int32 id=1;
string name=2;
string agency=3;
int32 hour=4;
int32 minute=5;
int32 seats=6;
int32 price=7;
}
message ReservationDTO{
int32 id=1;
string first_name=2;
string last_name=3;
string phone=4;
int32 seats=5;
AttractionDTO attraction=6;
AgencyDTO agency=7;
}
message Response{
enum ResponseType{
OK=0;
NOT_LOGGED_ID=1;
SERVER_ERROR=2;
VALIDATOR_ERROR=3;
}
ResponseType type=1;
AgencyDTO user=2;
string message=3;
}
When using a java client everything works fine, the server receives the request and responds appropriately. When using C# with the same .proto file for generating sources at the client.Login() I get the following errror: Grpc.Core.RpcException Status(StatusCode=Unimplemented, Detail="Method tourism.RemoteService/Login is unimplemented"). The server receives the request but does not have time to respond and throws:
INFO: Request from ex#ex.com
May 22, 2017 12:28:58 AM io.grpc.internal.SerializingExecutor run
SEVERE: Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2#4be43082
java.lang.IllegalStateException: call is closed
at com.google.common.base.Preconditions.checkState(Preconditions.java:174)
at io.grpc.internal.ServerCallImpl.sendHeaders(ServerCallImpl.java:103)
at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:282)
at ServiceImp.login(ServiceImp.java:20)
at tourism.RemoteServiceGrpc$MethodHandlers.invoke(RemoteServiceGrpc.java:187)
at io.grpc.stub.ServerCalls$1$1.onHalfClose(ServerCalls.java:148)
at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:262)
at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2.runInContext(ServerImpl.java:572)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:52)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:117)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Java server:
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import tourism.RemoteServiceGrpc;
import tourism.Service;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by Andu on 21/05/2017.
*/
public class ServerGrpc {
Logger logger= Logger.getLogger(ServerGrpc.class.getName());
private final Server server;
private final int port;
public ServerGrpc(int p){
port=p;
server= ServerBuilder.forPort(port).addService(new ServiceImp()).build();
}
public void start() throws IOException {
server.start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
// Use stderr here since the logger may has been reset by its JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
ServerGrpc.this.stop();
System.err.println("*** server shut down");
}
});
}
public void stop() {
if (server != null) {
server.shutdown();
}
}
void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
private class ServiceImp extends RemoteServiceGrpc.RemoteServiceImplBase {
Logger log=Logger.getLogger(ServiceImp.class.getName());
#Override
public void login(Service.LoginUserDTO request, StreamObserver<Service.Response> responseStreamObserver){
super.login(request,responseStreamObserver);
log.log(Level.INFO,"Request from "+request.getEmail());
Service.Response response= Service.Response.newBuilder().setMessage("Hello "+request.getEmail()+", I know your password: "+request.getPassword()).build();
responseStreamObserver.onNext(response);
responseStreamObserver.onCompleted();
}
}
}
C# Client:
namespace testGrpc2
{
class MainClass
{
public static void Main(string[] args)
{
var channel = new Channel("127.0.0.1:61666",ChannelCredentials.Insecure);
var client = new RemoteService.RemoteServiceClient(channel);
Response response=client.Login(new LoginUserDTO{Email="ex#ex.com",Password="notmypassword"});
Console.WriteLine(response);
Console.ReadKey();
}
}
}
I managed to find the source of the problem. For anyone else having this problem:
Make sure your .proto file is identical for both client and server and it has the same package. When the client calls a method on the remote server, it uses the full name of the remote class and the package.
However this was not the reason why the method appeared as unimplemented to the client. It was this:
super.login(request,responseStreamObserver);
Calling the super method login sends an async UNIMPLEMENTED error code back to the client. This is the login() method in the generated class:
public void login(LoginUserDTO request,StreamObserver<Response> responseObserver) {
asyncUnimplementedUnaryCall(METHOD_LOGIN, responseObserver);
}
So make sure in the implementation of your service methods you don't call the super method as it will appear to the client as UNIMPLEMENTED. If you generate #Override methods using IntelliJ IDEA it will add the super method call. Make sure to delete it.
For me it was that I forget adding endpoint of gRpc service in startup class.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
//Add your endpoint here like this
endpoints.MapGrpcService<YourProtoService>();
});
For me, using the C# client, the problem was that I wasn't overriding the generated service method.
Thanks to Alexandru - this helped solve my problem with Akka gRPC client and Python grPC server. In my case, I had same packages and preamble in .proto file but had eliminated message classes and gRPC functions not needed for this specific use case in the Python gRPC server. When I made the .proto files identical, everything worked and I no longer received UNIMPLEMENTED errors. This is needed for languages beyond the C#/Java example cited. Thanks again.
My server and client were both java, and the problem was removed after closing and opening the project in IntelliJ!!
I need to implement front-end for Server-Sent-Event. I use GWT, and i can not find any solution to create a listener for SSE. I need to push the data from server and to receive it on client every time hen data was changed. So for now i have a something like this:
private void method() {
final EventSource eventSource = EventSource.newEventSourceIfSupported();
if (null != eventSource) {
eventSource.setListener(this);
eventSource.open(GWT.getHostPageBaseURL() + "rest/myresource");
}
}
#Override
public void onOpen(EventSource eventSource) {
Window.alert("Open");
}
#Override
public void onClose(EventSource eventSource) {
Window.alert("onClose");
}
#Override
public void onMessage(EventSource eventSource, String lastEventId, String type, String data) {
Window.alert("lastEventId: " + lastEventId);
Window.alert("type: " + type);
Window.alert("data: " + data);
}
#Override
public void onError(EventSource eventSource) {
Window.alert("onError");
}
my class implements EventSourceListener
But it does not work. Actually this code reacting only when connection is opened, but it is impossible to receive any message from server. Do somebody know how to deal the issue with receiving data on client using GWT?
There are so many methods exist in GWT for push back services like a GWT Event Services enter link description here
In order for the server to initiate a request to the client, you will need to use WebSockets, and experimental HTML5 feature currently only supported by Chrome.
Or, to simulate this kind of interaction, you can use Comet (long-polling), made available in GWT by the rocket-gwt project.
I have to make a work with BDI Agents and for that i will use JADEX 2.4 but i have a big problem. The documentation is a bit poor and i can't exchange messages between agents.
I have read this article http://www.activecomponents.org/bin/view/AC+Tutorial/05+Provided+Services
And i'm trying make the same thing on my code but no success. I need to know how to do 2 things for make my work: send a message from one agent to other, and send a message from one agent to all agents. Anyone knows how to do that?
The code that i have is the following:
ChatSystem.java
package agents;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import ....
#Service
public class ChatSystem implements IChatService{
#ServiceComponent
protected IInternalAccess agent;
protected IClockService clock;
protected DateFormat format;
#ServiceStart
public IFuture<IClockService> startService(){
format = new SimpleDateFormat("hh:mm:ss");
final Future<IClockService> ret = new Future<IClockService>();
IFuture<IClockService> fut = agent.getServiceContainer().getRequiredService("clockservice");
fut.addResultListener(new DelegationResultListener<IClockService>(ret)
{
public void customResultAvailable(IClockService result)
{
clock = result;
super.customResultAvailable(null);
}
});
return ret;
}
#Override
public IFuture<Void> message(String nick, String text,
boolean privatemessage) {
// TODO Auto-generated method stub
//System.out.println(" received at" + text);
System.out.println(agent.getComponentIdentifier().getLocalName()+" received at "
+" from: "+nick+" message: "+text);
return null;
}
}
HelperAgent.java
package agents;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import .....
#Agent
#Service
#RequiredServices({#RequiredService(name="clockservice", type=IClockService.class,binding=#Binding(scope=RequiredServiceInfo.SCOPE_PLATFORM)),#RequiredService(name="chatservices", type=IClockService.class,binding=#Binding(scope=RequiredServiceInfo.SCOPE_PLATFORM,dynamic=true),multiple=true)})
#ProvidedServices(#ProvidedService(type=IChatService.class, implementation=#Implementation(ChatSystem.class)))
public class HelperAgent {
#Agent
protected MicroAgent agent;
#AgentBody
public void AgentBody()
{
IFuture<IClockService> fut = agent.getServiceContainer().getRequiredService("clockservice");
fut.addResultListener(new DefaultResultListener<IClockService>()
{
public void resultAvailable(IClockService cs)
{
System.out.println("Time for a chat, buddy: "+new Date(cs.getTime()));
}
});
IFuture<Collection<IChatService>> chatservices = agent.getServiceContainer().getRequiredServices("chatservices");
chatservices.addResultListener(new DefaultResultListener<Collection<IChatService>>()
{
public void resultAvailable(Collection<IChatService> result)
{
for(Iterator<IChatService> it=result.iterator(); it.hasNext(); )
{
IChatService cs = it.next();
cs.message(agent.getComponentIdentifier().getName(), "test",false);
}
}
});
}
}
Anyone can help me?
Regards
In Jadex you work with active components representing enhanced agents, i.e. in addition to sending and receiving messages you can work with services. Agents can expose services using Java interfaces and other agents can simply fetch these services via their type. Using services communication is done without having to know agent identifities. This helps in building more SOA driven solutions dynamic service providers.
If you want to communicate via messages the API depends on the type of component you are using. In case of micro agents (as shown in your snippets) you can just prepare a FIPA message and call sendMessage on the agent API as shown below:
Map msg = new HashMap();
msg.put(SFipa.CONTENT, content);
msg.put(SFipa.PERFORMATIVE, SFipa.QUERY_IF);
msg.put(SFipa.CONVERSATION_ID, "someuniqueid");
msg.put(SFipa.RECEIVERS, new IComponentIdentifier[]{receiver});
msg.put(SFipa.SENDER, getComponentIdentifier());
agent.sendMessage(msg, SFipa.FIPA_MESSAGE_TYPE);
with 'agent' being the injected MicroAgent.
Kind regards
Lars
I'm doing my first steps with RMI, and I have a simple question.
I have a .jar file which has the implementation of several methods from a library.
I want to call this methods in the .jar file using RMI.
What I'm trying is to create a kind of a wrapper to do it.
So, I'm working on something like this:
Interface class: This interface has the methods to be implemented by the remote object.
Implementation class: This class, has the implementation of the interface methods, each implementation calls the corresponding method in the .jar file. E.g., the jar file has a method called getDetails(), and it returns a "ResponseDetail" object. ResponseDetail is a response class I have in the .jar.
Server class: it binds the methods to the rmiregistry
Client class: it will consume the methods implemented in implementation.
So far so good? :)
Now, I have a lib folder where resides the .jar file.
In the server machine I have deployed the Interface, Implementation and Server classes. I've generated the stub, and I ran the rmiregistry successfully, but, with these details:
To start the rmiregistry, I had to set the classpath in the command line to reference the .jar files, otherwise I get the java.lang.NoClassDefFoundError. I did it with this .sh file:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
rmiregistry -J-classpath -J".:${THE_CLASSPATH}"
To start the server, I had to set the classpath as well to reference the .jar files, otherwise, I get the java.lang.NoClassDefFoundError. I've used something like this:
THE_CLASSPATH=
for i in `ls ./lib/*.jar` do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" Server
Client machine:
To run the Client.class file from the client machine, I had to copy the .jar files to it, and make reference to them in the classpath, because otherwise, it does not run and I get the java.lang.NoClassDefFoundError. I had to use this on the client machine:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" HelloClient
Is this ok? I mean, do I have to copy the .jar files to the client machine to execute methods through RMI?
Prior to JDK v5 one had to generate the RMI stubc using the rmic (RMI Compiler). This is done automatically from JDK v5 on. Moreover, you can start the RMI Registry from within the Java code as well. To start with a simple RMI application you may want to follow the following steps:
Create the interface:
import java.rmi.*;
public interface SomeInterface extends Remote {
public String someMethod1() throws RemoteException;
public int someMethod2(float someParameter) throws RemoteException;
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException;
}
Implement the interface:
import java.rmi.*;
import java.rmi.server.*;
public class SomeImpl extends UnicastRemoteObject implements SomeInterface {
public SomeImpl() throws RemoteException {
super();
}
public String someMethod1() throws RemoteException {
return "Hello World!";
}
public int someMethod2( float f ) throws RemoteException {
return (int)f + 1;
}
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException {
int i = someStruct.getInt();
float f = someStruct.getFloat();
someStruct.setInt(i + 1);
someStruct.setFloat(f + 1.0F);
return someStruct;
}
}
Implement a non-primitive serializable object that is to be passed between a client and the server:
import java.io.*;
public class SomeStruct implements Serializable {
private int i = 0;
private float f = 0.0F;
public SomeStruct(int i, float f) {
this.i = i;
this.f = f;
}
public int getInt() {
return i;
}
public float getFloat() {
return f;
}
public void setInt(int i) {
this.i = i;
}
public void setFloat(float f) {
this.f = f;
}
}
Implement the server:
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.net.*;
import java.io.*;
public class SomeServer {
public static void main(String args[]) {
String portNum = "1234", registryURL;
try{
SomeImpl exportedObj = new SomeImpl();
startRegistry( Integer.parseInt(portNum) );
// register the object under the name "some"
registryURL = "rmi://localhost:" + portNum + "/some";
Naming.rebind(registryURL, exportedObj);
System.out.println("Some Server ready.");
} catch (Exception re) {
System.out.println("Exception in SomeServer.main: " + re);
}
}
// This method starts a RMI registry on the local host, if it
// does not already exist at the specified port number.
private static void startRegistry(int rmiPortNum) throws RemoteException{
try {
Registry registry = LocateRegistry.getRegistry(rmiPortNum);
registry.list( );
// The above call will throw an exception
// if the registry does not already exist
} catch (RemoteException ex) {
// No valid registry at that port.
System.out.println("RMI registry is not located at port " + rmiPortNum);
Registry registry = LocateRegistry.createRegistry(rmiPortNum);
System.out.println("RMI registry created at port " + rmiPortNum);
}
}
}
Implement the client:
import java.io.*;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class SomeClient {
public static void main(String args[]) {
try {
String hostName;
String portNum = "1234";
String registryURL = "rmi://localhost:" + portNum + "/some";
SomeInterface h = (SomeInterface)Naming.lookup(registryURL);
// invoke the remote method(s)
String message = h.someMethod1();
System.out.println(message);
int i = h.someMethod2(12344);
System.out.println(i);
SomeStruct someStructOut = new SomeStruct(10, 100.0F);
SomeStruct someStructIn = new SomeStruct(0, 0.0F);
someStructIn = h.someStructTest(someStructOut);
System.out.println( someStructIn.getInt() );
System.out.println( someStructIn.getFloat() );
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
A larger client-server application should be divided into three modules:client, server, and common (for classes shared between the server and client code, i.e. the remote interface and the non-primitive object in this example). The client application will then be created from client + common modules on the classpath and the server from server + common modules on the classpath.
I used this example many years ago to learn basics of RMI and it still works. However it is far from being perfect (default Java package used, incorrect exception handling, hostname and port parameters are hard-coded and not configurable, etc.)
Nevertheless, it is good for starters. All the files can be placed in one directory and compiled using the simple javac *.java command. The server application can then be started using the java SomeServer and the client one by launching the java SomeClient command.
I hope this helps to understand the Java RMI which is, in fact, far more complicated than just this.
You shouldn't be generating stubs (if you are following a tutorial, it is way old). you can run the client without necessarily having the jars locally (using remote classloading), but it's way easier to do it this with the jars available locally (i've personally done a fair bit of RMI and never actually deployed a system with remote classloading). typically, you want 2 jars, a "client" jar with just the remote interfaces (and any Serializable classes used by those interfaces) and a "server" jar which includes the implementation classes. you would then run the server with the server jar, and the rmiregistry/client with the client jars.
This is a pretty good (up to date and simple) getting started guide.
To say it in short what the other answers elaborated:
The client needs only the common interfaces (and the client classes), not the server implementation.
The server needs interfaces and implementation (and your server main class).
The rmiregistry needs only the interfaces.
(Actually, you can start your own registry inside the server process - then you don't need the rmiregistry at all. Have a look at the createRegistry methods in the java.rmi.registry.LocateRegistry class.)
"Interfaces" here means both the remote interfaces and any (serializable) classes used by these as parameter or argument types.
How you distribute these classes to jar files is independent of this.
I have an application that needs to make a SOAP client request to a system on the Internet, so it needs to go though our HTTP proxy.
One can do this by setting system-wide values such as system properties:
// Cowboy-style. Blow away anything any other part of the application has set.
System.getProperties().put("proxySet", "true");
System.getProperties().put("https.proxyHost", HTTPS_PROXY_HOST);
System.getProperties().put("https.proxyPort", HTTPS_PROXY_PORT);
Or by setting the default ProxySelector (also a system-wide setting):
// More Cowboy-style! Every thing Google has found says to do it this way!?!?!
ProxySelector.setDefault(new MyProxySelector(HTTPS_PROXY_HOST, HTTPS_PROXY_PORT));
Neither of these is a wise choice if there is the possibility of other subsystems wanting to access web servers via different HTTP proxies or without any proxy. Using the ProxySelector would let me configure which connections use the proxy, but I would have to figure that out for every single thing in the huge application.
A reasonable API would have a method that took a java.net.Proxy object just like the java.net.Socket(java.net.Proxy proxy) constructor does. That way the necessary settings are local to the part of the system that needs to set them. Is there some way to do this with a JAX-WS?
I do not want to set a system-wide proxy configuration.
I recommend using a custom ProxySelector. I had the same problem and it works great and is super flexible. It's simple too.
Here's my CustomProxySelector:
import org.hibernate.validator.util.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* So the way a ProxySelector works is that for all Connections made,
* it delegates to a proxySelector(There is a default we're going to
* override with this class) to know if it needs to use a proxy
* for the connection.
* <p>This class was specifically created with the intent to proxy connections
* going to the allegiance soap service.</p>
*
* #author Nate
*/
class CustomProxySelector extends ProxySelector {
private final ProxySelector def;
private Proxy proxy;
private static final Logger logger = Logger.getLogger(CustomProxySelector.class.getName());
private List<Proxy> proxyList = new ArrayList<Proxy>();
/*
* We want to hang onto the default and delegate
* everything to it unless it's one of the url's
* we need proxied.
*/
CustomProxySelector(String proxyHost, String proxyPort) {
this.def = ProxySelector.getDefault();
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, (null == proxyPort) ? 80 : Integer.valueOf(proxyPort)));
proxyList.add(proxy);
ProxySelector.setDefault(this);
}
#Override
public List<Proxy> select(URI uri) {
logger.info("Trying to reach URL : " + uri);
if (uri == null) {
throw new IllegalArgumentException("URI can't be null.");
}
if (uri.getHost().contains("allegiancetech")) {
logger.info("We're trying to reach allegiance so we're going to use the extProxy.");
return proxyList;
}
return def.select(uri);
}
/*
* Method called by the handlers when it failed to connect
* to one of the proxies returned by select().
*/
#Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
logger.severe("Failed to connect to a proxy when connecting to " + uri.getHost());
if (uri == null || sa == null || ioe == null) {
throw new IllegalArgumentException("Arguments can't be null.");
}
def.connectFailed(uri, sa, ioe);
}
}
If you are using JAX-WS you might be able to set the socket factory used by the underlying HttpURLConnection. I see vague signs that this is possible for SSL (see HTTPS SSLSocketFactory) but I'm not certain if you can do that for regular HTTP connections (or quite frankly how that even works: the JAXWSProperties class they reference appears to be a non-standard JDK class).
If you can set the socket factory then you can configure a custom socket factory that uses the specific proxy you want.