Package org.springframework.osgi.context.support

Source Code of org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext$NoDependenciesWaitRefreshExecutor

/*
* Copyright 2006-2008 the original author or authors.
*
* Licensed 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.springframework.osgi.context.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
import org.springframework.osgi.context.OsgiBundleApplicationContextExecutor;
import org.springframework.osgi.context.event.OsgiBundleApplicationContextEventMulticaster;
import org.springframework.osgi.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;
import org.springframework.osgi.context.event.OsgiBundleContextFailedEvent;
import org.springframework.osgi.context.event.OsgiBundleContextRefreshedEvent;
import org.springframework.osgi.util.OsgiBundleUtils;
import org.springframework.osgi.util.OsgiStringUtils;
import org.springframework.osgi.util.internal.ClassUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
* OSGi-specific application context that delegates the execution of its life
* cycle methods to a different class. The main reason behind this is to
* <em>break</em> the startup of the application context in steps that can be
* executed asynchronously.
*
* <p/> The {@link #refresh()} and {@link #close()} methods delegate their
* execution to an {@link OsgiBundleApplicationContextExecutor} class that
* chooses how to call the lifecycle methods.
*
* <p/> One can still call the 'traditional' lifecycle methods through
* {@link #normalRefresh()} and {@link #normalClose()}.
*
* @see DelegatedExecutionOsgiBundleApplicationContext
*
* @author Costin Leau
*/
public abstract class AbstractDelegatedExecutionApplicationContext extends AbstractOsgiBundleApplicationContext
    implements DelegatedExecutionOsgiBundleApplicationContext {

  /**
   * Executor that offers the traditional way of <code>refreshing</code>/<code>closing</code>
   * of an ApplicationContext (no conditions have to be met and the refresh
   * happens in only one step).
   *
   * @author Costin Leau
   */
  private static class NoDependenciesWaitRefreshExecutor implements OsgiBundleApplicationContextExecutor {

    private final DelegatedExecutionOsgiBundleApplicationContext context;


    private NoDependenciesWaitRefreshExecutor(DelegatedExecutionOsgiBundleApplicationContext ctx) {
      context = ctx;
    }

    public void refresh() throws BeansException, IllegalStateException {
      context.normalRefresh();
    }

    public void close() {
      context.normalClose();
    }
  }


  /** Default executor */
  private OsgiBundleApplicationContextExecutor executor = new NoDependenciesWaitRefreshExecutor(this);

  /** this context monitor */
  private final Object contextMonitor = new Object();

  /** monitor for available flag */
  private final Object availableMonitor = new Object();

  private boolean available = false;

  /** delegated multicaster */
  private OsgiBundleApplicationContextEventMulticaster delegatedMulticaster;

  private ContextClassLoaderProvider cclProvider;


  /**
   *
   * Create a new AbstractDelegatedExecutionApplicationContext with no parent.
   *
   */
  public AbstractDelegatedExecutionApplicationContext() {
    super();
  }

  /**
   * Create a new AbstractDelegatedExecutionApplicationContext with the given
   * parent context.
   *
   * @param parent the parent context
   */
  public AbstractDelegatedExecutionApplicationContext(ApplicationContext parent) {
    super(parent);
  }

  boolean isAvailable() {
    synchronized (availableMonitor) {
      return available;
    }
  }

  /**
   * Delegate execution of refresh method to a third party. This allows
   * breaking the refresh process into several small pieces providing
   * continuation-like behavior or completion of the refresh method on several
   * threads, in a asynch manner.
   *
   * By default, the refresh method in executed in <em>one go</em> (normal
   * behavior).
   *
   * {@inheritDoc}
   */
  public void refresh() throws BeansException, IllegalStateException {
    executor.refresh();
  }

  public void normalRefresh() {
    Assert.notNull(getBundleContext(), "bundle context should be set before refreshing the application context");

    Thread currentThread = Thread.currentThread();
    ClassLoader oldTCCL = currentThread.getContextClassLoader();

    try {
      currentThread.setContextClassLoader(contextClassLoaderProvider().getContextClassLoader());
      try {
        super.refresh();
        sendRefreshedEvent();
      }
      catch (Throwable th) {
        logger.error("Refresh error", th);
        sendFailedEvent(th);
        // propagate exception to the caller
        // rethrow the problem w/o rewrapping
        if (th instanceof RuntimeException) {
          throw (RuntimeException) th;
        }
        else {
          throw (Error) th;
        }
      }
    }
    finally {
      currentThread.setContextClassLoader(oldTCCL);
    }
  }

  public void normalClose() {
    Thread currentThread = Thread.currentThread();
    ClassLoader oldTCCL = currentThread.getContextClassLoader();

    try {
      currentThread.setContextClassLoader(contextClassLoaderProvider().getContextClassLoader());
      super.doClose();
    }
    finally {
      currentThread.setContextClassLoader(oldTCCL);
    }
  }

  // Adds behaviour for isAvailable flag.
  protected void doClose() {
    synchronized (availableMonitor) {
      available = false;
    }
    executor.close();
  }

  public void startRefresh() {

    // check concurrent collection (which are mandatory)
    if (!ClassUtils.concurrentLibAvailable())
      throw new IllegalStateException(
        "JVM 5+ or backport-concurrent library (for JVM 1.4) required; see the FAQ for more details");

    Thread thread = Thread.currentThread();
    ClassLoader oldTCCL = thread.getContextClassLoader();

    try {
      synchronized (contextMonitor) {
        thread.setContextClassLoader(contextClassLoaderProvider().getContextClassLoader());

        if (ObjectUtils.isEmpty(getConfigLocations())) {
          setConfigLocations(getDefaultConfigLocations());
        }
        if (!OsgiBundleUtils.isBundleActive(getBundle())) {
          throw new ApplicationContextException("Unable to refresh application context: bundle is "
              + OsgiStringUtils.bundleStateAsString(getBundle()));
        }

        ConfigurableListableBeanFactory beanFactory = null;
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
          // Allows post-processing of the bean factory in context
          // subclasses.
          postProcessBeanFactory(beanFactory);

          // Invoke factory processors registered as beans in the
          // context.
          invokeBeanFactoryPostProcessors(beanFactory);

          // Register bean processors that intercept bean creation.
          registerBeanPostProcessors(beanFactory);

        }
        catch (BeansException ex) {
          // Destroy already created singletons to avoid dangling
          // resources.
          beanFactory.destroySingletons();
          cancelRefresh(ex);
          // propagate exception to the caller
          throw ex;
        }
      }
    }
    catch (Throwable th) {
      logger.error("Pre refresh error", th);
      // send failure event
      sendFailedEvent(th);
      // rethrow the problem w/o rewrapping
      if (th instanceof RuntimeException) {
        throw (RuntimeException) th;
      }
      else {
        throw (Error) th;
      }
    }
    finally {
      thread.setContextClassLoader(oldTCCL);
    }
  }

  public void completeRefresh() {
    Thread thread = Thread.currentThread();
    ClassLoader oldTCCL = thread.getContextClassLoader();

    try {

      synchronized (contextMonitor) {
        thread.setContextClassLoader(contextClassLoaderProvider().getContextClassLoader());

        try {
          ConfigurableListableBeanFactory beanFactory = getBeanFactory();

          // Initialize message source for this context.
          initMessageSource();

          // Initialize event multicaster for this context.
          initApplicationEventMulticaster();

          // Initialize other special beans in specific context
          // subclasses.
          onRefresh();

          // Check for listener beans and register them.
          registerListeners();

          // Instantiate all remaining (non-lazy-init) singletons.
          finishBeanFactoryInitialization(beanFactory);

          // Last step: publish corresponding event.
          finishRefresh();

          // everything went okay, post notification
          sendRefreshedEvent();
        }
        catch (BeansException ex) {
          // Destroy already created singletons to avoid dangling
          // resources.
          getBeanFactory().destroySingletons();
          cancelRefresh(ex);
          // propagate exception to the caller
          throw ex;
        }
      }
    }
    catch (Throwable th) {
      logger.error("Post refresh error", th);
      // post notification
      sendFailedEvent(th);
      // rethrow the problem w/o rewrapping
      if (th instanceof RuntimeException) {
        throw (RuntimeException) th;
      }
      else {
        throw (Error) th;
      }
    }
    finally {
      thread.setContextClassLoader(oldTCCL);
    }
  }

  protected void finishRefresh() {
    super.finishRefresh();

    synchronized (availableMonitor) {
      available = true;
    }
    // publish the context only after all the beans have been published
    publishContextAsOsgiServiceIfNecessary();
  }

  public Object getMonitor() {
    return contextMonitor;
  }

  public void setExecutor(OsgiBundleApplicationContextExecutor executor) {
    this.executor = executor;
  }

  public void setDelegatedEventMulticaster(OsgiBundleApplicationContextEventMulticaster multicaster) {
    this.delegatedMulticaster = multicaster;
  }

  /**
   * Sets the OSGi multicaster by using a Spring
   * {@link ApplicationEventMulticaster}. This method is added as a
   * covenience.
   *
   * @param multicaster Spring multi-caster used for propagating OSGi specific
   * events
   *
   * @see OsgiBundleApplicationContextEventMulticasterAdapter
   */
  public void setDelegatedEventMulticaster(ApplicationEventMulticaster multicaster) {
    this.delegatedMulticaster = new OsgiBundleApplicationContextEventMulticasterAdapter(multicaster);
  }

  public OsgiBundleApplicationContextEventMulticaster getDelegatedEventMulticaster() {
    return this.delegatedMulticaster;
  }

  private void sendFailedEvent(Throwable cause) {
    if (delegatedMulticaster != null)
      delegatedMulticaster.multicastEvent(new OsgiBundleContextFailedEvent(this, this.getBundle(), cause));
  }

  private void sendRefreshedEvent() {
    if (delegatedMulticaster != null)
      delegatedMulticaster.multicastEvent(new OsgiBundleContextRefreshedEvent(this, this.getBundle()));
  }

  /**
   * Returns the context class loader to be used as the Thread Context Class
   * Loader for {@link #refresh()} and {@link #destroy()} calls.
   *
   * The default implementation returns the bean class loader if it is set or
   * or the current context class loader otherwise.
   *
   * @return the thread context class loader to be used during the execution
   * of critical section blocks
   * @deprecated will be removed after RC1 is released
   */
  protected ClassLoader getContextClassLoader() {
    return contextClassLoaderProvider().getContextClassLoader();
  }

  /** private method used for doing lazy-init-if-not-set for cclProvider */
  private ContextClassLoaderProvider contextClassLoaderProvider() {
    if (cclProvider == null) {
      DefaultContextClassLoaderProvider defaultProvider = new DefaultContextClassLoaderProvider();
      defaultProvider.setBeanClassLoader(getClassLoader());
      cclProvider = defaultProvider;
    }
    return cclProvider;
  }

  /**
   * Sets the {@link ContextClassLoaderProvider} used by this OSGi application
   * context instance. By default, {@link DefaultContextClassLoaderProvider}
   * is used.
   *
   * @param contextClassLoaderProvider context class loader provider to use
   * @see ContextClassLoaderProvider
   * @see DefaultContextClassLoaderProvider
   */
  public void setContextClassLoaderProvider(ContextClassLoaderProvider contextClassLoaderProvider) {
    this.cclProvider = contextClassLoaderProvider;
  }
}
TOP

Related Classes of org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext$NoDependenciesWaitRefreshExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.