/**
   * {@inheritDoc}
   *
   * <p>Cleanup the configuration items.
   */
  public void destroy() {

    synchronized (lock) {
      if (isMulticasterManagedInternally) {
        eventMulticaster.removeAllListeners();
        eventMulticaster = null;
      }

      if (extenderConfiguration != null) {
        extenderConfiguration.close();
        extenderConfiguration = null;
      }

      // postpone the task executor shutdown
      if (forceThreadShutdown) {

        if (isTaskExecutorManagedInternally) {
          log.warn("Forcing the (internally created) taskExecutor to stop...");
          ThreadGroup th = ((SimpleAsyncTaskExecutor) taskExecutor).getThreadGroup();
          if (!th.isDestroyed()) {
            // ask the threads nicely to stop
            th.interrupt();
          }
        }
        taskExecutor = null;
      }

      if (isShutdownTaskExecutorManagedInternally) {
        try {
          ((DisposableBean) shutdownTaskExecutor).destroy();
        } catch (Exception ex) {
          log.debug("Received exception while shutting down shutdown task executor", ex);
        }
        shutdownTaskExecutor = null;
      }
    }
  }
  /**
   * Constructs a new <code>ExtenderConfiguration</code> instance. Locates the extender
   * configuration, creates an application context which will returned the extender items.
   *
   * @param bundleContext extender OSGi bundle context
   */
  public ExtenderConfiguration(BundleContext bundleContext, Log log) {
    this.log = log;
    Bundle bundle = bundleContext.getBundle();
    Properties properties = new Properties(createDefaultProperties());

    Enumeration<?> enm = bundle.findEntries(EXTENDER_CFG_LOCATION, XML_PATTERN, false);

    if (enm == null) {
      log.info("No custom extender configuration detected; using defaults...");

      synchronized (lock) {
        taskExecutor = createDefaultTaskExecutor();
        shutdownTaskExecutor = createDefaultShutdownTaskExecutor();
        eventMulticaster = createDefaultEventMulticaster();
        contextCreator = createDefaultApplicationContextCreator();
        contextEventListener = createDefaultApplicationContextListener();
      }
      classLoader = BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle);
    } else {
      String[] configs = copyEnumerationToList(enm);

      log.info(
          "Detected extender custom configurations at " + ObjectUtils.nullSafeToString(configs));
      // create OSGi specific XML context
      ConfigurableOsgiBundleApplicationContext extenderAppCtx =
          new OsgiBundleXmlApplicationContext(configs);
      extenderAppCtx.setBundleContext(bundleContext);
      extenderAppCtx.refresh();

      synchronized (lock) {
        extenderConfiguration = extenderAppCtx;
        // initialize beans
        taskExecutor =
            extenderConfiguration.containsBean(TASK_EXECUTOR_NAME)
                ? (TaskExecutor)
                    extenderConfiguration.getBean(TASK_EXECUTOR_NAME, TaskExecutor.class)
                : createDefaultTaskExecutor();

        shutdownTaskExecutor =
            extenderConfiguration.containsBean(SHUTDOWN_TASK_EXECUTOR_NAME)
                ? (TaskExecutor)
                    extenderConfiguration.getBean(SHUTDOWN_TASK_EXECUTOR_NAME, TaskExecutor.class)
                : createDefaultShutdownTaskExecutor();

        eventMulticaster =
            extenderConfiguration.containsBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
                ? (OsgiBundleApplicationContextEventMulticaster)
                    extenderConfiguration.getBean(
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
                        OsgiBundleApplicationContextEventMulticaster.class)
                : createDefaultEventMulticaster();

        contextCreator =
            extenderConfiguration.containsBean(CONTEXT_CREATOR_NAME)
                ? (OsgiApplicationContextCreator)
                    extenderConfiguration.getBean(
                        CONTEXT_CREATOR_NAME, OsgiApplicationContextCreator.class)
                : createDefaultApplicationContextCreator();

        contextEventListener =
            extenderConfiguration.containsBean(CONTEXT_LISTENER_NAME)
                ? (OsgiBundleApplicationContextListener)
                    extenderConfiguration.getBean(
                        CONTEXT_LISTENER_NAME, OsgiBundleApplicationContextListener.class)
                : createDefaultApplicationContextListener();
      }

      // get post processors
      postProcessors.addAll(
          extenderConfiguration.getBeansOfType(OsgiBeanFactoryPostProcessor.class).values());

      // get dependency factories
      dependencyFactories.addAll(
          extenderConfiguration.getBeansOfType(OsgiServiceDependencyFactory.class).values());

      classLoader = extenderConfiguration.getClassLoader();
      // extender properties using the defaults as backup
      if (extenderConfiguration.containsBean(PROPERTIES_NAME)) {
        Properties customProperties =
            (Properties) extenderConfiguration.getBean(PROPERTIES_NAME, Properties.class);
        Enumeration<?> propertyKey = customProperties.propertyNames();
        while (propertyKey.hasMoreElements()) {
          String property = (String) propertyKey.nextElement();
          properties.setProperty(property, customProperties.getProperty(property));
        }
      }
    }

    synchronized (lock) {
      shutdownWaitTime = getShutdownWaitTime(properties);
      dependencyWaitTime = getDependencyWaitTime(properties);
      processAnnotation = getProcessAnnotations(properties);
    }

    // load default dependency factories
    addDefaultDependencyFactories();

    // allow post processing
    contextCreator = postProcess(contextCreator);
  }