/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.spring.extender.internal.context; import com.liferay.portal.bean.BeanLocatorImpl; import com.liferay.portal.kernel.bean.PortletBeanLocatorUtil; import com.liferay.portal.kernel.service.configuration.configurator.ServiceConfigurator; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.spring.bean.BeanReferenceRefreshUtil; import com.liferay.portal.spring.extender.internal.bean.ApplicationContextServicePublisher; import com.liferay.portal.spring.extender.internal.bundle.CompositeResourceLoaderBundle; import com.liferay.portal.spring.extender.internal.classloader.BundleResolverClassLoader; import com.liferay.portal.spring.extender.loader.ModuleResourceLoader; import java.beans.Introspector; import org.apache.felix.utils.log.Logger; import org.osgi.framework.Bundle; import org.osgi.framework.wiring.BundleWiring; import org.springframework.beans.CachedIntrospectionResults; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; /** * @author Miguel Pastor */ public class ModuleApplicationContextRegistrator { public ModuleApplicationContextRegistrator( Bundle extendeeBundle, Bundle extenderBundle, ServiceConfigurator serviceConfigurator) { _extendeeBundle = extendeeBundle; _extenderBundle = extenderBundle; _serviceConfigurator = serviceConfigurator; BundleWiring bundleWiring = _extendeeBundle.adapt(BundleWiring.class); _extendeeClassLoader = bundleWiring.getClassLoader(); _logger = new Logger(_extendeeBundle.getBundleContext()); } protected void start() throws Exception { try { ConfigurableApplicationContext configurableApplicationContext = _createApplicationContext(_extenderBundle, _extendeeBundle); _registerBeanLocator( _extendeeBundle, configurableApplicationContext); _refreshBeanFactory(configurableApplicationContext); _serviceConfigurator.initServices( new ModuleResourceLoader(_extendeeBundle), _extendeeClassLoader); _configurableApplicationContext = configurableApplicationContext; _applicationContextServicePublisher = new ApplicationContextServicePublisher( _configurableApplicationContext, _extendeeBundle.getBundleContext()); _applicationContextServicePublisher.register(); } catch (Exception e) { _logger.log( Logger.LOG_ERROR, "Unable to start " + _extendeeBundle.getSymbolicName(), e); throw e; } } protected void stop() throws Exception { _cleanInstropectionCaches(_extendeeBundle); _applicationContextServicePublisher.unregister(); PortletBeanLocatorUtil.setBeanLocator( _extendeeBundle.getSymbolicName(), null); _serviceConfigurator.destroyServices( new ModuleResourceLoader(_extendeeBundle), _extendeeClassLoader); _configurableApplicationContext.close(); _configurableApplicationContext = null; } private void _cleanInstropectionCaches(Bundle bundle) { BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); CachedIntrospectionResults.clearClassLoader( bundleWiring.getClassLoader()); Introspector.flushCaches(); } private ConfigurableApplicationContext _createApplicationContext( Bundle extender, Bundle extendee) throws RuntimeException { SpringContextHeaderParser springContextHeaderParser = new SpringContextHeaderParser(extendee); String[] beanDefinitionFileNames = springContextHeaderParser.getBeanDefinitionFileNames(); if (ArrayUtil.isEmpty(beanDefinitionFileNames)) { return null; } ClassLoader classLoader = new BundleResolverClassLoader( extendee, extender); Bundle compositeResourceLoaderBundle = new CompositeResourceLoaderBundle(extendee, extender); ModuleApplicationContext moduleApplicationContext = new ModuleApplicationContext( compositeResourceLoaderBundle, classLoader, beanDefinitionFileNames); moduleApplicationContext.addBeanFactoryPostProcessor( new ModuleBeanFactoryPostProcessor( classLoader, extendee.getBundleContext())); moduleApplicationContext.refresh(); return moduleApplicationContext; } private void _refreshBeanFactory(ApplicationContext applicationContext) { try { BeanReferenceRefreshUtil.refresh( applicationContext.getAutowireCapableBeanFactory()); } catch (Exception e) { _logger.log( Logger.LOG_ERROR, "Unable to refresh " + applicationContext.getDisplayName() + ". This may result in memory leaks on multiple " + "redeployments."); } } private void _registerBeanLocator( Bundle bundle, ApplicationContext applicationContext) { ClassLoader classLoader = new BundleResolverClassLoader(bundle); PortletBeanLocatorUtil.setBeanLocator( bundle.getSymbolicName(), new BeanLocatorImpl(classLoader, applicationContext)); } private ApplicationContextServicePublisher _applicationContextServicePublisher; private ConfigurableApplicationContext _configurableApplicationContext; private final Bundle _extendeeBundle; private final ClassLoader _extendeeClassLoader; private final Bundle _extenderBundle; private final Logger _logger; private final ServiceConfigurator _serviceConfigurator; }