new to parallel/distributed computing and having issues with a client-server program I'm trying to write. What's supposed to happen is the server receives an integer from the client and sends back the sum all the numbers leading up to it (ex, user enters 5, server calculates 1+2+3+4+5, server sends back 15). I'm still trying to figure it out, so I've hard coded the input on the client side.
This is what I have on the server side:
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
import java.util.*;
public class Server {
public static void main(String[]args) {
try{
int port = 16790;
String host = "localhost";
CalculateSumServerImpl export = new CalculateSumServerImpl();
LocateRegistry.createRegistry(port);
String registryURL = "rmi://" + host + ":" + port + "/sum";
Naming.rebind(registryURL, export);
System.out.println("Server ready");
} catch (Exception e) {
e.printStackTrace();
}
} }
//to calculate the sum
import java.rmi.*;
import java.rmi.server.*;
public class CalculateSumServerImpl extends UnicastRemoteObject implements CalServerInterface {
public int n; //value entered
public int sum; //sum
protected CalculateSumServerImpl() throws RemoteException {
super();
}
#Override
public int calculateSum(int n) throws RemoteException {
n = (n*(n+1))/2; //sum of 1 + 2 + 3 + .. + n
sum = n;
return sum;
} }
//interface
import java.rmi.Remote;
public interface CalServerInterface extends Remote {
public int calculateSum(int n ) throws java.rmi.RemoteException;
}
And on the client side:
import java.rmi.*;
import java.util.PropertyPermission;
public class Client {
public static void main(String[]args) {
System.setSecurityManager(new java.rmi.RMISecurityManager());
System.setProperty("java.net.preferIPv4Stack" , "true");
try {
int port = 16790;
String host = "localhost";
String registryURL = "rmi://" + host + ":" + port + "/sum";
Project4ServerInterface obj = (Project4ServerInterface)Naming.lookup(registryURL);
System.out.println("Lookup completed.");
int output = obj.calculateSum(3);
System.out.println("Sum is: " + output);
} catch (Exception e) {
e.printStackTrace();
}
System.setProperty("java.net.preferIPv4Stack","true");
} }
And I've implemented the Interface on the client side as well.
The error that I've been getting on the client side is:
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.net.preferIPv4Stack" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.System.setProperty(System.java:792)
at project04client.Client.main(Client.java:10)
with the error pointing to the line with this code:
System.setProperty("java.net.preferIPv4Stack" , "true");
Anyone have any experience trouble shooting this error?
Thanks!
The problem is that you have set a security manager for the entire (client) application that won't let you modify system properties.
The simple fix is to set the system properties you need to set before you set the RMI security manager.
Alternatively, you may be able to get rid of the System.setSecurityManager(...) call entirely. You (probably) only need it if you want the client to be able to download classes from your RMI service.
I tried setting the system property before the security manager and got an AccessControlException, denying socket permissions.
That doesn't make much sense. You would only get an AccessControlException if there was a security manager in place at that point. There shouldn't be ... unless this is applet code or similar launched in a web browser. Also, I don't know why a call to set a property would be denied saying that you don't have socket permissions.
When I took the security manager out completely, I got an UnmarshalException pointing to the interface.
You also need to add the classes / interfaces for the objects that tou will be unmarshalling to the client-side classpath.
Actually, I just noticed that the javadoc for RMISecurityManager says:
"RMISecurityManager implements a policy identical to the policy implemented by SecurityManager. RMI applications should use the SecurityManager class or another appropriate SecurityManager implementation instead of this class."
Related
I have used RMI in my code :
import java.rmi.*;
public interface AddServerIntf extends Remote {
double add(double d1,double d2) throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
public class AddServerImpl extends UnicastRemoteObject implements AddServerIntf {
public AddServerImpl() throws RemoteException {
}
public double add(double d1,double d2) throws RemoteException {
return d1+d2;
}
}
import java.net.*;
import java.rmi.*;
public class AddServer {
public static void main(String args[]) {
try {
AddServerImpl addServerImpl=new AddServerImpl();
Naming.rebind("AddServer",addServerImpl);
} catch(Exception exc) {
System.out.println(exc);
}
}
}
import java.rmi.*;
public class AddClient {
public static void main(String args[]) {
try {
String Url="rmi://"+args[0]+"/AddServer";
AddServerIntf addServerIntf=(AddServerIntf)Naming.lookup(Url);
System.out.println("The first number is "+args[1]);
double d1=Double.valueOf(args[1]).doubleValue();
System.out.println("The second number is: "+args[2]);
double d2=Double.valueOf(args[2]).doubleValue();
System.out.println("The Sum is: "+addServerIntf.add(d1,d2));
} catch(Exception exc) {
System.out.println(exc);
}
}
}
These are 4 .java files written.
Next i compile all these files.Then I create a stub using rmic AddServerImpl. After that i start rmi registry on server side using start rmiregistry. Then i start server using java AddServer and finally client using java AddClient 27.60.200.80 5 9.
But nothing happens
Exception that is thrown on client side is java.net.ConnectException : connection timed out : connect
What is the reason and how can i solve this?
On client machine these are the following .class files AddClient.class AddServerImpl.class AddServerImpl_Stub.class and on server side AddServer.class AddServerImpl.class AddServerImpl_Stub.class AddServerIntf.class
The error message says it all: your connection timed out. This means your request did not get a response within some (default) timeframe. The reasons that no response was received is likely to be one of:
a) The IP/domain or port is incorrect
b) The IP/domain or port (i.e service) is down
c) The IP/domain is taking longer than your default timeout to respond
d) You have a firewall that is blocking requests or responses on whatever port you are using
e) You have a firewall that is blocking requests to that particular host
f) Your internet access is down
Note that firewalls and port or IP blocking may be in place by your ISP
Number (1): The IP was incorrect - is the correct answer. The /etc/hosts file (a.k.a.
C:\Windows\system32\drivers\etc\hosts ) had an incorrect entry for the local machine name.
Corrected the 'hosts' file and Camel runs very well. Thanks for the pointer.
Exception : java.net.ConnectException
This means your request didn't getting response from server in stipulated time. And their are some reasons for this exception:
Too many requests overloading the server
Request packet loss because of wrong network configuration or line overload
Sometimes firewall consume request packet before sever getting
Also depends on thread connection pool configuration and current status of connection pool
Response packet lost during transition
If you're pointing the config at a domain (eg fabrikam.com), do an NSLOOKUP to ensure all the responding IPs are valid, and can be connected to on port 389:
NSLOOKUP fabrikam.com
Test-NetConnection <IP returned from NSLOOKUP> -port 389
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to run 3 RMI servers on single (96 Ram) machine. From three different machine clients are calling, but for three clients I have given 3 different port numbers and binded object name are also different for all three client.
For 1st 2 client I got the output and for thirst one I am not getting any output. Only "Null Pointer exception" I am getting on client side. On Server side I have given -Xms250m to -Xmx 20g on all 3 server. On client all have 8 GB ram I have given -Xmx6g.
You need to use a customized RMIRegistry port to have two or more registry instances run in a same machine. See this fully working RMI Server and Client example, you can run multiple clients connecting to the same remote object instance. Remember to synchronize internal behaviour of the service implementation.
Here is a remote service interface and implementation run on server machine.
import java.rmi.*;
public interface CounterService extends Remote {
public void setValue(String value) throws RemoteException;
public String getValue() throws RemoteException;
}
- - - - - -
import java.rmi.*;
public class CounterServiceImpl implements CounterService {
private int callCount=0;
private String name;
private String value;
public CounterServiceImpl(String name) {
this.name=name;
this.value="";
}
public synchronized void setValue(String value) throws RemoteException {
callCount++;
this.value=value;
}
public synchronized String getValue() throws RemoteException {
callCount++;
return String.format("%s (name=%s, callcount=%d)", value, name, callCount);
}
}
Here is a RMI client and server implementation.
import java.util.*;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.ExportException;
public class RMITest1Client {
private static Random randomInt = new Random();
public static int getRandomInt(int min, int max) {
int range = (max - min) + 1;
return randomInt.nextInt(range) + min;
}
public static void main(String[] args) throws Exception {
String rmiEndPoint = args[0];
String serviceName = args[1];
CounterService counter = (CounterService)Naming.lookup(rmiEndPoint+"/"+serviceName);
System.out.println("Connected to " + rmiEndPoint+"/"+serviceName);
for(int idx=0; idx<10; idx++) {
System.out.println("getValue="+counter.getValue());
Thread.sleep(getRandomInt(1, 5)*1000);
counter.setValue( "val"+getRandomInt(100, 999) );
Thread.sleep(getRandomInt(1, 5)*1000);
}
}
}
- - - - - -
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.ExportException;
public class RMITest1Server {
public static void main(String[] args) throws Exception {
// create the RMIregistry service
int port = Integer.parseInt(args[0]);
Registry registry;
try {
System.out.println("RMIRegistry on port " + port);
registry = LocateRegistry.createRegistry(port);
} catch (ExportException ex) {
// registry may already be created by another process,
// get reference to an existing registry instance.
System.out.println("Creating registry failed, try to connect an existing registry, ex="+ex.getMessage());
registry = LocateRegistry.getRegistry(port);
}
CounterService counter = new CounterServiceImpl("counter1");
UnicastRemoteObject.exportObject(counter, port);
registry.rebind("counter1", counter);
counter = new CounterServiceImpl("counter2");
UnicastRemoteObject.exportObject(counter, port);
registry.rebind("counter2", counter);
System.out.println("Running...");
Thread.sleep(30000);
// close registry objects
for(String serviceName : registry.list()) {
try {
System.out.println("RMIRegistry unbind " + serviceName);
Remote obj = (Remote)registry.lookup(serviceName);
UnicastRemoteObject.unexportObject(obj, true);
} catch (Exception ex) { }
try { registry.unbind(serviceName); } catch (Exception ex) { }
}
System.out.println("RMIRegistry closed");
System.exit(0); // mandatory if RMIRegistry was started in this JVM instance
}
}
Here are test scripts to run server and client.
**goServer.bat**
#SET /p port=Server port (2222, 3333, 0=exit):
#IF "0"=="%port%" GOTO :EOF
java -cp "./lib/*;" RMITest1Server %port%
pause
- - - - - -
**goClient.bat**
#SET /p port=Server port (2222, 3333, 0=exit):
#IF "0"=="%port%" GOTO :EOF
#SET /p service=Service index (1,2):
java -cp "./lib/*;" RMITest1Client rmi://127.0.0.1:%port% counter%service%
pause
I'm writing a distributed app by Java RMI. The RMI client registers event handler / callback to RMI server, and the server calls the client's callback function when required. Now the problem is, when network connection failure (for example, Ethernet cable plugged out...), the RMI server and client won't be notified, and the RMI server fails when attempts to call the client's registered callback function.The RMI server cannot notify the RMI client about this issue too. Even worse, when network connection recovers, the RMI client service will still lose contact with RMI server because nobody notify her to reconnect.
My current idea is to implement a ping() method in RMI client in separate thread.
This thread could wake up at regular intervals and check on the server.
if failed, then farce to reconnect.
Any other elegant solutions? Hope you guys can help !
the interface
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyInterface extends Remote {
public int RegisterEventHandler(RemoteMyEventHandler eventHandler) throws RemoteException;
public void unRegisterEventHandler(int eventHandlerId) throws RemoteException;
}
the RMI Server impelementation
import java.rmi.RemoteException;
import com.me.MyInterface;
public class MyInterfaceImpl implements MyInterface {
{
public void init() {
try {
//... initialize RMI server....
//....
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public int RegisterEventHandler(RemoteMyEventHandler eventHandler)
throws RemoteException {
return MyEventHandlerImp.getInstance().addHandler(eventHandler);
}
#Override
public void unRegisterEventHandler(int eventHandlerId)
throws RemoteException {
MyEventHandlerImp.getInstance().removeHandler(eventHandlerId);
}
}
//handler.notifyEventSnap(events);
the RMI Client implementation
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.me.MyInterface;
public class MyService implements NotifyHandler{
{
private MyInterface client;
private MyEventHandler myEventHandler;
private void connectToServer() {
try {
//...
Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);
client = (MyInterface) registry.lookup(MyCInterface.class.getName());
} catch (RemoteException er) {
} catch (NotBoundException en) {
} catch (Exception en) {
}
}
private void startService(){
//Attach my event handler
if(client != null)
{
myEventHandler = new MyEventHandler();
myEventHandlerId = client.RegisterEventHandler(myEventHandler);
}
}
}
when network connection failure (for example, Ethernet cable plugged out...), the RMI server and client won't be notified, and the RMI server fails when attempts to call the client's registered callback function.
Err, that is the notification to the server. The server just has to note this and try again later.
The RMI server cannot notify the RMI client about this issue too.
The client doesn't need to know.
Even worse, when network connection recovers, the RMI client service will still lose contact with RMI server because nobody notify her to reconnect.
The client doesn't have to 'reconnect'. There is no connect or reconnect step in RMI. As long as the client's JVM and remote objects remain up and exported respectively, the stubs at the server remain valid and can continue to be used by the server.
You're solving a non-problem.
You seem to be partially implementing a client/server session. This is a token that the server can track to ensure a client is valid. If there is an error while the server is communicating with the client the session should be ended and all references to the client removed.
Your server is already implementing a session with the integer used to unRegisterEventHandler. You should keep track of those integers somewhere like a Map. If the server cannot connect to a client it should simply unregister that client and make the session invalid by removing it from the map. The server should remove all references to the client and not attempt to communicate with the client until a new session is created.
If a client tries to communicate with the server it should get an InvalidException exception from the server. This way the client can attempt to make a new session by calling RegisterEventHandler in the catch block.
I worked on a project that dealt with this problem using a ping like you suggested at https://code.google.com/p/umuc-team-factor/
All client communication with the server was in a looped try catch block like
private void getSession() {
while(isRun()) {
try {
if(server == null) {
Logger.getLogger(JobClient.class.getName()).info("Server is null.");
setupServer();
}
UUID sid = server.getSession(this);
synchronized (this) {
id = sid;
}
Logger.getLogger(JobClient.class.getName()).info("Session id is " + id);
return;
} catch (RemoteException ex) {
Logger.getLogger(JobClient.class.getName()).info("Could not get session from server: " + ex + ". setting up server.");
setupServer();
}
}
}
This try to setup a session with the server until the program is stopped.
All server communication with the client should end the session for the client if there is a RemoteException thrown. c.status() is similar to a ping.
List<UUID> endSessions = new ArrayList<UUID>();
for (UUID id : copy.keySet()) {
ClientCallback c = copy.get(id).client;
try {
ClientStatus status = c.status();
Logger.getLogger(ProcessManager.class.getName()).info("got client status for " + id + ": " + status.getSessionID() + " -" + status.getJobStatus());
if (status.getSessionID() == null || !status.getSessionID().equals(id)) {
endSessions.add(id);
}
} catch (Exception ex) {
endSessions.add(id);
Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
for (UUID id : endSessions) {
try {
endSession(id);
} catch (SessionExpiredException ex) {
Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
On this article: http://java.sun.com/developer/technicalArticles/tools/JavaSpaces/ is a tutorial how to run JavaSpaces client. I wrote these classes in Eclipse, started Launch-All script and Run example. It works.
After that I exported these classes into executable jar (JavaSpaceClient.jar) and tried that jar with following command:
java -jar JavaSpaceClient.jar
It works fine, gives me result:
Searching for a JavaSpace...
A JavaSpace has been discovered.
Writing a message into the space...
Reading a message from the space...
The message read is: Здраво JavaSpace свете!
My problem is when I move this jar file on my other LAN computer, it shows me error when I type same command. Here is error:
cica#cica-System-Name:~/Desktop$ java -jar JavaSpaceClient.jar
Searching for a JavaSpace...
Jul 27, 2011 11:20:54 PM net.jini.discovery.LookupDiscovery$UnicastDiscoveryTask run
INFO: exception occurred during unicast discovery to biske-Inspiron-1525:4160 with constraints InvocationConstraints[reqs: {}, prefs: {}]
java.net.UnknownHostException: biske-Inspiron-1525
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:175)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384)
at java.net.Socket.connect(Socket.java:546)
at java.net.Socket.connect(Socket.java:495)
at com.sun.jini.discovery.internal.MultiIPDiscovery.getSingleResponse(MultiIPDiscovery.java:134)
at com.sun.jini.discovery.internal.MultiIPDiscovery.getResponse(MultiIPDiscovery.java:75)
at net.jini.discovery.LookupDiscovery$UnicastDiscoveryTask.run(LookupDiscovery.java:1756)
at net.jini.discovery.LookupDiscovery$DecodeAnnouncementTask.run(LookupDiscovery.java:1599)
at com.sun.jini.thread.TaskManager$TaskThread.run(TaskManager.java:331)
I just writes "Searching for JavaSpace..." and after a while prints these error messages.
Can someone help me with this error?
EDIT:
For discovery I am using LookupDiscovery class I've found on Internet:
import java.io.IOException;
import java.rmi.RemoteException;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
/**
A class which supports a simple JINI multicast lookup. It doesn't register
with any ServiceRegistrars it simply interrogates each one that's
discovered for a ServiceItem associated with the passed interface class.
i.e. The service needs to already have registered because we won't notice
new arrivals. [ServiceRegistrar is the interface implemented by JINI
lookup services].
#todo Be more dynamic in our lookups - see above
#author Dan Creswell (dan#dancres.org)
#version 1.00, 7/9/2003
*/
public class Lookup implements DiscoveryListener {
private ServiceTemplate theTemplate;
private LookupDiscovery theDiscoverer;
private Object theProxy;
/**
#param aServiceInterface the class of the type of service you are
looking for. Class is usually an interface class.
*/
public Lookup(Class aServiceInterface) {
Class[] myServiceTypes = new Class[] {aServiceInterface};
theTemplate = new ServiceTemplate(null, myServiceTypes, null);
}
/**
Having created a Lookup (which means it now knows what type of service
you require), invoke this method to attempt to locate a service
of that type. The result should be cast to the interface of the
service you originally specified to the constructor.
#return proxy for the service type you requested - could be an rmi
stub or an intelligent proxy.
*/
Object getService() {
synchronized(this) {
if (theDiscoverer == null) {
try {
theDiscoverer =
new LookupDiscovery(LookupDiscovery.ALL_GROUPS);
theDiscoverer.addDiscoveryListener(this);
} catch (IOException anIOE) {
System.err.println("Failed to init lookup");
anIOE.printStackTrace(System.err);
}
}
}
return waitForProxy();
}
/**
Location of a service causes the creation of some threads. Call this
method to shut those threads down either before exiting or after a
proxy has been returned from getService().
*/
void terminate() {
synchronized(this) {
if (theDiscoverer != null)
theDiscoverer.terminate();
}
}
/**
Caller of getService ends up here, blocked until we find a proxy.
#return the newly downloaded proxy
*/
private Object waitForProxy() {
synchronized(this) {
while (theProxy == null) {
try {
wait();
} catch (InterruptedException anIE) {
}
}
return theProxy;
}
}
/**
Invoked to inform a blocked client waiting in waitForProxy that
one is now available.
#param aProxy the newly downloaded proxy
*/
private void signalGotProxy(Object aProxy) {
synchronized(this) {
if (theProxy == null) {
theProxy = aProxy;
notify();
}
}
}
/**
Everytime a new ServiceRegistrar is found, we will be called back on
this interface with a reference to it. We then ask it for a service
instance of the type specified in our constructor.
*/
public void discovered(DiscoveryEvent anEvent) {
synchronized(this) {
if (theProxy != null)
return;
}
ServiceRegistrar[] myRegs = anEvent.getRegistrars();
for (int i = 0; i < myRegs.length; i++) {
ServiceRegistrar myReg = myRegs[i];
Object myProxy = null;
try {
myProxy = myReg.lookup(theTemplate);
if (myProxy != null) {
signalGotProxy(myProxy);
break;
}
} catch (RemoteException anRE) {
System.err.println("ServiceRegistrar barfed");
anRE.printStackTrace(System.err);
}
}
}
/**
When a ServiceRegistrar "disappears" due to network partition etc.
we will be advised via a call to this method - as we only care about
new ServiceRegistrars, we do nothing here.
*/
public void discarded(DiscoveryEvent anEvent) {
}
}
My client program tries simply to search for JavaSpaces service write MessageEntry into and then retrieves message and prints it out. Here is client program:
import net.jini.space.JavaSpace;
public class SpaceClient {
public static void main(String argv[]) {
try {
MessageEntry msg = new MessageEntry();
msg.content = "Hello JavaSpaces wordls!";
System.out.println("Searching for JavaSpaces...");
Lookup finder = new Lookup(JavaSpace.class);
JavaSpace space = (JavaSpace) finder.getService();
System.out.println("JavaSpaces discovered.");
System.out.println("Writing into JavaSpaces...");
space.write(msg, null, 60*60*1000);
MessageEntry template = new MessageEntry();
System.out.println("Reading message from JavaSpaces...");
MessageEntry result = (MessageEntry) space.read(template, null, Long.MAX_VALUE);
System.out.println("Message: "+result.content);
} catch(Exception e) {
e.printStackTrace();
}
}
}
And of course this is MessageEntry class:
import net.jini.core.entry.*;
public class MessageEntry implements Entry {
public String content;
public MessageEntry() {
}
public MessageEntry(String content) {
this.content = content;
}
public String toString() {
return "MessageContent: " + content;
}
}
EDIT2:
I did discovery on two Windows computers.
After that I tried Windows - Ubuntu combiantion and it doesn't work. Maybe there are some network problems? When I ping each another everything is ok. Maybe there are some DNS issues on Ubuntu..
EDIT3:
Windows - Ubuntu combination works if JavaSpaces service is started up on Windows and client program is on Ubuntu. When I try to do reverse, to run JavaSpaces service on Ubuntu and run client on Windows error occurs.
Obviously there is some problem with Ubuntu. Ubuntu has installed OpenJDK installed by default. I installed Oracle JDK, and set JAVA_HOME and put JAVA_HOME/bin into PATH variable. I wonder maybe there is some problem with different versions of Java, maybe I am not using right one.
It is possible that the service registrar that you are running (on host biske-Inspiron-1525 at port 4160), is discovering it's hostname incorrectly (without domain name) and is therefore sending out the announcements with a short hostname. Therefore, after discovering the service registrar, it is possible that subsequently the client is trying to make a connection to the service registrar it cannot resolve the hostname if it is on a different domain.
To ensure that the service registrar is running with the correct hostname, try starting it with the following command line attribute:
-Dcom.sun.jini.reggie.unicastDiscoveryHost="biske-Inspiron-1525.and.its.domain"
It appears that you are doing unicast discovery to a specific host and port and that you can't look up that host.
Assuming you can resolve the name biske-Inspiron-1525 with DNS try removing the ":4160" part and see if the unicast lookup succeeds then.
Here is an example of the code I use to look up a service. It's a bit more complicated because I implement ServiceDiscoveryListener and handle service discovery that way. I actually keep a list of services and dynamically switch between then when one fails but I stripped that part out of the example. I am also using the Configuration part of Jini which I'll explain afterwards. The service interface I am using here is called "TheService":
public class JiniClient implements ServiceDiscoveryListener {
private TheService service = null;
private Class[] serviceClasses;
private ServiceTemplate serviceTemplate;
public JiniClient(String[] configFiles) throws ConfigurationException {
Configuration config = ConfigurationProvider.getInstance(configFiles,
getClass().getClassLoader());
// Set the security manager
System.setSecurityManager(new RMISecurityManager());
// Define the service we are interested in.
serviceClasses = new Class[] {TheService.class};
serviceTemplate = new ServiceTemplate(null, serviceClasses, null);
// Build a cache of all discovered services and monitor changes
ServiceDiscoveryManager serviceMgr = null;
DiscoveryManagement mgr = null;
try {
mgr = (DiscoveryManagement)config.getEntry(
getClass().getName(), // component
"discoveryManager", // name
DiscoveryManagement.class); // type
if (null == mgr) {
throw new ConfigurationException("entry for component " +
getClass().getName() + " name " +
"discoveryManager must be non-null");
}
} catch (Exception e) {
/* This will catch both NoSuchEntryException and
* ConfigurationException. Putting them both
* below just to make that clear.
*/
if( (e instanceof NoSuchEntryException) ||
(e instanceof ConfigurationException)) {
// default value
try {
System.err.println("Warning, using default multicast discover.");
mgr = new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,
null, // unicast locators
null); // DiscoveryListener
} catch(IOException ioe) {
e.printStackTrace();
throw new RuntimeException("Unable to create lookup discovery manager: " + e.toString());
}
}
}
try {
serviceMgr = new ServiceDiscoveryManager(mgr, new LeaseRenewalManager());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Unable to create service discovery manager: " + e.toString());
}
try {
serviceMgr.createLookupCache(serviceTemplate,
null, // no filter
this); // listener
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to create serviceCache: " + e.getMessage());
}
}
public void serviceAdded(ServiceDiscoveryEvent evt) {
/* Called when a service is discovered */
ServiceItem postItem = evt.getPostEventServiceItem();
//System.out.println("Service appeared: " +
// postItem.service.getClass().toString());
if(postItem.service instanceof TheService) {
/* You may be looking for multiple services.
* The serviceAdded method will be called for each
* so you can use instanceof to figure out if
* this is the one you want.
*/
service = (TheService)postItem.service;
}
}
public void serviceRemoved(ServiceDiscoveryEvent evt) {
/* This notifies you of when a service goes away.
* You could keep a list of services and then remove this
* service from the list.
*/
}
public void serviceChanged(ServiceDiscoveryEvent evt) {
/* Likewise, this is called when a service changes in some way. */
}
The Configuration system allows you to dynamically configure the discovery method so you can switch to discover specific unicast systems or multicast without changing the app. Here is an example of a unicast discovery configuration file that you could pass to the above objects constructor:
import net.jini.core.discovery.LookupLocator;
import net.jini.discovery.LookupDiscoveryManager;
import net.jini.discovery.LookupDiscovery;
com.company.JiniClient {
discoveryManager = new LookupDiscoveryManager(
LookupDiscovery.ALL_GROUPS,
new LookupLocator[] { new LookupLocator("jini://biske-Inspiron-1525.mycompany.com")},
null,
this); // the current config
}
I found solution! That was dns issue. On Ubuntu my /etc/hosts file was:
192.168.1.3 biske-Inspiron-1525 # Added by NetworkManager
127.0.0.1 localhost.localdomain localhost
::1 biske-Inspiron-1525 localhost6.localdomain6 localhost6
127.0.1.1 biske-Inspiron-1525
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
I've just removed line 127.0.1.1 biske-Inspiron-1525 and now it works fine.
Little thing was destroyed million of my nerves :)
I am trying to create a simple chat client using the red5 media server, but I seem to be having a slight hiccup. I am creating a shared object on the server side, and it seems to be creating it successfully. However, when I make changes to the object via the client (type a message), the SYNC event fires, but the content within the shared object remains empty. I suspect I am doing something wrong on the java end, any advice?
Console Results:
Success!
Server Message: clear
Server Message: [object Object]
Local message: asdf
Server Message: change
Server Message: [object Object]
Local message: fdsa
Server Message: change
Server Message: [object Object]
Local message: fewa
Server Message: change
Server Message: [object Object]
Server Side:
package org.red5.core;
import java.util.List;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.service.ServiceUtils;
import org.red5.server.api.so.ISharedObject;
// import org.apache.commons.logging.Log;
// import org.apache.commons.logging.LogFactory;
public class Application extends ApplicationAdapter {
private IScope appScope;
// private static final Log log = LogFactory.getLog( Application.class );
/** {#inheritDoc} */
#Override
public boolean connect(IConnection conn, IScope scope, Object[] params) {
appScope = scope;
createSharedObject(appScope, "generalChat", false); // Creates general chat shared object
return true;
}
/** {#inheritDoc} */
#Override
public void disconnect(IConnection conn, IScope scope) {
super.disconnect(conn, scope);
}
public void updateChat(Object[] params)
{
ISharedObject so = getSharedObject(appScope, "generalChat"); // Declares and stores general chat data in general chat shared object
so.setAttribute("point", params[0].toString());
}
}
Client Side:
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.net.*;
// This class is going to handle all data to and from from media server
public class SOConnect extends MovieClip
{
// Variables
var nc:NetConnection = null;
var so:SharedObject;
public function SOConnect():void
{
}
public function connect():void
{
// Create a NetConnection and connect to red5
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
nc.connect("rtmp://localhost/testChat");
// Create a StoredObject for general chat
so = SharedObject.getRemote("generalChat", nc.uri, false);
so.connect(nc);
so.addEventListener(SyncEvent.SYNC, receiveChat)
}
public function sendChat(msg:String)
{
trace ("Local message: " + msg);
nc.call("updateChat", null, msg)
}
public function receiveChat(e:SyncEvent):void
{
for (var i in e.changeList)
{
trace ("Server Message: " + e.changeList[i].code)
trace ("Server Message: " + e.changeList[i])
}
}
// Given result, determine successful connection
private function netStatusHandler(e:NetStatusEvent):void
{
if (e.info.code == "NetConnection.Connect.Success")
{
trace("Success!");
}
else
{
trace("Failure!\n");
trace(e.info.code);
}
}
}
}
you don't need to write anything on the server side in order to do a chat in as3 and red5;
here is an example for you the chat that it is working and it is written in as3/flex3
Yes its posible to create a chat without writing server side code but i dont see how someone could control users disconnections or use lists of users on sync, anyway back to the subject maybe you have a problem with dir permissions so try running red5 as root/admin once , just to check if it works, if it does you should create a user (with the correct writing permissions) in your system and then run red5 using that user.