/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG 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: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.core.singleton; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.eclipse.riena.internal.core.singleton.RAPSingletonProvider; import org.eclipse.riena.internal.core.singleton.RCPSingletonProvider; /** * The {@code SessionServiceProvider} should be used for creating state-full * OSGi services, e.g. creating actual instances of a service, which may be used * in a RAP client.<br> * The {@code SessionServiceProvider} assures that when run in a RAP environment * the service instance will be created by RAP's session aware singleton * creation technique in a lazy manner using Java's dynamic proxies.<br> * When not run in a RAP environment the instance will just be created, i.e. * {@code Class.newInstance()}.<br> * However, in both cases an optional initializer may be executed and the * service instance will be wired. * <p> * Its intended usage is like this, where {@code IServiceInterface} is the * services interface and {@code ServiceImplementation} is the services * implementation: * * <pre> * public void start(final BundleContext context) throws Exception { * super.start(context); * Activator.plugin = this; * * IServiceInterface service = SessionServiceProvider.createService(IServiceInterface.class, * ServiceImplementation.class); * context.registerService(IServiceInterface.class.getName(), service, null); * } * </pre> * * @since 4.0 */ public final class SessionServiceProvider { private SessionServiceProvider() { } /** * Create (construct) a service instance. * * @param serviceInterfaceType * the service interface type * @param serviceType * the service implementation type * @return the service implementation */ public static <S> S createService(final Class<? super S> serviceInterfaceType, final Class<S> serviceType) { return createService(serviceInterfaceType, serviceType, null); } /** * Create (construct) a service instance. * * @param serviceInterfaceType * the service interface type * @param serviceType * the service implementation type * @param initializer * the optional initializer for the service implementation (may * be {@code null}. * @return the service implementation */ public static <S> S createService(final Class<? super S> serviceInterfaceType, final Class<S> serviceType, final ISingletonInitializer<S> initializer) { if (RAPSingletonProvider.isAvailable()) { return (S) Proxy.newProxyInstance(serviceInterfaceType.getClassLoader(), new Class<?>[] { serviceInterfaceType }, new ServiceInvocationHandler<S>(serviceType, initializer)); } return RCPSingletonProvider.getInstance(serviceType, initializer); } private static class ServiceInvocationHandler<S> implements InvocationHandler { private final Class<S> serviceType; private final ISingletonInitializer<S> initializer; public ServiceInvocationHandler(final Class<S> serviceType, final ISingletonInitializer<S> initializer) { this.serviceType = serviceType; this.initializer = initializer; } public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final S instance = RAPSingletonProvider.getInstance(serviceType, initializer); if (instance != null) { try { return method.invoke(instance, args); } catch (final InvocationTargetException e) { throw e.getTargetException(); } } throw new SingletonFailure("Could not create a session based RAP instance for type " + serviceType); //$NON-NLS-1$ } } }