Search in sources :

Example 1 with AcsJComponentDeactivationUncleanEx

use of alma.maciErrType.wrappers.AcsJComponentDeactivationUncleanEx in project ACS by ACS-Community.

the class ComponentAdapter method deactivateComponent.

/**
	 * Deactivates a component.
	 * <ol>
	 *  <li>First the component's POA manager is put into inactive state, so that all incoming calls to this component are rejected. 
	 *      However, we wait for currently executing calls to finish, with a timeout as described below.
	 *  <ul>
	 *   <li>Rejection applies to requests already received and queued by the ORB (but that have not started executing), 
	 *       as well as to requests that clients will send in the future. 
	 *   <li>Note that entering into the inactive state may take forever if the component hangs in a functional call.
	 *   <li>Therefore we use a timeout to proceed in such cases where POA manager deactivation does not happen in time.
	 *       This bears the risk of undesirable behavior caused by calling the {@link ComponentLifecycle#cleanUp() cleanUp} 
	 *       method while other threads still perform functional calls on the component.
	 *  </ul>
	 *  <li>Second the component itself is deactivated:
	 *  <ul>
	 *   <li>The lifecycle method {@link ComponentLifecycle#cleanUp() cleanUp} is called, currently without enforcing a timeout.
	 *   <li>TODO: use a timeout, unless we decide that a client-side timeout for releaseComponent is good enough.
	 *  </ul>
	 *  <li>Third the component is disconnected from CORBA ("etherealized" from the POA).
	 *  <ul>
	 *   <li>Note that also etherealization may take forever if the component hangs in a call.
	 *   <li>Therefore we use a timeout to proceed with deactivation in such cases where etherealization does not happen in time.
	 *   <li>Currently a component that failed to etherealize in time can stay active as long as the container is alive.
	 *       TODO: check if using the "container sealant" we can identify and stop the active ORB threads.
	 *  </ul>
	 * </ol>   
	 * This method logs errors as FINER if they also cause an exception, and as WARNING if they cannot lead to an exception
	 * because other more important error conditions are present.
	 * 
	 * @throws ComponentDeactivationUncleanEx, ComponentDeactivationFailedEx 
	 */
void deactivateComponent() throws AcsJComponentDeactivationUncleanEx, AcsJComponentDeactivationFailedEx {
    if (m_containerLogger.isLoggable(Level.FINER)) {
        m_containerLogger.finer("About to deactivate component " + m_compInstanceName + " with handle " + getHandle());
    }
    AcsJComponentDeactivationUncleanEx deactivationUncleanEx = null;
    AcsJComponentDeactivationFailedEx deactivationFailedEx = null;
    try {
        // (1) try to reject calls by sending poa manager to inactive state  
        // TODO: make the timeout configurable
        int deactivateTimeoutMillis = 10000;
        boolean isInactive = acsCorba.deactivateComponentPOAManager(m_componentPOA, m_compInstanceName, deactivateTimeoutMillis);
        if (isInactive && m_containerLogger.isLoggable(Level.FINER)) {
            m_containerLogger.finer("Now rejecting any calls to component '" + m_compInstanceName + "'. Will call cleanUp() next.");
        } else if (!isInactive) {
            String msg = "Component '" + m_compInstanceName + "' failed to reject calls within " + deactivateTimeoutMillis + " ms, probably because of pending calls. Will call cleanUp() anyway.";
            m_containerLogger.warning(msg);
            deactivationUncleanEx = new AcsJComponentDeactivationUncleanEx();
            deactivationUncleanEx.setCURL(m_compInstanceName);
            deactivationUncleanEx.setReason(msg);
        // do not yet throw deactivationUncleanEx as we need to go through the other steps first
        }
        // (2) call the lifecycle method cleanUp and also clean container services and other support classes 
        ClassLoader contCL = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(m_componentClassLoader);
        try {
            // TODO: also use a timeout for cleanUp
            m_component.cleanUp();
        } catch (Throwable thr) {
            // AcsJComponentCleanUpEx is declared, but any other ex will be wrapped by AcsJComponentDeactivationUncleanEx as well
            m_containerLogger.log(Level.FINE, "Failure in cleanUp() method of component " + m_compInstanceName, thr);
            // this would override a previous ex from POA deactivation 
            deactivationUncleanEx = new AcsJComponentDeactivationUncleanEx(thr);
            deactivationUncleanEx.setCURL(m_compInstanceName);
        // do not yet throw deactivationUncleanEx as we need to nonetheless destroy the POA
        } finally {
            Thread.currentThread().setContextClassLoader(contCL);
            try {
                m_componentStateManager.setStateByContainer(ComponentStates.COMPSTATE_DEFUNCT);
            } catch (ComponentLifecycleException ex) {
                if (deactivationUncleanEx == null) {
                    // an ex from cleanUp would be more important
                    deactivationUncleanEx = new AcsJComponentDeactivationUncleanEx(ex);
                    deactivationUncleanEx.setCURL(m_compInstanceName);
                } else {
                    m_containerLogger.log(Level.WARNING, "Failed to set component state DEFUNCT on " + m_compInstanceName, ex);
                }
            }
            m_containerServices.cleanUp();
            m_threadFactory.cleanUp();
        }
        // (3) destroy the component POA
        // since we already tried to discard requests using the poa manager before,
        // the additional timeout can be kept small. If calls are pending, we fail.
        int etherealizeTimeoutMillis = 1000;
        boolean isEtherealized = acsCorba.destroyComponentPOA(m_componentPOA, compServantManager, etherealizeTimeoutMillis);
        if (isEtherealized && m_containerLogger.isLoggable(Level.FINER)) {
            m_containerLogger.finer("Component '" + m_compInstanceName + "' is etherealized.");
        } else if (!isEtherealized) {
            m_containerLogger.warning("Component '" + m_compInstanceName + "' failed to be etherealized in " + etherealizeTimeoutMillis + " ms, probably because of pending calls.");
            deactivationFailedEx = new AcsJComponentDeactivationFailedEx();
            deactivationFailedEx.setCURL(m_compInstanceName);
            deactivationFailedEx.setReason("Component POA etherialization timed out after " + etherealizeTimeoutMillis + " ms.");
            // @TODO: distinguish the cases better
            deactivationFailedEx.setIsPermanentFailure(true);
        // do not yet throw deactivationFailedEx as we need to nonetheless close the classloader
        }
        // (4) "close" m_componentClassLoader (otherwise JVM native mem leak, see COMP-4929)
        if (m_componentClassLoader instanceof AcsComponentClassLoader) {
            try {
                ((AcsComponentClassLoader) m_componentClassLoader).close();
            } catch (IOException ex) {
                m_containerLogger.log(Level.WARNING, "Failed to close component class loader", ex);
            }
        }
    } catch (RuntimeException ex) {
        if (deactivationFailedEx == null) {
            // exception from POA destruction has precedence
            deactivationFailedEx = new AcsJComponentDeactivationFailedEx(ex);
            deactivationFailedEx.setCURL(m_compInstanceName);
            deactivationFailedEx.setReason("Unexpected exception caught during component deactivation.");
        } else {
            m_containerLogger.log(Level.WARNING, "Unexpected exception caught during deactivation of component " + m_compInstanceName, ex);
        }
    }
    if (deactivationFailedEx != null) {
        if (m_containerLogger.isLoggable(Level.FINER)) {
            m_containerLogger.log(Level.FINER, "Deactivation of component " + m_compInstanceName + " failed. " + "Will throw AcsJComponentDeactivationFailedEx", deactivationFailedEx);
        }
        throw deactivationFailedEx;
    }
    if (deactivationUncleanEx != null) {
        if (m_containerLogger.isLoggable(Level.FINER)) {
            m_containerLogger.log(Level.FINER, "Deactivation of component " + m_compInstanceName + " finished with problems. " + "Will throw AcsJComponentDeactivationUncleanEx", deactivationUncleanEx);
        }
        throw deactivationUncleanEx;
    }
    if (m_containerLogger.isLoggable(Level.FINER)) {
        m_containerLogger.finer("Done deactivating component " + m_compInstanceName + " with handle " + getHandle());
    }
}
Also used : AcsJComponentDeactivationFailedEx(alma.maciErrType.wrappers.AcsJComponentDeactivationFailedEx) AcsJComponentDeactivationUncleanEx(alma.maciErrType.wrappers.AcsJComponentDeactivationUncleanEx) AcsComponentClassLoader(alma.acs.classloading.AcsComponentClassLoader) ComponentLifecycleException(alma.acs.component.ComponentLifecycleException) AcsComponentClassLoader(alma.acs.classloading.AcsComponentClassLoader) IOException(java.io.IOException)

Aggregations

AcsComponentClassLoader (alma.acs.classloading.AcsComponentClassLoader)1 ComponentLifecycleException (alma.acs.component.ComponentLifecycleException)1 AcsJComponentDeactivationFailedEx (alma.maciErrType.wrappers.AcsJComponentDeactivationFailedEx)1 AcsJComponentDeactivationUncleanEx (alma.maciErrType.wrappers.AcsJComponentDeactivationUncleanEx)1 IOException (java.io.IOException)1