Hello I am trying to create an RMI programm that sends and receives data from a server. However after I create my registries and look them up etc, and point my program to a method in the interface it throws itself into an integerpage (via debugger). my code is as follows
For the client
public static void SendData(int score,String name) throws RemoteException, NotBoundException {
try {
Registry reg = LocateRegistry.getRegistry("127.0.0.1",1099);
TestRemote remote = (TestRemote) reg.lookup("TestRMI");
remote.SendMyData(score,name);
} catch (Exception e) {
String ex = e.toString();
}
For the server
public class RMIserver {
public static void main(String[] args ) throws RemoteException, AlreadyBoundException {
RemoteImp imp = new RemoteImp();
Registry reg = LocateRegistry.createRegistry(1099);
reg.rebind("TestRMI", imp);
System.out.println("Server is Started");
}
}
Interface
public interface TestRemote extends Remote {
public ArrayList<TempPlayer> getOpdata() throws RemoteException;
public void SendMyData(int score, String player) throws RemoteException;}
And for the interface implementation:
private static final long serialVersionUID = 1L;
private ArrayList<TempPlayer> opdata = new ArrayList<TempPlayer>();
private ArrayList<String> lobbydata = new ArrayList<String>();
protected RemoteImp() throws RemoteException
{
}
#Override
public ArrayList<TempPlayer> getOpdata() throws RemoteException {
return opdata;
}
#Override
public void SendMyData(int score, String name) throws RemoteException {
//opdata.add(String.valueOf(score));
for (TempPlayer player : opdata) {
if (player.player == name) {
player.setScore(score);
} else {
opdata.add(new TempPlayer(score, name));
}
}
}
}
Now, when I try to invoke SendData by calling Remote.senddata, it goes to the Integer.java page. My question now is what could cause this and how do I get the program to actually go to the function I want it to go to?
Related
I have an interface, for example:
interface MyService {
String sayHello(Object who) throws ServiceException;
}
And now I need use this interface with RMI. Of course I can define another interface like:
interface MyService extends Remote{
String sayHello(Object who) throws RemoteException;
}
and then adapt my implemention class to the RMI interface.
But I have hundreds interfaces to convert to RMI. Write hundreds classes with same logic is so boring and ugly.
So is there a simple way to use these interfaces in RMI?
This is real scene in my work. And I used dynamic bytecode to do the hundurds work in one time.
First, here is my old code demo (without RMI).
class ServiceException extends Exception {
public ServiceException(String msg) {
super(msg);
}
}
interface MyService {
String sayHello(Object who) throws ServiceException;
void throwIt() throws ServiceException;
}
class MyServiceImpl implements MyService {
#Override
public String sayHello(Object who) throws ServiceException {
String hello = who.toString();
System.out.println("Server said: " + hello);
return "Hello! " + hello;
}
#Override
public void throwIt() throws ServiceException {
throw new ServiceException("throw in server");
}
}
And I use Javassist to convert the interface to RMI interface:
public static Class<? extends Remote> toRemoteInterface(Class<?> inter) throws Exception {
return cache("toRemote", inter, () -> uncheck(() -> {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.getAndRename(inter.getName(), inter.getName() + "$RemoteVersion");
cc.setModifiers(Modifier.PUBLIC | cc.getModifiers());
cc.addInterface(pool.get(Remote.class.getName()));
for (CtMethod cm : cc.getMethods()) {
cm.setExceptionTypes(new CtClass[] { pool.getCtClass(RemoteException.class.getName()) });
}
cc.writeFile();
return cc.toClass();
}));
}
Then, use Cglib to convert between the remote object and the local object:
public static <T> T fromRemote(Remote remote, Class<T> inter) throws Exception {
Enhancer e = new Enhancer();
e.setInterfaces(new Class[] { inter });
e.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
Method remoteMethod = remote.getClass().getMethod(method.getName(), method.getParameterTypes());
try {
return remoteMethod.invoke(remote, args);
} catch (InvocationTargetException ex) {
Throwable targetException = ex.getTargetException();
while (targetException instanceof RemoteException) {
targetException = targetException.getCause();
}
throw targetException;
}
});
return (T) e.create();
}
public static <T> Remote toRemote(T local, Class<T> inter) throws Exception {
Enhancer e = new Enhancer();
e.setSuperclass(UnicastRemoteObject.class);
e.setInterfaces(new Class[] { toRemoteInterface(inter) });
e.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
Method targetMethod = local.getClass().getMethod(method.getName(), method.getParameterTypes());
try {
return targetMethod.invoke(local, args);
} catch (InvocationTargetException ex) {
Throwable targetException = ex.getTargetException();
throw new RemoteException(targetException.getMessage(), targetException);
}
});
return (Remote) e.create();
}
Now we can use the non-rmi interface and its implementation just like it is RMI interface:
public static void startClient() throws Exception {
String stringURL = "rmi://127.0.0.1/" + MyService.class.getName();
toRemoteInterface(MyService.class);// define the Remote interface in client classloader
MyService service = fromRemote(Naming.lookup(stringURL), MyService.class);
String said = service.sayHello("Dean");
System.out.println("Client heard: " + said);
service.throwIt();
}
public static void startServer() throws Exception {
LocateRegistry.createRegistry(1099);
Remote remote = toRemote(new MyServiceImpl(), MyService.class);
Naming.rebind(MyService.class.getName(), remote);
System.out.println(remote);
System.out.println(remote.getClass());
System.out.println("Server started!");
}
For complete code, see this on github
I'm trying to make a custom "http" sever embedding a Jetty (verion 9) into my application.
The problem I'm facing right now is that Websocket Events are not being called.
This is what I have to so far (relevant parts):
SocketServer:
public class SocketServer
{
public static void main(String[] args) throws Exception
{
Server server = new Server(9091);
HandlerCollection handlerCollection = new HandlerCollection();
ServletContextHandler sch = new ServletContextHandler();
sch.addServlet(new ServletHolder(new RandomWebSocketServlet()), "");
handlerCollection.addHandler(sch);
server.setHandler(handlerCollection);
server.start();
server.join();
}
}
RandomWebSocketServlet:
public class RandomWebSocketServlet extends WebSocketServlet {
private static final long serialVersionUID = -1134228059326523215L;
public RandomWebSocketServlet() {
}
#Override
public void configure(WebSocketServletFactory factory) {
factory.setCreator(new AdvancedSocketCreator());
}
}
AdvancedSocketCreator:
public class AdvancedSocketCreator implements WebSocketCreator {
public AdvancedSocketCreator() {
}
#Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) {
return new Handler();
}
}
Handler:
#WebSocket
public class Handler {
protected Session session = null;
public Handler() {
}
#OnWebSocketConnect
public void onConnect(Session session) {
Log.log("WebSocket connected to client: "+session.getRemoteAddress().getHostName()+":"+session.getRemoteAddress().getPort());
this.session = session;
}
#OnWebSocketError
public void onError(Throwable t) {
Log.log("WebSocket error");
}
#OnWebSocketMessage
public void onMessage(String message) {
Log.log("Message: "+message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
Log.log("WebSocket closed: "+statusCode+" - "+reason);
}
}
When I try to open a connection (using telnet, for instance), the #OnWebSocketConnect onConnect method is not being called.
I tried many ways, following many internet tutorials... but with no success.
Any help?
I am writing a simple routing application. The idea is that I have servers or source nodes that receive transient clients connections that last for a period of x time. The messages received are decoded and then sent to a corresponding sink node or client that is/are already open depending on the details of the message. The Router class registers all channels and attemps to save them in maps so that it can filter and worj out the destination of the message. Once I get the destination, I should then be able to pick the actual sink node (could be of transient of persistent nature depending on the configurations) and send data to that channel wait for a response and then send it back to the originator. I'd like to know first if my implementation using netty is in the right direction ? and how can I pass a message received from any of the servers and send it to any of the clients and respond back to the originating source node ?
Below is my source code : It will / should give you an idea of what I am up to :Kindly use code examples in your explanation .
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
/*
* #author Kimathi
*/
public class Service {
private Nodes nodes;
public void start(){
nodes = new Nodes();
nodes.addSourceNodes(new SourceNodes()).
addSinkNodes(new SinkNodes()).
addConfigurations(new Configurations()).
boot();
}
public void stop(){
nodes.stop();
}
public static void main(String [] args){
new Service().start();
}
}
class Nodes {
private SourceNodes sourcenodes;
private SinkNodes sinknodes ;
private Configurations configurations;
public Nodes addConfigurations(Configurations configurations){
this.configurations = configurations;
return this;
}
public Nodes addSourceNodes(SourceNodes sourcenodes){
this.sourcenodes = sourcenodes;
return this;
}
public Nodes addSinkNodes(SinkNodes sinknodes){
this.sinknodes = sinknodes;
return this;
}
public void boot(){
Router router = new Router(configurations);
sourcenodes.addPort(8000).
addPort(8001).
addPort(8002);
sourcenodes.addRouter(router);
sourcenodes.boot() ;
sinknodes.addRemoteAddress("127.0.0.1", 6000).
addRemoteAddress("127.0.0.1", 6001).
addRemoteAddress("127.0.0.1", 6002);
sinknodes.addRouter(router);
sinknodes.boot();
}
public void stop(){
sourcenodes.stop();
sinknodes.stop();
}
}
final class SourceNodes implements Bootable , Routable {
private List <Integer> ports = new ArrayList();
private ServerBootstrap serverbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SourceNodes addPort(int port){
this.ports.add(port);
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.serverbootstrap.setOption("child.tcpNoDelay", true);
this.serverbootstrap.setOption("child.keepAlive", true);
this.serverbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SourceHandler(router));
}
});
for(int port:this.ports){
this.serverbootstrap.bind(new InetSocketAddress(port));
}
}
#Override
public void stop(){
this.serverbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.serverbootstrap = new ServerBootstrap(factory);
}
}
final class SinkNodes implements Bootable , Routable {
private List<SinkAddress> addresses= new ArrayList();
private ClientBootstrap clientbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SinkNodes addRemoteAddress(String hostAddress,int port){
this.addresses.add(new SinkAddress(hostAddress,port));
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.clientbootstrap.setOption("tcpNoDelay", true);
this.clientbootstrap.setOption("keepAlive", true);
this.clientbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SinkHandler(router));
}
});
for(SinkAddress address:this.addresses){
this.clientbootstrap.connect(new InetSocketAddress(address.hostAddress(),address.port()));
}
}
#Override
public void stop(){
this.clientbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.clientbootstrap = new ClientBootstrap(factory);
}
private class SinkAddress {
private final String hostAddress;
private final int port;
public SinkAddress(String hostAddress, int port) {
this.hostAddress = hostAddress;
this.port = port;
}
public String hostAddress() { return this.hostAddress; }
public int port() { return this.port; }
}
}
class SourceHandler extends SimpleChannelHandler {
private Router router;
public SourceHandler(Router router){
this.router = router;
}
#Override
public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
System.out.println("child is opened");
}
#Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("child is closed");
}
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Server is opened");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
class SinkHandler extends SimpleChannelHandler {
private Router router;
public SinkHandler(Router router){
this.router = router;
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Channel is connected");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
final class Router {
private Configurations configurations;
private Map sourcenodes = new HashMap();
private Map Sinknodes = new HashMap();
public Router(){}
public Router(Configurations configurations){
this.configurations = configurations;
}
public synchronized boolean submitSource(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
public synchronized boolean submitSink(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
}
final class Configurations {
public Configurations(){}
}
interface Bootable {
public abstract void boot();
public abstract void stop();
}
interface Routable {
public abstract void addRouter(Router router);
}
The idea seems reasonable.
The source channel handler can just write to the corresponding sink channel, using Channel#write(...), and vice versa on the reply.
Of course, you also need a way to correlate the source channel with the reply, and how that is best done depends an the nature of the protocol. The best alternative, if possible, is to somehow encode the source channel id in the message to the sink channel (and also in the reply, of course).
If that is not possible, you will somehow have to maintain the correlation. A FIFO queue per sink channel may be appropriate if the replies are guaranteed to pair up with the sent requests.
I have an application which consists of two parts as server and client.
It works like this :
Client connects to the server and sends a string; server receives the string and returns an ArrayList (by converting string) which contains 10000 elements.
I wrote a class (ClientConnector.java) which simulates many clients use one connection to take those 10000 elements from server.
When I run this two programs, server side is ok. However on the client side, used heap is always increasing ! I tried to release the used objects by "null" but the used memory is still getting larger and larger.
http://s10.postimage.org/egf4ugrd5/mem.png
My Server Side Codes :
Client.java
public class Client {
private static final int PORT = 7571;
ClientHandler handler = new ClientHandler("hey");
IoConnector connector;
boolean available = true;
public synchronized void setAvailable(boolean available) {
this.available = available;
}
public synchronized boolean isAvailable() {
return available;
}
public void starter() throws InterruptedException {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20 * 150000);
t.setDecoderMaxLineLength(20 * 150000);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
connector.setHandler(handler);
ConnectFuture future = connector.connect(new InetSocketAddress("localhost", PORT));
future.awaitUninterruptibly();
if (!future.isConnected()) {
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
});
t.start();
Thread.sleep(300);
}
public void conClose() {
connector.dispose();
}
public ClientHandler getHandler() {
return handler;
}
public void reqInf() {
handler.reqInfo();
}
public static void main(String[] args) {
try {
Client c = new Client();
c.starter();
} catch (InterruptedException ex) {
System.out.println("error");
}
}
}
ClientHandler.java
public class ClientHandler extends IoHandlerAdapter {
long time;
private final String values;
IoSession session;
public ClientHandler(String values) {
this.values = values;
}
#Override
public void sessionOpened(IoSession session) throws InterruptedException {
this.session = session;
}
public ArrayList<String> convert(String str) {
Gson gson = new Gson();
return gson.fromJson(str, ArrayList.class);
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
try {
ArrayList<String> test = convert(message.toString());
System.out.println("TIME : " + (System.currentTimeMillis() - time) + " strList:" + test.size());
message = null;
test = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
System.out.println(cause.toString());
}
#Override
public void sessionClosed(IoSession session) {
System.out.println("Connection Lost");
}
public void reqInfo() {
time = System.currentTimeMillis();
session.write("test");
}
}
My Server Side :
Server.java
public class Server {
private static final int PORT = 7571; //TEST PORT
IoAcceptor acceptor = new NioSocketAcceptor();
public Server() throws IOException {
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20*150000);
t.setDecoderMaxLineLength(20*150000);
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
// acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
Executor executor = new ThreadPoolExecutor(5, 70, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(executor));
acceptor.setHandler(new ServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
//timer();
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("***Mina Server is ready !");
System.out.println("");
System.out.println("");
}
public static void main(String[] args) throws IOException {
Server m = new Server();
}
}
ServerHandler.java
public class ServerHandler extends IoHandlerAdapter {
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
IoSession sessions;
//Communication communication;
public ServerHandler() throws IOException {
loader();
// communication = new Communication(this);
}
#Override
public void sessionOpened(IoSession session) {
// set idle time to 10 seconds
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
System.out.println("Client Connected !!!");
//session.setAttribute("Values: ");
this.sessions = session;
}
public String toGSon(ArrayList<String> list) {
Gson gson = new Gson();
String str = gson.toJson(list);
return str;
}
ArrayList<String> str = new ArrayList<String>();
public void loader() {
for (int i = 0; i < 10000; i++) {
str.add("test" + i);
}
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
long time = System.currentTimeMillis();
session.write(toGSon(str));
System.out.println("TIME : " + (System.currentTimeMillis() - time));
}
#Override
public void sessionIdle(IoSession session, IdleStatus status) {
System.out.println("Socket #" + session.getId() + " is disconnecting... (IDLE)");
session.close();
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
System.out.println("------------>" + cause.toString());
session.close();
}
}
And my Main Class
public class ClientConnector {
public ClientConnector() throws InterruptedException {
Client cl = new Client();
cl.starter();
while (true) {
cl.reqInf();
Thread.sleep(100);
}
}
public static void main(String[] args) throws InterruptedException {
ClientConnector cl = new ClientConnector();
}
}
You must remove below code from client side.
session.getConfig().setUseReadOperation(true);
Above code will cause memory leak.
One of our developers found an issue in Mina with the way clean up was being done and a patch was applied to version 2.0.8. Since as of today this is "snapshot" you have to grab it from git and build it yourself. Here is the command to get it from git:
git checkout 2.0
Repository uri:
git clone http://git-wip-us.apache.org/repos/asf/mina.git
This code is not enough to reach to a pin pointed answer.
Heap size continuous increase and no effect of GC --> Signs of memory leak.
Probably you should Profile your application and use some OQL Tools to find out which class is using char[], which here is the culprit looking at heap dump in your case
For Example
SvrInterface si1 = (SvrInterface) Naming.lookup(Address);
SvrInterface si2 = (SvrInterface) Naming.lookup(Address);
si1.setUser ("User1");
si2.setUser ("User2");
And Next
String si1User = si1.getUser();
Will the result of si1User become "User1" ?
The simple answer in your case is No. You're still referencing the same remote object in registry bound to the address. Good place to begin learning more about RMI architecture > here.
EDIT 1
Simple RMI Factory example I whipped up quickly...
EchoService
public interface EchoService extends Remote, Serializable{
String echo(String msg) throws RemoteException;
String getUser() throws RemoteException;
void setUser(String user) throws RemoteException;
}
EchoServiceImpl
public class EchoServiceImpl extends UnicastRemoteObject implements EchoService {
private static final long serialVersionUID = -3671463448485643888L;
private String user;
public EchoServiceImpl() throws RemoteException {
super();
}
#Override
public String echo(String msg) throws RemoteException {
return this.user + ": " + msg;
}
#Override
public String getUser() throws RemoteException {
return this.user;
}
#Override
public void setUser(String user) throws RemoteException {
this.user = user;
}
}
EchoServiceFactory
public interface EchoServiceFactory extends Remote {
EchoService createEchoService() throws RemoteException;
}
EchoServiceFactoryImpl
public class EchoServiceFactoryImpl extends UnicastRemoteObject implements
EchoServiceFactory {
private static final long serialVersionUID = 6625883990856972736L;
protected EchoServiceFactoryImpl() throws RemoteException {
super();
System.setProperty("java.rmi.server.codebase", EchoServiceFactory.class.getProtectionDomain().getCodeSource().getLocation().toString());
System.setProperty("java.security.policy", "/java.policy");
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
Registry registry = LocateRegistry.getRegistry("localhost");
registry.rebind("EchoService", this);
System.out.println("Echo service factory registered.");
} catch (Exception e) {
System.err.println("Error registering echo service factory: "
+ e.getMessage());
}
}
#Override
public EchoService createEchoService() throws RemoteException {
return new EchoServiceImpl();
}
public static void main(String[] args) {
try {
new EchoServiceFactoryImpl();
} catch (RemoteException e) {
System.err.println("Error creating echo service factory: "
+ e.getMessage());
}
}
}
EchoServiceClient
public class EchoServiceClient {
public static void main(String[] args) {
try {
System.setProperty("java.security.policy", "/java.policy");
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
Registry registry = LocateRegistry.getRegistry("localhost");
EchoServiceFactory serviceFactory =
(EchoServiceFactory) registry.lookup("EchoService");
EchoService echoServiceX = serviceFactory.createEchoService();
echoServiceX.setUser("Tom");
System.out.println(echoServiceX.echo("Hello!"));
EchoService echoServiceY =
serviceFactory.createEchoService();
echoServiceY.setUser("Jerry");
System.out.println(echoServiceY.echo("Hello"));
System.out.println(echoServiceX.echo("Hey There!!!"));
System.out.println(echoServiceY.echo(":o)"));
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
Running the client produce output as below.
Tom: Hello!
Jerry: Hello
Tom: Hey There!!!
Jerry: :o)