English 中文(简体)
Jini/JavaSpaces discovery error
原标题:

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.

最佳回答

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 :)

问题回答

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
}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签