From: Bryan T. <tho...@us...> - 2007-03-18 22:29:49
|
Update of /cvsroot/cweb/bigdata/src/test/org/CognitiveWeb/bigdata/jini In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv18893/src/test/org/CognitiveWeb/bigdata/jini Modified Files: TestServer.java TestServiceDiscovery.java Added Files: ITestService.java Log Message: more work on jini support. Index: TestServiceDiscovery.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/org/CognitiveWeb/bigdata/jini/TestServiceDiscovery.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** TestServiceDiscovery.java 17 Mar 2007 23:14:59 -0000 1.2 --- TestServiceDiscovery.java 18 Mar 2007 22:29:43 -0000 1.3 *************** *** 48,52 **** import java.io.IOException; - import java.io.Serializable; import java.net.InetAddress; --- 48,51 ---- *************** *** 70,78 **** * Browser (you will see "Unknown service") unless you set the codebase when * executing this test class and the .class files are available for download ! * from the codebase URL. I jump start the tests myself using * </p> * * <pre> ! * -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://proto.cognitiveweb.org/maven-repository/bigdata/jars/ * </pre> * --- 69,80 ---- * Browser (you will see "Unknown service") unless you set the codebase when * executing this test class and the .class files are available for download ! * from the codebase URL. I jump start the tests myself by copying them onto an ! * HTTP server and using the following options in the command line to execute ! * the test: * </p> * * <pre> ! * -Djava.security.policy=policy.all ! * -Djava.rmi.server.codebase=http://proto.cognitiveweb.org/maven-repository/bigdata/jars/ * </pre> * *************** *** 97,118 **** * network. * ! * @todo Explore the jini {@link net.jini.core.transaction.Transaction}model. * Perhaps we can use this as is to support two phase commits across the * database segments? The transaction model does not impose any semantics, * e.g., there is no locking, but we can handle all of that. * - * @see http://archives.java.sun.com/cgi-bin/wa?A2=ind0311&L=jini-users&F=&S=&P=7182 - * for a description of policy files and - * http://www.dancres.org/cottage/jini-start-examples-2_1.zip for the - * policy files described.<br> - * When testing standalone with only trusted code and NO downloaded code, - * it is reasonable to consider running the test code using - * "-Djava.security.policy=policy.all" so that you can get things moving. - * * @version $Id$ * @author <a href="mailto:tho...@us...">Bryan Thompson * </a> */ - public class TestServiceDiscovery extends TestCase { --- 99,111 ---- * network. * ! * @todo Explore the jini {@link net.jini.core.transaction.Transaction} model. * Perhaps we can use this as is to support two phase commits across the * database segments? The transaction model does not impose any semantics, * e.g., there is no locking, but we can handle all of that. * * @version $Id$ * @author <a href="mailto:tho...@us...">Bryan Thompson * </a> */ public class TestServiceDiscovery extends TestCase { *************** *** 127,140 **** */ ! public void test_serviceDiscovery() throws IOException, ClassNotFoundException { ! /* ! * install suitable security manager. this is required before the ! * application can download code. ! */ ! System.setSecurityManager(new SecurityManager()); ! /* ! * Launch the server to which we will connect. */ TestServer.launchServer(); --- 120,141 ---- */ ! public void test_serviceDiscovery() throws IOException, ! ClassNotFoundException { ! /* ! * Install suitable security manager. this is required before the client ! * can download code. The code will be downloaded from the HTTP server ! * identified by the codebase property specified for the VM running the ! * service. For the purposes of this test, we are using the _same_ VM to ! * run the client and the service, so you have to specify the codebase ! * property when running the test. ! */ ! System.setSecurityManager(new SecurityManager()); ! /* ! * Launch the server to which we will connect (this is being done by the ! * test harness rather than setting up activation for the service since ! * we want to explicitly control the service instances for the purpose ! * of testing). */ TestServer.launchServer(); *************** *** 155,165 **** /* ! * What follows is an example of service lookup, but we have to register ! * the service first. */ ! ! // Prepare a template for lookup search ! ServiceTemplate template = new ServiceTemplate(null, ! new Class[] { TestServerImpl.class }, null); /* --- 156,179 ---- /* ! * Prepare a template for lookup search. ! * ! * Note: The client needs a local copy of the interface in order to be ! * able to invoke methods on the service without using reflection. The ! * implementation class will be downloaded from the codebase identified ! * by the server. */ ! ServiceTemplate template = new ServiceTemplate(// ! /* ! * use this to request the service by its serviceID. ! */ ! null, ! /* ! * Use this to filter services by an interface that they expose. ! */ ! new Class[] { ITestService.class }, ! /* ! * use this to filter for services by Entry attributes. ! */ ! null); /* *************** *** 172,239 **** * wait state). */ ! TestServerImpl service = null; ! for( int i=0; i<10 && service == null; i++) { ! service = (TestServerImpl) serviceRegistrar.lookup(template /*, maxMatches*/); ! if( service == null ) { ! log.info("Service not found: sleeping..."); ! try {Thread.sleep(100);} ! catch( InterruptedException ex) {} ! } ! } ! ! assertNotNull("Could not find service.", service ); ! ! service.invoke(); ! ! // Sleep for a bit so that I can inspect the service in the Service Browser. ! try {Thread.sleep(10000);} ! catch( InterruptedException ex) {} ! ! } ! ! public static interface ITestService ! { ! ! /** ! * Method for testing remote invocation. ! */ ! public void invoke(); ! ! } ! ! /** ! * The proxy object that gets passed around. ! * ! * @todo It appears that multiple instances of this class are getting ! * created. This is consistent with the notion that the instance is ! * being "passed" around by state and not by reference. This implies ! * that instances are not consumed when they are discovered but merely ! * cloned using Java serialization. ! * ! * @version $Id$ ! * @author <a href="mailto:tho...@us...">Bryan Thompson ! * </a> ! */ ! public static class TestServerImpl implements ITestService, Serializable ! { ! /** ! * ! */ ! private static final long serialVersionUID = -920558820563934297L; ! /** ! * De-serialization constructor (required). ! */ ! public TestServerImpl() { ! log.info("Created: "+this); ! } ! public void invoke() { ! log.info("invoked: "+this); } } ! public static void main(String[] args) throws Exception { --- 186,215 ---- * wait state). */ ! ITestService service = null; ! for (int i = 0; i < 10 && service == null; i++) { ! service = (ITestService) serviceRegistrar ! .lookup(template /* , maxMatches */); ! if (service == null) { ! log.info("Service not found: sleeping..."); ! try { ! Thread.sleep(200); ! } catch (InterruptedException ex) { ! } ! } ! } ! assertNotNull("Could not find service.", service); ! service.invoke(); ! // Sleep for a bit so that I can inspect the service in the Service ! // Browser. ! try { ! Thread.sleep(10000); ! } catch (InterruptedException ex) { } } ! public static void main(String[] args) throws Exception { --- NEW FILE: ITestService.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Mar 18, 2007 */ package org.CognitiveWeb.bigdata.jini; import java.io.IOException; import java.rmi.Remote; import java.rmi.RemoteException; /** * The public interface for a test service. * <p> * Note: The interface extends {@link Remote} so that both the implementation of * this service and the proxy generated by jeri for the service will implement * this interface. This is necessary for service discovery or the resulting * proxy will NOT implement the interface and both service discovery (based on * the interface name) and use of the interface via the proxy will fail. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ * * @client This interface must be available to the client in order for it to * execute the methods defined by the interface without the use of * reflection. * * @server This interface must be available to the server since it exposes this * interface on its service. */ public interface ITestService extends Remote { /** * Method for testing remote invocation. * <p> * Note: The methods on a {@link Remote} interface MUST throw * {@link RemoteException} (or {@link IOException} if you want to reduce * your dependency on JINI for an interface that is also used outside of * JINI). */ public void invoke() throws RemoteException; } Index: TestServer.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/org/CognitiveWeb/bigdata/jini/TestServer.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** TestServer.java 17 Mar 2007 23:14:59 -0000 1.2 --- TestServer.java 18 Mar 2007 22:29:43 -0000 1.3 *************** *** 48,54 **** import java.io.IOException; ! import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import net.jini.core.entry.Entry; import net.jini.core.lease.Lease; --- 48,55 ---- import java.io.IOException; ! import java.rmi.Remote; import java.rmi.RemoteException; + import net.jini.admin.JoinAdmin; import net.jini.core.entry.Entry; import net.jini.core.lease.Lease; *************** *** 60,65 **** --- 61,71 ---- import net.jini.discovery.DiscoveryListener; import net.jini.discovery.LookupDiscovery; + import net.jini.export.Exporter; + import net.jini.export.ProxyAccessor; import net.jini.id.Uuid; import net.jini.id.UuidFactory; + import net.jini.jeri.BasicILFactory; + import net.jini.jeri.BasicJeriExporter; + import net.jini.jeri.tcp.TcpServerEndpoint; import net.jini.lease.LeaseListener; import net.jini.lease.LeaseRenewalEvent; *************** *** 74,78 **** import net.jini.lookup.entry.StatusType; ! import org.CognitiveWeb.bigdata.jini.TestServiceDiscovery.TestServerImpl; /** --- 80,84 ---- import net.jini.lookup.entry.StatusType; ! import org.apache.log4j.Logger; /** *************** *** 82,89 **** * invocation and one to shutdown the server. * - * @todo Look into {@link java.rmi.RMISecurityManager}. Simply adding this to - * main() causes things to fail, but gives us the trace that was otherwise - * missing. - * * @todo Look into the manager classes for service joins, discovery, etc. The * code in this class can probably be simplified drammatically. --- 88,91 ---- *************** *** 96,99 **** --- 98,103 ---- { + public static Logger log = Logger.getLogger(TestServer.class); + private ServiceID serviceID; private ServiceItem item; *************** *** 151,158 **** * indicator of whether or not it has been registered. * ! * @todo I can't figure out how to get the service to show up with its ! * metadata in the service browser. ! * ! * @todo Modify service proxy to use RMI. * * @todo This should be a fast operation and should not make remote calls. --- 155,161 ---- * indicator of whether or not it has been registered. * ! * @todo Modify service proxy to use RMI. The client stub should be ! * downloaded from the codebase and should know how to commuicate with ! * the discovered service, e.g., using RMI or a custom NIO protocol. * * @todo This should be a fast operation and should not make remote calls. *************** *** 171,175 **** /** ! * Registers a service proxy with reach identified registrar. The * registration happens in another thread to keep the latency down for the * {@link DiscoveryListener#discovered(net.jini.discovery.DiscoveryEvent)} --- 174,178 ---- /** ! * Registers a service proxy with each identified registrar. The * registration happens in another thread to keep the latency down for the * {@link DiscoveryListener#discovered(net.jini.discovery.DiscoveryEvent)} *************** *** 179,191 **** * One or more service registrars. */ - private void registerService( final ServiceRegistrar[] registrars ) { ! TestServiceDiscovery.log.info("Discovered "+registrars.length+" service registrars"); new Thread("Register Service") { public void run() { // Create an information item about a service ! item = new ServiceItem(serviceID, new TestServerImpl(), new Entry[] { new Comment("Test service(comment)"), // human facing comment. new Name("Test service(name)"), // human facing name. --- 182,195 ---- * One or more service registrars. */ private void registerService( final ServiceRegistrar[] registrars ) { ! log.info("Discovered "+registrars.length+" service registrars"); new Thread("Register Service") { public void run() { + // the service + Object impl = new TestServerImpl().getProxy(); // Create an information item about a service ! item = new ServiceItem(serviceID, impl, new Entry[] { new Comment("Test service(comment)"), // human facing comment. new Name("Test service(name)"), // human facing name. *************** *** 216,219 **** --- 220,243 ---- // Register the service. reg = registrar.register(item, Lease.FOREVER); + /* + * Setup automatic lease renewal. + * + * Note: A single lease manager can handle multiple services + * and the lease of a given service on multiple service + * registrars. It knows which lease is about to expire and + * preemptively extends the lease on the behalf of the + * registered service. It will notify the LeaseListener iff + * it is unable to renew a lease. + */ + log.info("lease will expire in " + + (reg.getLease().getExpiration() - System + .currentTimeMillis()) + "ms"); + leaseManager + .renewUntil(reg.getLease(), Lease.FOREVER, TestServer.this); + /* + * Service has been registered and lease renewal is + * operating. + */ + break; } catch (RemoteException ex) { // retry until successful. *************** *** 223,244 **** } } - /* - * Setup automatic lease renewal. - * - * Note: A single lease manager can handle multiple services - * and the lease of a given service on multiple service - * registrars. It knows which lease is about to expire and - * preemptively extends the lease on the behalf of the - * registered service. It will notify the LeaseListener iff - * it is unable to renew a lease. - */ - TestServiceDiscovery.log.info("lease will expire in " - + (reg.getLease().getExpiration() - System - .currentTimeMillis()) + "ms"); - leaseManager - .renewUntil(reg.getLease(), Lease.FOREVER, TestServer.this); - // Service has been registered and lease renewal is - // operating. - break; } } --- 247,250 ---- *************** *** 255,259 **** public void discarded(DiscoveryEvent arg0) { ! TestServiceDiscovery.log.info(""); } --- 261,265 ---- public void discarded(DiscoveryEvent arg0) { ! log.info(""); } *************** *** 266,270 **** public void notify(LeaseRenewalEvent event) { ! TestServiceDiscovery.log.error("Lease could not be renewed: " + event); } --- 272,276 ---- public void notify(LeaseRenewalEvent event) { ! log.error("Lease could not be renewed: " + event); } *************** *** 289,310 **** public static void main(String[] args) { final long lifespan = 3 * 60 * 1000; // life span in seconds. ! TestServiceDiscovery.log.info("Will start test server."); TestServer testServer = new TestServer(); ! TestServiceDiscovery.log.info("Started test server."); try { Thread.sleep(lifespan); } catch( InterruptedException ex ) { ! TestServiceDiscovery.log.warn(ex); } /* * @todo This forces a hard reference to remain for the test server. */ ! TestServiceDiscovery.log.info("Server will die: "+testServer); } /** ! * {@link Status} is abstract so a service basically needs to provide their ! * own concrete implementation. * * @version $Id$ --- 295,316 ---- public static void main(String[] args) { final long lifespan = 3 * 60 * 1000; // life span in seconds. ! log.info("Will start test server."); TestServer testServer = new TestServer(); ! log.info("Started test server."); try { Thread.sleep(lifespan); } catch( InterruptedException ex ) { ! log.warn(ex); } /* * @todo This forces a hard reference to remain for the test server. */ ! log.info("Server will die: "+testServer); } /** ! * {@link Status} is abstract so a service needs to provide their own ! * concrete implementation. * * @version $Id$ *************** *** 318,326 **** private static final long serialVersionUID = 3431522046169284463L; - /* - * Note: public fields are required and must be Serializable. - */ - public StatusType statusType; - /** * Deserialization constructor (required). --- 324,327 ---- *************** *** 329,333 **** public MyStatus(StatusType statusType) { ! this.statusType = statusType; } --- 330,340 ---- public MyStatus(StatusType statusType) { ! ! /* ! * Note: This just sets the read/write public [severity] field on ! * the super class. ! */ ! super(statusType); ! } *************** *** 376,378 **** } ! } \ No newline at end of file --- 383,553 ---- } ! /** ! * The remote service implementation object. This implements the ! * {@link Remote} interface and uses JERI to create a proxy for the remote ! * object and configure and manage the protocol for communications between ! * the client (service proxy) and the remote object (the service ! * implementation). ! * <p> ! * Note: You have to implement {@link JoinAdmin} in order to show up as an ! * administerable service (blue folder) in the jini Service Browser. ! * ! * @version $Id$ ! * @author <a href="mailto:tho...@us...">Bryan Thompson ! * </a> ! */ ! public static class TestServerImpl implements ProxyAccessor, ITestService/*, Serializable*/ ! { ! ! /** ! * Note: Mark the {@link Logger} as transient since we do NOT need to ! * serialize its state. ! * <p> ! * ! * @todo When the service uses a proxy and a remote communications ! * protocol, the service instance is remote and this object is not ! * instantiated on the client (test this hypothesis by removing ! * log4j from the codebase). ! */ ! public static final transient Logger log = Logger.getLogger(TestServerImpl.class); ! ! // Note required when using a service proxy. the Exporter handles the proxy generation. ! // /** ! // * ! // */ ! // private static final long serialVersionUID = -920558820563934297L; ! ! /** ! * The location of the JERI configuration file. ! * ! * @todo provide a command line option to override the file location. ! */ ! private transient static String CONFIG_FILE = "jeri/jeri.config"; ! ! private ITestService proxy; ! ! // /** ! // * ! // * @param args ! // * @throws Exception ! // * ! // * @see http://jan.newmarch.name/java/jini/tutorial/Jeri.xml for an ! // * explanation of what is going on here. ! // */ ! // public static void main(String[] args) throws Exception { ! // ! // String[] configArgs = new String[] { CONFIG_FILE }; ! // ! // // get the configuration (by default a FileConfiguration) ! // Configuration config = ConfigurationProvider ! // .getInstance(configArgs); ! // System.out.println("Configuration: " + config.toString()); ! // ! // // and use the configuration to construct an exporter ! // Exporter exporter = (Exporter) config.getEntry( ! // // ! // TestServerImpl.class.getName(), // component ! // "exporter", // name ! // Exporter.class, // type (of the return object) ! // new BasicJeriExporter(TcpServerEndpoint.getInstance(0), ! // new BasicILFactory()) /* default */,// ! // Configuration.NO_DATA // data. ! // ); ! // ! // // export an object of this class ! // Remote proxy = exporter.export(new TestServerImpl()); ! // System.out.println("Proxy is " + proxy.toString()); ! // ! // // now unexport it once finished ! // exporter.unexport(true); ! // ! // } ! ! /* ! * @todo presumably service shutdown should clear the proxy reference ! * once the service has been removed from the registry. ! */ ! public Object getProxy() { ! ! return proxy; ! ! } ! ! /** ! * Service constructor. ! * ! * @todo can the constructor accept arguments? ! */ ! public TestServerImpl() /*@todo throws RemoteException ?*/ { ! ! /* ! * @todo when this is added the test will succeed the first time but ! * thereafter will fail with a connection refused to the end point ! * for the _expired_ service. While that exception makes sense in ! * that the expired service should not be connectable, I do not ! * understand why adding or dropping this line has any influence. ! * Perhaps the problem is that it changes GC behavior and the prior ! * test service is otherwise NOT expired? Look into what this ! * service is doing to shutdown after the test and what is should ! * be doing. ! * ! * So - the test does NOT attempt to close down the service - I was ! * deliberately leaving it open so that I could explore the service ! * in the Service Browser. The issue may be that this replaces the ! * SecurityManager after one was already installed in the VM by the ! * test itself! ! */ ! // System.setSecurityManager(new SecurityManager()); ! ! try { ! ! // @todo work out use of a configuration file. ! // String[] configArgs = new String[] { CONFIG_FILE }; ! // ! // // get the configuration (by default a FileConfiguration) ! // Configuration config = ConfigurationProvider ! // .getInstance(configArgs); ! // System.out.println("Configuration: " + config.toString()); ! // ! // // and use the configuration to construct an exporter ! // Exporter exporter = (Exporter) config.getEntry( ! // // ! // TestServerImpl.class.getName(), // component ! // "exporter", // name ! // Exporter.class, // type (of the return object) ! // new BasicJeriExporter(TcpServerEndpoint.getInstance(0), ! // new BasicILFactory()) /* default */,// ! // Configuration.NO_DATA // data. ! // ); ! ! // hardwired jeri exporter using TCP. ! Exporter exporter = new BasicJeriExporter(TcpServerEndpoint ! .getInstance(0), new BasicILFactory()); ! ! // export an object of this class ! proxy = (ITestService) exporter.export(this); ! log.info("Proxy is " + proxy + "(" + proxy.getClass() + ")"); ! ! } catch(Exception ex) { ! // @todo should we retry the operation? ! log.error(ex); ! throw new RuntimeException(ex); ! } ! ! // @todo who will unexport the proxy? ! ! // // now unexport it once finished ! // exporter.unexport(true); ! ! // System.err.println("Created: "+this); ! log.info("Created: "+this); ! } ! ! public void invoke() { ! // System.err.println("invoked: "+this); ! log.info("invoked: "+this); ! } ! ! } ! ! } |