/* * Copyright (c) 2007-2009, 2011, 2012, 2015, 2016 Eike Stepper (Berlin, Germany) 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: * Eike Stepper - initial API and implementation */ package org.eclipse.net4j.util.lifecycle; import org.eclipse.net4j.internal.util.bundle.OM; import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.event.IEvent; import org.eclipse.net4j.util.event.IListener; import org.eclipse.net4j.util.om.log.OMLogger.Level; import org.eclipse.net4j.util.om.trace.ContextTracer; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * Various static helper methods for dealing with {@link ILifecycle lifecycles}. * * @author Eike Stepper */ public final class LifecycleUtil { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_LIFECYCLE, LifecycleUtil.class); private LifecycleUtil() { } /** * @since 3.5 */ public static int getRefCount(Object object) { if (object instanceof ShareableLifecycle) { return ((ShareableLifecycle)object).refCount.get(); } return 0; } /** * @since 3.0 */ public static LifecycleState getLifecycleState(Object object) { if (object instanceof ILifecycle) { return ((ILifecycle)object).getLifecycleState(); } return object != null ? LifecycleState.ACTIVE : LifecycleState.INACTIVE; } /** * @since 3.2 */ public static boolean isDeferredActivation(Object object) { if (object instanceof ILifecycle.DeferrableActivation) { return ((ILifecycle.DeferrableActivation)object).isDeferredActivation(); } return false; } public static boolean isActive(Object object) { if (object instanceof ILifecycle) { return ((ILifecycle)object).isActive(); } return object != null; } /** * @since 2.0 */ public static void checkActive(Object object) throws LifecycleException { if (!isActive(object)) { throw new LifecycleException("Not active: " + object); //$NON-NLS-1$ } } /** * @since 2.0 */ public static void checkInactive(Object object) throws LifecycleException { if (isActive(object)) { throw new LifecycleException("Not inactive: " + object); //$NON-NLS-1$ } } public static void activate(Object object) throws LifecycleException { activate(object, false); } /** * @see Activator */ public static void activate(Object object, boolean useAnnotation) throws LifecycleException { if (object instanceof ILifecycle) { ((ILifecycle)object).activate(); } else if (object != null && useAnnotation) { invokeAnnotation(object, Activator.class); } } public static Exception activateSilent(Object object) { return activateSilent(object, false); } /** * @see Activator */ public static Exception activateSilent(Object object, boolean useAnnotation) { try { activate(object, useAnnotation); return null; } catch (Exception ex) { OM.LOG.error(ex); return ex; } } public static boolean waitForActive(Object object, long millis) { return waitFor(object, millis, LifecycleState.ACTIVE); } /** * @since 3.1 */ public static boolean waitForInactive(Object object, long millis) { return waitFor(object, millis, LifecycleState.INACTIVE); } /** * @since 3.1 */ public static boolean waitFor(Object object, long millis, final LifecycleState state) { try { if (object instanceof ILifecycle) { ILifecycle lifecycle = (ILifecycle)object; if (lifecycle.getLifecycleState() == state) { return true; } final CountDownLatch latch = new CountDownLatch(1); IListener adapter = new IListener() { public void notifyEvent(IEvent event) { if (event instanceof ILifecycleEvent) { ILifecycleEvent e = (ILifecycleEvent)event; if (e.getSource().getLifecycleState() == state) { latch.countDown(); } } } }; try { lifecycle.addListener(adapter); latch.await(millis, TimeUnit.MILLISECONDS); } finally { lifecycle.removeListener(adapter); } return lifecycle.getLifecycleState() == state; } return true; } catch (Exception ex) { throw WrappedException.wrap(ex); } } public static Exception deactivate(Object object) { return deactivate(object, false); } /** * @see Deactivator */ public static Exception deactivate(Object object, boolean useAnnotation) { if (object instanceof IDeactivateable) { return ((IDeactivateable)object).deactivate(); } else if (object != null && useAnnotation) { // TODO Handle evtl. return value (exception) invokeAnnotation(object, Deactivator.class); } return null; } /** * @since 2.0 */ public static void deactivate(Object object, Level logLevel) { Exception exception = deactivate(object); if (exception != null) { OM.LOG.log(logLevel, "Problem while deactivating " + object, exception); //$NON-NLS-1$ } } public static void deactivateNoisy(Object object) throws LifecycleException { deactivateNoisy(object, false); } public static void deactivateNoisy(Object object, boolean useAnnotation) throws LifecycleException { Exception ex = deactivate(object, useAnnotation); if (ex instanceof RuntimeException) { throw (RuntimeException)ex; } else if (ex != null) { throw new LifecycleException(ex); } } /** * @since 2.0 */ public static <T> T delegateLifecycle(ClassLoader loader, T pojo, Class<?> pojoInterface, ILifecycle delegate) { return Delegator.newProxy(loader, pojo, pojoInterface, delegate); } /** * @since 2.0 */ public static <T> T delegateLifecycle(ClassLoader loader, T pojo, ILifecycle delegate) { return Delegator.newProxy(loader, pojo, pojo.getClass(), delegate); } private static <T extends Annotation> void invokeAnnotation(Object object, Class<T> annotationClass) { Class<?> c = object.getClass(); while (c != Object.class) { final Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { if (method.getParameterTypes().length == 0) { Annotation annotation = method.getAnnotation(annotationClass); if (annotation != null) { invokeMethod(object, method); boolean propagate = annotationClass == Activator.class ? ((Activator)annotation).propagate() : ((Deactivator)annotation).propagate(); if (!propagate) { break; } } } } c = c.getSuperclass(); } } private static Object invokeMethod(Object object, Method method) { try { return method.invoke(object, (Object[])null); } catch (IllegalAccessException iae) { try { method.setAccessible(true); return method.invoke(object, (Object[])null); } catch (Exception ex) { if (TRACER.isEnabled()) { TRACER.trace(ex); } } } catch (Exception ex) { if (TRACER.isEnabled()) { TRACER.trace(ex); } } return null; } /** * Annotates a method of a POJO class that's supposed to be called to <em>activate</em> a POJO object during * {@link LifecycleUtil#activate(Object)}. * * @author Eike Stepper * @apiviz.exclude */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Activator { boolean propagate() default true; } /** * Annotates a method of a POJO class that's supposed to be called to <em>deactivate</em> a POJO object during * {@link LifecycleUtil#deactivate(Object)}. * * @author Eike Stepper * @apiviz.exclude */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Deactivator { boolean propagate() default true; } /** * The {@link InvocationHandler invocation handler} of the {@link Proxy dynamic proxy} created in * {@link LifecycleUtil#delegateLifecycle(ClassLoader, Object, ILifecycle) LifecycleUtil.delegateLifecycle()}. * * @author Eike Stepper * @since 2.0 * @apiviz.exclude */ public static final class Delegator<T> implements InvocationHandler { private static final Class<ILifecycle> INTERFACE = ILifecycle.class; private T pojo; private ILifecycle delegate; public Delegator(T pojo, ILifecycle delegate) { this.pojo = pojo; this.delegate = delegate; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); if (name.equals("activate")) //$NON-NLS-1$ { delegate.activate(); return null; } if (name.equals("deactivate")) //$NON-NLS-1$ { return delegate.deactivate(); } if (name.equals("isActive")) //$NON-NLS-1$ { return delegate.isActive(); } if (name.equals("getLifecycleState")) //$NON-NLS-1$ { return delegate.getLifecycleState(); } if (name.equals("getListeners")) //$NON-NLS-1$ { return delegate.getListeners(); } if (name.equals("hasListeners")) //$NON-NLS-1$ { return delegate.hasListeners(); } if (name.equals("addListener")) //$NON-NLS-1$ { delegate.addListener((IListener)args[0]); return null; } if (name.equals("removeListener")) //$NON-NLS-1$ { delegate.removeListener((IListener)args[0]); return null; } if (name.equals("toString")) //$NON-NLS-1$ { return delegate.toString(); } try { return method.invoke(pojo, args); } catch (Exception ex) { throw ex; } } public static <T> T newProxy(ClassLoader loader, T pojo, Class<?> pojoInterface, ILifecycle delegate) { if (pojo == null) { return pojo; } Delegator<T> h = new Delegator<T>(pojo, delegate); final Class<?>[] interfaces = { pojoInterface, INTERFACE }; @SuppressWarnings("unchecked") T proxy = (T)Proxy.newProxyInstance(loader, interfaces, h); return proxy; } } }