blob: 05672b8e288e2ea3ae874db013a54becd87ea097 [file] [log] [blame]
/*
* Copyright (c) 2007-2009, 2011, 2012, 2015 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 ILifecycle)
{
return ((ILifecycle)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;
}
}
}