blob: b70a4c54a4947502d66becf8a9394828f786de6a [file] [log] [blame]
/*
* Copyright (c) 2008-2012, 2019 Eike Stepper (Loehne, 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.CheckUtil;
import org.eclipse.net4j.util.ReflectUtil;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.Notifier;
import org.eclipse.net4j.util.lifecycle.ILifecycle.DeferrableActivation;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import java.util.concurrent.Semaphore;
/**
* A default implementation of an entity with a {@link ILifecycle lifecycle}.
*
* @author Eike Stepper
*/
public class Lifecycle extends Notifier implements ILifecycle, DeferrableActivation
{
public static boolean USE_LABEL = true;
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_LIFECYCLE, Lifecycle.class);
private static final ContextTracer DUMPER = new ContextTracer(OM.DEBUG_LIFECYCLE_DUMP, Lifecycle.class);
private static final boolean TRACE_IGNORING = false;
private static final boolean LOCKING = true;
private LifecycleState lifecycleState = LifecycleState.INACTIVE;
@ExcludeFromDump
private Semaphore lifecycleSemaphore = new Semaphore(1);
/**
* @since 2.0
*/
public Lifecycle()
{
}
void internalActivate() throws LifecycleException
{
try
{
if (lifecycleState == LifecycleState.INACTIVE)
{
if (TRACER.isEnabled())
{
TRACER.trace("Activating " + this); //$NON-NLS-1$
}
lock();
IListener[] listeners = getListeners();
if (listeners != null)
{
fireEvent(new LifecycleEvent(this, ILifecycleEvent.Kind.ABOUT_TO_ACTIVATE), listeners);
}
doBeforeActivate();
lifecycleState = LifecycleState.ACTIVATING;
doActivate();
if (!isDeferredActivation())
{
deferredActivate(true);
}
dump();
}
else
{
if (TRACE_IGNORING)
{
if (TRACER.isEnabled())
{
TRACER.format("Ignoring activation in state {0} for {1}", lifecycleState, this); //$NON-NLS-1$
}
}
}
}
catch (RuntimeException ex)
{
deferredActivate(false);
throw ex;
}
catch (Exception ex)
{
deferredActivate(false);
throw new LifecycleException(ex);
}
}
Exception internalDeactivate()
{
try
{
if (lifecycleState == LifecycleState.ACTIVE)
{
if (TRACER.isEnabled())
{
TRACER.trace("Deactivating " + this); //$NON-NLS-1$
}
lock();
doBeforeDeactivate();
IListener[] listeners = getListeners();
if (listeners != null)
{
fireEvent(new LifecycleEvent(this, ILifecycleEvent.Kind.ABOUT_TO_DEACTIVATE), listeners);
}
lifecycleState = LifecycleState.DEACTIVATING;
doDeactivate();
lifecycleState = LifecycleState.INACTIVE;
unlock();
if (listeners != null)
{
fireEvent(new LifecycleEvent(this, ILifecycleEvent.Kind.DEACTIVATED), listeners);
}
return null;
}
if (TRACE_IGNORING)
{
if (TRACER.isEnabled())
{
TRACER.format("Ignoring deactivation in state {0} for {1}", lifecycleState, this); //$NON-NLS-1$
}
}
return null;
}
catch (Exception ex)
{
lifecycleState = LifecycleState.INACTIVE;
unlock();
return ex;
}
}
public final void activate() throws LifecycleException
{
internalActivate();
}
public final Exception deactivate()
{
return internalDeactivate();
}
/**
* @since 3.0
*/
public final LifecycleState getLifecycleState()
{
return lifecycleState;
}
public final boolean isActive()
{
return lifecycleState == LifecycleState.ACTIVE;
}
@Override
public String toString()
{
if (USE_LABEL)
{
return ReflectUtil.getLabel(this);
}
return super.toString();
}
protected final void dump()
{
if (DUMPER.isEnabled())
{
DUMPER.trace("DUMP" + ReflectUtil.toString(this)); //$NON-NLS-1$
}
}
protected final void checkActive()
{
LifecycleUtil.checkActive(this);
}
protected final void checkInactive()
{
LifecycleUtil.checkInactive(this);
}
protected final void checkNull(Object handle, String msg) throws NullPointerException
{
CheckUtil.checkNull(handle, msg);
}
protected final void checkArg(boolean expr, String msg) throws IllegalArgumentException
{
CheckUtil.checkArg(expr, msg);
}
protected final void checkArg(Object handle, String handleName) throws IllegalArgumentException
{
CheckUtil.checkState(handle, handleName);
}
protected final void checkState(boolean expr, String msg) throws IllegalStateException
{
CheckUtil.checkState(expr, msg);
}
protected final void checkState(Object handle, String handleName) throws IllegalStateException
{
CheckUtil.checkState(handle, handleName);
}
/**
* @since 2.0
*/
protected final void deferredActivate(boolean successful)
{
if (successful)
{
lifecycleState = LifecycleState.ACTIVE;
try
{
doAfterActivate();
}
catch (Exception ex)
{
OM.LOG.error(ex);
deactivate();
return;
}
unlock();
IListener[] listeners = getListeners();
if (listeners != null)
{
fireEvent(new LifecycleEvent(this, ILifecycleEvent.Kind.ACTIVATED), listeners);
}
}
else
{
lifecycleState = LifecycleState.INACTIVE;
unlock();
}
}
/**
* @since 3.2
*/
public boolean isDeferredActivation()
{
return false;
}
protected void doBeforeActivate() throws Exception
{
}
protected void doActivate() throws Exception
{
}
/**
* @since 3.0
*/
protected void doAfterActivate() throws Exception
{
}
protected void doBeforeDeactivate() throws Exception
{
}
protected void doDeactivate() throws Exception
{
}
private void lock() throws InterruptedException
{
if (LOCKING)
{
lifecycleSemaphore.acquire();
}
}
private void unlock()
{
if (LOCKING)
{
lifecycleSemaphore.release();
}
}
}