com.caucho.lifecycle.Lifecycle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.lifecycle;
import static com.caucho.lifecycle.LifecycleState.ACTIVE;
import static com.caucho.lifecycle.LifecycleState.DESTROYED;
import static com.caucho.lifecycle.LifecycleState.DESTROYING;
import static com.caucho.lifecycle.LifecycleState.FAILED;
import static com.caucho.lifecycle.LifecycleState.INIT;
import static com.caucho.lifecycle.LifecycleState.INITIALIZING;
import static com.caucho.lifecycle.LifecycleState.STARTING;
import static com.caucho.lifecycle.LifecycleState.STOPPED;
import static com.caucho.lifecycle.LifecycleState.STOPPED_IDLE;
import static com.caucho.lifecycle.LifecycleState.STOPPING;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.caucho.util.CurrentTime;
/**
* Lifecycle class.
*/
public final class Lifecycle {
private final Logger _log;
private String _name;
private Level _level = Level.FINE;
private Level _lowLevel = Level.FINER;
private final AtomicReference _state
= new AtomicReference(LifecycleState.NEW);
private long _activeCount;
private long _failCount;
private long _lastFailTime;
private long _lastChangeTime;
private ArrayList> _listeners;
/**
* Creates an anonymous lifecycle.
*/
public Lifecycle()
{
_log = null;
}
/**
* Creates an lifecycle with logger and name.
*/
public Lifecycle(Logger log)
{
_log = log;
}
/**
* Creates an lifecycle with logger and name.
*/
public Lifecycle(Logger log, String name)
{
_log = log;
_name = name;
}
/**
* Creates an lifecycle with logger, a name, and a level.
*/
public Lifecycle(Logger log, String name, Level level)
{
_log = log;
_name = name;
setLevel(level);
}
/**
* Gets the lifecycle name.
*/
public String getName()
{
return _name;
}
/**
* Sets the lifecycle name, and the level to Level.INFO.
*/
public void setName(String name)
{
_name = name;
}
/**
* Gets the lifecycle logging level.
*/
public Level getLevel()
{
return _level;
}
/**
* Sets the lifecycle logging level.
*/
public void setLevel(Level level)
{
_level = level;
if (level.intValue() < _lowLevel.intValue())
_lowLevel = level;
}
public final LifecycleState getState()
{
return _state.get();
}
/**
* Returns the current state.
*/
public int getStateOrdinal()
{
return _state.get().ordinal();
}
/**
* Returns the state name for the passed state.
*/
/*
public static String getStateName(int state)
{
switch (state) {
case IS_NEW:
return "new";
case IS_INITIALIZING:
return "initializing";
case IS_INIT:
return "init";
case IS_STARTING:
return "starting";
case IS_ACTIVE:
return "active";
case IS_FAILED:
return "failed";
case IS_STOPPING:
return "stopping";
case IS_STOPPED:
return "stopped";
case IS_DESTROYING:
return "destroying";
case IS_DESTROYED:
return "destroyed";
default:
return "unknown";
}
}
*/
/**
* Returns the current state name.
*/
public String getStateName()
{
return getState().toString();
}
/**
* Returns the last lifecycle change time.
*/
public long getLastChangeTime()
{
return _lastChangeTime;
}
/**
* Returns the last failure time.
*/
public long getLastFailTime()
{
return _lastFailTime;
}
/**
* Returns the number of times the lifecycle has switched to active.
*/
public long getActiveCount()
{
return _activeCount;
}
/**
* Returns the number of times the lifecycle has switched to failing.
*/
public long getFailCount()
{
return _failCount;
}
/**
* Returns true for the initializing state.
*/
public boolean isInitializing()
{
return getState().isInitializing();
}
/**
* Returns true for the init state.
*/
public boolean isInit()
{
return getState().isInit();
}
/**
* Returns true for the init state.
*/
public boolean isBeforeInit()
{
return getState().isBeforeInit();
}
/**
* True for any state after initialization.
*/
public boolean isAfterInit()
{
return getState().isAfterInit();
}
/**
* True for an idle state, where any request would transition to an
* active state.
*/
public boolean isIdle()
{
return getState().isIdle();
}
/**
* Returns true if the service is starting.
*/
public boolean isStarting()
{
return getState().isStarting();
}
/**
* Returns true if the service is starting.
*/
/*
public boolean isAfterStarting()
{
return getState().isAfterStarting();
}
*/
/**
* Returns true for the warmup state.
*/
public boolean isWarmup()
{
return getState().isWarmup();
}
/**
* Returns true for the initializing state.
*/
public boolean isBeforeActive()
{
return getState().isBeforeActive();
}
/**
* Returns true for the closing states
*/
/*
public boolean isAfterActive()
{
return getState().isAfterActive();
}
*/
/**
* Wait for a period of time until the service starts.
*/
public boolean waitForActive(long timeout)
{
LifecycleState state = getState();
if (state.isActive()) {
return true;
}
else if (state.isAfterActive()) {
return false;
}
// server/1d2j
long waitEnd = CurrentTime.getCurrentTimeActual() + timeout;
synchronized (this) {
while ((state = _state.get()).isBeforeActive()
&& CurrentTime.getCurrentTimeActual() < waitEnd) {
if (state.isActive()) {
return true;
}
else if (state.isAfterActive()) {
return false;
}
try {
long delta = waitEnd - CurrentTime.getCurrentTimeActual();
if (delta > 0) {
wait(delta);
}
} catch (InterruptedException e) {
}
}
}
return _state.get().isActive();
}
/**
* Returns true for the active state.
*/
public boolean isActive()
{
return getState().isActive();
}
/**
* Returns true for the a runnable state, including warmup
*/
public boolean isRunnable()
{
return getState().isRunnable();
/*
int state = _state.get();
return IS_WARMUP <= state && state <= IS_ACTIVE;
*/
}
/**
* Returns true for the closing states
*/
public boolean isAfterStopping()
{
return getState().isAfterStopping();
}
/**
* Returns true for the failed state.
*/
public boolean isError()
{
return getState().isError();
}
/**
* Returns true for the failed state.
*/
public boolean isFailed()
{
return getState().isError();
}
/**
* True if a stop for a restart would be allowed.
*/
public boolean isAllowStopFromRestart()
{
return getState().isAllowStopFromRestart();
}
/**
* Returns true if the state is stopping.
*/
public boolean isStopping()
{
return getState().isStopping();
}
/**
* Returns true if the state is stopping.
*/
public boolean isStopped()
{
return getState().isStopped();
}
/**
* Returns true if the state is closed
*/
public boolean isDestroying()
{
return getState().isDestroying();
}
/**
* Returns true if the state is closed
*/
public boolean isDestroyed()
{
return getState().isDestroyed();
}
/**
* Changes to the initializing state.
*
* @return true if the transition is allowed
*/
public boolean toInitializing()
{
return toNextState(INITIALIZING);
}
/**
* Changes to the init state.
*
* @return true if the transition is allowed
*/
public boolean toInit()
{
return toNextState(INIT);
}
/**
* Changes to the init from the stopped state.
*
* @return true if the transition is allowed
*/
public boolean toPostInit()
{
if (_state.compareAndSet(STOPPED, INIT)) {
_lastChangeTime = CurrentTime.getCurrentTime();
notifyListeners(STOPPED, INIT);
return true;
}
else
return _state.get().isInit();
}
/**
* Changes to the starting state.
*
* @return true if the transition is allowed
*/
public boolean toStarting()
{
LifecycleState state;
do {
state = _state.get();
if (state.isAfterStarting() && ! state.isStopped())
return false;
} while (! _state.compareAndSet(state, STARTING));
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_level) && _log.isLoggable(Level.FINE))
_log.fine(_name + " starting");
notifyListeners(state, STARTING);
return true;
}
/**
* Changes to the active state.
*
* @return true if the transition is allowed
*/
public boolean toActive()
{
LifecycleState state;
do {
state = _state.get();
if (state.isAfterActive() && ! state.isStopped())
return false;
} while (! _state.compareAndSet(state, ACTIVE));
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_level))
_log.log(_level, _name + " active");
notifyListeners(state, ACTIVE);
return true;
}
/**
* Changes to the error state.
*
* @return true if the transition is allowed
*/
public boolean toError()
{
return toFail();
}
/**
* Changes to the failed state.
*
* @return true if the transition is allowed
*/
public boolean toFail()
{
LifecycleState state;
do {
state = _state.get();
if (state.isAfterDestroying()) {
return false;
}
} while (! _state.compareAndSet(state, FAILED));
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_level))
_log.log(_level, _name + " fail");
notifyListeners(state, FAILED);
_failCount++;
return true;
}
/**
* Changes to the stopping state.
*
* @return true if the transition is allowed
*/
public boolean toStopping()
{
LifecycleState state;
do {
state = _state.get();
if (state.isAfterStopping() || state.isStarting()) {
return false;
}
} while (! _state.compareAndSet(state, STOPPING));
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_level)) {
_log.log(_level, _name + " stopping");
}
notifyListeners(state, STOPPING);
return true;
}
/**
* Changes to the idle (stopped) state.
*
* @return true if the transition is allowed
*/
public boolean toIdle()
{
return toState(STOPPED_IDLE);
}
/**
* Changes to the stopped state.
*
* @return true if the transition is allowed
*/
public boolean toStop()
{
return toNextState(STOPPED);
}
/**
* Changes to the destroying state.
*
* @return true if the transition is allowed
*/
public boolean toDestroying()
{
return toNextState(DESTROYING);
}
/**
* Changes to the closed state.
*
* @return true if the transition is allowed
*/
public boolean toDestroy()
{
return toNextState(DESTROYED);
}
/**
* Changes to the next state.
*
* @return true if the transition is allowed
*/
private boolean toNextState(LifecycleState newState)
{
LifecycleState state;
do {
state = _state.get();
if (newState.ordinal() <= state.ordinal())
return false;
} while (! _state.compareAndSet(state, newState));
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_lowLevel)) {
_log.log(_lowLevel, _name + " " + newState);
}
notifyListeners(state, newState);
return true;
}
/**
* Changes to the next state.
*
* @return true if the transition is allowed
*/
private boolean toState(LifecycleState newState)
{
LifecycleState state = _state.getAndSet(newState);
_lastChangeTime = CurrentTime.getCurrentTime();
if (_log != null && _log.isLoggable(_lowLevel))
_log.log(_lowLevel, _name + " " + newState);
notifyListeners(state, newState);
return true;
}
//
// listeners
//
/**
* Adds a listener to detect lifecycle changes.
*/
public void addListener(LifecycleListener listener)
{
synchronized (this) {
if (isDestroyed()) {
IllegalStateException e = new IllegalStateException("attempted to add listener to a destroyed lifecyle " + this);
if (_log != null)
_log.log(Level.WARNING, e.toString(), e);
else
Logger.getLogger(Lifecycle.class.getName()).log(Level.WARNING, e.toString(), e);
return;
}
if (_listeners == null)
_listeners = new ArrayList>();
for (int i = _listeners.size() - 1; i >= 0; i--) {
LifecycleListener oldListener = _listeners.get(i).get();
if (listener == oldListener)
return;
else if (oldListener == null)
_listeners.remove(i);
}
_listeners.add(new WeakReference(listener));
}
}
/**
* Removes a listener.
*/
public void removeListener(LifecycleListener listener)
{
synchronized (this) {
if (_listeners == null)
return;
for (int i = _listeners.size() - 1; i >= 0; i--) {
LifecycleListener oldListener = _listeners.get(i).get();
if (listener == oldListener) {
_listeners.remove(i);
return;
}
else if (oldListener == null)
_listeners.remove(i);
}
}
}
/**
* Returns the listeners.
*/
private void notifyListeners(LifecycleState oldState, LifecycleState newState)
{
// initial must be outside synchronized to avoid any blocking
// for fail-safe shutdown
if (_listeners == null) {
return;
}
ArrayList listeners = null;
synchronized (this) {
notifyAll();
if (_listeners != null) {
for (int i = 0; i < _listeners.size(); i++) {
LifecycleListener listener = _listeners.get(i).get();
if (listener != null) {
if (listeners == null) {
listeners = new ArrayList();
}
listeners.add(listener);
}
else {
_listeners.remove(i);
i--;
}
}
}
}
if (listeners != null) {
for (LifecycleListener listener : listeners) {
listener.lifecycleEvent(oldState, newState);
}
}
}
/**
* Copies from a target state.
*
* @return true if the transition is allowed
*/
public void copyState(Lifecycle source)
{
_state.set(source._state.get());
}
/**
* Debug string value.
*/
public String toString()
{
if (_name != null)
return "Lifecycle[" + _name + ", " + getStateName() + "]";
else
return "Lifecycle[" + getStateName() + "]";
}
}