From: markt Date: Thu, 4 Mar 2010 18:07:59 +0000 (+0000) Subject: Lifecycle refactoring. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=de3485e1e7bfc6f38513560a8c07dd4849655082;p=tomcat7.0 Lifecycle refactoring. In an effort to reduce code duplication and improve consistency, provide a base Lifecycle implementation. This will be used as the basis of the refactoring of the components that implement Lifecycle git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@919102 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/catalina/util/LifecycleBase.java b/java/org/apache/catalina/util/LifecycleBase.java new file mode 100644 index 000000000..936df3710 --- /dev/null +++ b/java/org/apache/catalina/util/LifecycleBase.java @@ -0,0 +1,260 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.LifecycleState; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Base implementation of the {@link Lifecycle} interface that implements the + * state transition rules for {@link Lifecycle#start()} and + * {@link Lifecycle#stop()} + */ +public abstract class LifecycleBase implements Lifecycle { + + private static Log log = LogFactory.getLog(LifecycleBase.class); + + private static StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + + /** + * Used to handle firing lifecycle events. + * TODO: Consider merging LifecycleSupport into this class. + */ + private LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The current state of the source component. + */ + private volatile LifecycleState state = LifecycleState.NEW; + + + /** + * {@inheritDoc} + */ + @Override + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + + /** + * {@inheritDoc} + */ + @Override + public LifecycleListener[] findLifecycleListeners() { + return lifecycle.findLifecycleListeners(); + } + + + /** + * {@inheritDoc} + */ + @Override + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + + /** + * Allow sub classes to fire {@link Lifecycle} events. + * + * @param type Event type + * @param data Data associated with event. + */ + protected void fireLifecycleEvent(String type, Object data) { + lifecycle.fireLifecycleEvent(type, data); + } + + + /** + * {@inheritDoc} + */ + @Override + public final void start() throws LifecycleException { + + synchronized (this) { + if(LifecycleState.STARTING_PREP.equals(state) || + LifecycleState.STARTING.equals(state) || + LifecycleState.STARTED.equals(state)) { + + if(log.isInfoEnabled()) { + log.info(sm.getString("lifecycleBase.alreadyStarted", + toString())); + } + + return; + } + + if (!state.equals(LifecycleState.NEW) && + !state.equals(LifecycleState.STOPPED)) { + invalidTransition(Lifecycle.BEFORE_START_EVENT); + } + + // Set state and fire event separately rather than via setState() + // so event fires outside of sync boundary + state = LifecycleState.STARTING_PREP; + } + + lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_START_EVENT, null); + + startInternal(); + + if (state.equals(LifecycleState.FAILED) || + state.equals(LifecycleState.MUST_STOP)) { + stop(); + } else { + // Shouldn't be necessary but acts as a check that sub-classes are doing + // what they are supposed to. + if (!state.equals(LifecycleState.STARTING)) { + invalidTransition(Lifecycle.AFTER_START_EVENT); + } + + setState(LifecycleState.STARTED); + } + } + + + /** + * Sub-classes must ensure that: + * + * + * If a component fails to start it may either throw a + * {@link LifecycleException} which will cause it's parent to fail to start + * or it can place itself in the error state in which case {@link #stop()} + * will be called on the failed component but the parent component will + * continue to start normally. + * + * @throws LifecycleException + */ + protected abstract void startInternal() throws LifecycleException; + + + /** + * {@inheritDoc} + */ + @Override + public final void stop() throws LifecycleException { + + synchronized (this) { + if(LifecycleState.STOPPING_PREP.equals(state) || + LifecycleState.STOPPING.equals(state) || + LifecycleState.STOPPED.equals(state)) { + + if(log.isInfoEnabled()) { + log.info(sm.getString("lifecycleBase.alreadyStopped", + toString())); + } + + return; + } + + if (!state.equals(LifecycleState.STARTED) && + !state.equals(LifecycleState.FAILED)) { + invalidTransition(Lifecycle.BEFORE_STOP_EVENT); + } + + // Set state and fire event separately rather than via setState() + // so event fires outside of sync boundary + state = LifecycleState.STOPPING_PREP; + } + + lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_STOP_EVENT, null); + + stopInternal(); + + // Shouldn't be necessary but acts as a check that sub-classes are doing + // what they are supposed to. + if (!state.equals(LifecycleState.STOPPING)) { + invalidTransition(Lifecycle.AFTER_STOP_EVENT); + } + + setState(LifecycleState.STOPPED); + } + + + /** + * Sub-classes must ensure that: + * + * + * @throws LifecycleException + */ + protected abstract void stopInternal() throws LifecycleException; + + + /** + * {@inheritDoc} + */ + public LifecycleState getState() { + return state; + } + + + /** + * Provides a mechanism for sub-classes to update the component state. + * Calling this method will automatically fire any associated + * {@link Lifecycle} event. + * + * @param state The new state for this component + */ + protected void setState(LifecycleState state) { + setState(state, null); + } + + + /** + * Provides a mechanism for sub-classes to update the component state. + * Calling this method will automatically fire any associated + * {@link Lifecycle} event. + * + * @param state The new state for this component + * @param data The data to pass to the associated {@link Lifecycle} event + */ + protected void setState(LifecycleState state, Object data) { + this.state = state; + String lifecycleEvent = state.getLifecycleEvent(); + if (lifecycleEvent != null) { + fireLifecycleEvent(lifecycleEvent, data); + } + } + + + private void invalidTransition(String type) throws LifecycleException { + String msg = sm.getString("lifecycleBase.invalidTransition", type, + toString(), state); + throw new LifecycleException(msg); + } +} diff --git a/java/org/apache/catalina/util/LocalStrings.properties b/java/org/apache/catalina/util/LocalStrings.properties index d101e52ad..b61f7cf1b 100644 --- a/java/org/apache/catalina/util/LocalStrings.properties +++ b/java/org/apache/catalina/util/LocalStrings.properties @@ -19,9 +19,12 @@ hexUtil.bad=Bad hexadecimal digit hexUtil.odd=Odd number of hexadecimal digits #Default Messages Utilized by the ExtensionValidator extensionValidator.web-application-manifest=Web Application Manifest -extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension "{2}" not found. -extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find {1} required extension(s). -extensionValidator.failload=Failure loading extension {0} +extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension [{2}] not found. +extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find [{1}] required extension(s). +extensionValidator.failload=Failure loading extension [{0}] +lifecycleBase.alreadyStarted=The start() method was called on component [{0}] after start() had already been called. The second call will be ignored. +lifecycleBase.alreadyStopped=The stop() method was called on component [{0}] after stop() had already been called. The second call will be ignored. +lifecycleBase.invalidTransition=An invalid Lifecycle transition was attempted ([{0}]) for component [{1}] in state [{2}] requestUtil.convertHexDigit.notHex=[{0}] is not a hexadecimal digit requestUtil.parseParameters.uee=Unable to parse the parameters since the encoding [{0}] is not supported. requestUtil.urlDecode.missingDigit=The % character must be followed by two hexademical digits