/**************************************************************************** * Copyright (c) 2009 Composent, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Composent, Inc. - initial API and implementation *****************************************************************************/ package org.eclipse.ecf.internal.examples.remoteservices.hello.consumer; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.ecf.core.IContainerFactory; import org.eclipse.ecf.examples.remoteservices.hello.HelloMessage; import org.eclipse.ecf.examples.remoteservices.hello.IHello; import org.eclipse.ecf.examples.remoteservices.hello.IHelloAsync; import org.eclipse.ecf.osgi.services.distribution.IDistributionConstants; import org.eclipse.ecf.remoteservice.IAsyncCallback; import org.eclipse.ecf.remoteservice.IRemoteService; import org.eclipse.ecf.remoteservice.IRemoteServiceProxy; import org.eclipse.ecf.remoteservice.RemoteServiceHelper; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.equinox.concurrent.future.IFuture; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class HelloConsumerApplication implements IApplication, IDistributionConstants, ServiceTrackerCustomizer { public static final String CONSUMER_NAME = "org.eclipse.ecf.examples.remoteservices.hello.consumer"; private BundleContext bundleContext; private ServiceTracker containerFactoryServiceTracker; private String containerType = "ecf.r_osgi.peer"; private final Object appLock = new Object(); private boolean done = false; private ServiceTracker helloServiceTracker; private ServiceRegistration discoveryListenerRegistration; private ServiceRegistration distributionListenerRegistration; public Object start(IApplicationContext appContext) throws Exception { // Set bundle context (for use with service trackers) bundleContext = Activator.getContext(); processArgs(appContext); // Create ECF container of appropriate type. The container instance // can be created in a variety of ways...e.g. via code like the line below, // via the new org.eclipse.ecf.container extension point, or automatically // upon discovery via the IProxyContainerFinder/DefaultProxyContainerFinder. getContainerFactory().createContainer(containerType); // Create service tracker to track IHello instances that have the 'service.imported' // property set (as defined by OSGi 4.2 remote services spec). helloServiceTracker = new ServiceTracker(bundleContext, createRemoteFilter(), this); helloServiceTracker.open(); waitForDone(); return IApplication.EXIT_OK; } private Filter createRemoteFilter() throws InvalidSyntaxException { // This filter looks for IHello instances that have the // 'service.imported' property set, as specified by OSGi 4.2 // remote services spec (Chapter 13) return bundleContext.createFilter("(&(" + org.osgi.framework.Constants.OBJECTCLASS + "=" + IHello.class.getName() + ")(" + SERVICE_IMPORTED + "=*))"); } public void stop() { if (helloServiceTracker != null) { helloServiceTracker.close(); helloServiceTracker = null; } if (containerFactoryServiceTracker != null) { containerFactoryServiceTracker.close(); containerFactoryServiceTracker = null; } if (discoveryListenerRegistration != null) { discoveryListenerRegistration.unregister(); discoveryListenerRegistration = null; } if (distributionListenerRegistration != null) { distributionListenerRegistration.unregister(); distributionListenerRegistration = null; } this.bundleContext = null; synchronized (appLock) { done = true; appLock.notifyAll(); } } private IContainerFactory getContainerFactory() { if (containerFactoryServiceTracker == null) { containerFactoryServiceTracker = new ServiceTracker(bundleContext, IContainerFactory.class.getName(), null); containerFactoryServiceTracker.open(); } return (IContainerFactory) containerFactoryServiceTracker.getService(); } private void processArgs(IApplicationContext appContext) { String[] originalArgs = (String[]) appContext.getArguments().get( "application.args"); if (originalArgs == null) return; for (int i = 0; i < originalArgs.length; i++) { if (originalArgs[i].equals("-containerType")) { containerType = originalArgs[i + 1]; i++; } } } private void waitForDone() { // then just wait here synchronized (appLock) { while (!done) { try { appLock.wait(); } catch (InterruptedException e) { // do nothing } } } } /** * Method called when a REMOTE IHello instance is registered. */ public Object addingService(ServiceReference reference) { System.out.println("IHello service proxy being added"); // Since this reference is for a remote service, // The service object returned is a proxy implementing the // IHello interface IHello proxy = (IHello) bundleContext.getService(reference); // Call proxy synchronously. Note that this call may block or fail due to // synchronous communication with remote service System.out.println("STARTING remote call via proxy..."); proxy.hello(CONSUMER_NAME+" via proxy"); System.out.println("COMPLETED remote call via proxy"); System.out.println(); // Call other helloMessage method System.out.println("STARTING remote call via proxy..."); proxy.helloMessage(new HelloMessage(CONSUMER_NAME+" via proxy","howdy")); System.out.println("COMPLETED remote call via proxy"); System.out.println(); // If the proxy is also an instance of IHelloAsync then use // this asynchronous interface to invoke methods asynchronously if (proxy instanceof IHelloAsync) { IHelloAsync helloA = (IHelloAsync) proxy; // Create callback for use in IHelloAsync IAsyncCallback callback = new IAsyncCallback<String>() { public void onSuccess(String result) { System.out.println("COMPLETED remote call with callback SUCCESS with result="+result); System.out.println(); } public void onFailure(Throwable t) { System.out.println("COMPLETED remote call with callback FAILED with exception="+t); System.out.println(); } }; // Call asynchronously with callback System.out.println("STARTING async remote call via callback..."); helloA.helloAsync(CONSUMER_NAME + " via async proxy with listener", callback); System.out.println("LOCAL async invocation complete"); System.out.println(); // Call asynchronously with future System.out.println("STARTING async remote call via future..."); Future<String> future = helloA.helloAsync(CONSUMER_NAME + " via async proxy with future"); System.out.println("LOCAL async future invocation complete"); System.out.println(); try { while (!future.isDone()) { // do some other stuff System.out.println("LOCAL future not yet done...so we're doing other stuff while waiting for future to be done"); Thread.sleep(200); } // Now it's done, so this will not block String result = future.get(); System.out.println("COMPLETED remote call with future SUCCEEDED with result="+result); System.out.println(); } catch (OperationCanceledException e) { System.out.println("COMPLETED remote call with callback CANCELLED with exception="+e); System.out.println(); e.printStackTrace(); } catch (InterruptedException e) { System.out.println("COMPLETED remote call with callback INTERRUPTED with exception="+e); System.out.println(); e.printStackTrace(); } catch (ExecutionException e) { System.out.println("COMPLETED remote call with callback INTERRUPTED with exception="+e); System.out.println(); e.printStackTrace(); } // Call other helloMessage method // Call asynchronously with callback System.out.println("STARTING async remote call via callback..."); helloA.helloMessageAsync(new HelloMessage(CONSUMER_NAME + " via async proxy with listener","howdy"), callback); System.out.println("LOCAL async invocation complete"); System.out.println(); // Call asynchronously with future System.out.println("STARTING async remote call via future..."); future = helloA.helloMessageAsync(new HelloMessage(CONSUMER_NAME + " via async proxy with future","howdy")); System.out.println("LOCAL async future invocation complete"); System.out.println(); try { while (!future.isDone()) { // do some other stuff System.out.println("LOCAL future not yet done...so we're doing other stuff while waiting for future to be done"); Thread.sleep(200); } // Now it's done, so this will not block String result = future.get(); System.out.println("COMPLETED remote call with future SUCCEEDED with result="+result); System.out.println(); } catch (OperationCanceledException e) { System.out.println("COMPLETED remote call with callback CANCELLED with exception="+e); System.out.println(); e.printStackTrace(); } catch (InterruptedException e) { System.out.println("COMPLETED remote call with callback INTERRUPTED with exception="+e); System.out.println(); e.printStackTrace(); } catch (ExecutionException e) { System.out.println("COMPLETED remote call with callback INTERRUPTED with exception="+e); System.out.println(); e.printStackTrace(); } } // OSGi 4.2 remote service spec requires a property named 'service.imported' to be // set to a non-null value. In the case of any ECF provider, this 'service.imported' property // is set to the IRemoteService object associated with the remote service. IRemoteService remoteService = (IRemoteService) reference .getProperty(IDistributionConstants.SERVICE_IMPORTED); Assert.isNotNull(remoteService); // This IRemoteService instance allows allows non-blocking/asynchronous invocation of // remote methods. This allows the client to decide (at runtime if necessary) whether // to do synchronous/blocking calls or asynchronous/non-blocking calls. // It's also possible to get the remote service directly from the proxy remoteService = ((IRemoteServiceProxy) proxy).getRemoteService(); Assert.isNotNull(remoteService); // In this case, we will make an non-blocking call and immediately get a 'future'...which is // a placeholder for a result of the remote computation. This will not block. System.out.println("STARTING async remote call via future..."); IFuture future = RemoteServiceHelper.futureExec(remoteService, "hello", new Object[] { CONSUMER_NAME + " future" }); System.out.println("LOCAL async future invocation complete"); // Client can execute arbitrary code here... try { // This blocks until communication and computation have completed successfully while (!future.isDone()) { // do some other stuff System.out.println("LOCAL future not yet done...so we're doing other stuff while waiting for future to be done"); Thread.sleep(200); } // Now it's done, so this will not block Object result = future.get(); System.out.println("COMPLETED remote call with future SUCCEEDED with result="+result); System.out.println(); } catch (Exception e) { e.printStackTrace(); } return proxy; } public void modifiedService(ServiceReference reference, Object service) { } public void removedService(ServiceReference reference, Object service) { System.out.println("IHello Service proxy removed"); } }