/**
* 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.bean;
import com.liferay.portal.kernel.spring.osgi.OSGiBeanProperties;
import com.liferay.portal.kernel.util.HashMapDictionary;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.spring.aop.ServiceBeanAopProxy;
import com.liferay.portal.util.PropsValues;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.felix.utils.log.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.beans.factory.BeanIsAbstractException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
/**
* @author Miguel Pastor
*/
public class ApplicationContextServicePublisher {
public ApplicationContextServicePublisher(
ApplicationContext applicationContext, BundleContext bundleContext) {
_applicationContext = applicationContext;
_bundleContext = bundleContext;
_log = new Logger(bundleContext);
}
public void register() {
for (String beanName : _applicationContext.getBeanDefinitionNames()) {
Object bean = null;
try {
bean = _applicationContext.getBean(beanName);
}
catch (BeanIsAbstractException biae) {
}
catch (Exception e) {
_log.log(
Logger.LOG_ERROR, "Unable to register service " + beanName,
e);
}
if (bean != null) {
registerService(_bundleContext, bean);
}
}
Bundle bundle = _bundleContext.getBundle();
registerApplicationContext(
_applicationContext, bundle.getSymbolicName());
}
public void unregister() {
for (ServiceRegistration<?> serviceReference : _serviceRegistrations) {
serviceReference.unregister();
}
_serviceRegistrations.clear();
}
protected Dictionary<String, Object> getBeanProperties(
String symbloicName, Object object) {
HashMapDictionary<String, Object> properties =
new HashMapDictionary<>();
properties.put("origin.bundle.symbolic.name", symbloicName);
Class<? extends Object> clazz = null;
try {
clazz = getTargetClass(object);
}
catch (Exception e) {
return properties;
}
OSGiBeanProperties osgiBeanProperties = AnnotationUtils.findAnnotation(
clazz, OSGiBeanProperties.class);
if (osgiBeanProperties == null) {
return properties;
}
properties.putAll(OSGiBeanProperties.Convert.toMap(osgiBeanProperties));
return properties;
}
protected Set<Class<?>> getInterfaces(Object object) throws Exception {
Class<? extends Object> clazz = getTargetClass(object);
OSGiBeanProperties osgiBeanProperties = AnnotationUtils.findAnnotation(
clazz, OSGiBeanProperties.class);
if (osgiBeanProperties == null) {
return new HashSet<>(
Arrays.asList(ReflectionUtil.getInterfaces(object)));
}
Class<?>[] serviceClasses = osgiBeanProperties.service();
if (serviceClasses.length == 0) {
return new HashSet<>(
Arrays.asList(ReflectionUtil.getInterfaces(object)));
}
for (Class<?> serviceClazz : serviceClasses) {
serviceClazz.cast(object);
}
return new HashSet<>(Arrays.asList(osgiBeanProperties.service()));
}
protected Class<?> getTargetClass(Object service) throws Exception {
Class<?> clazz = service.getClass();
if (ProxyUtil.isProxyClass(clazz)) {
AdvisedSupport advisedSupport =
ServiceBeanAopProxy.getAdvisedSupport(service);
TargetSource targetSource = advisedSupport.getTargetSource();
Object target = targetSource.getTarget();
clazz = target.getClass();
}
return clazz;
}
protected boolean isIgnoredInterface(String interfaceClassName) {
for (String ignoredInterfaceClassName :
PropsValues.MODULE_FRAMEWORK_SERVICES_IGNORED_INTERFACES) {
if (!ignoredInterfaceClassName.startsWith(StringPool.EXCLAMATION) &&
(ignoredInterfaceClassName.equals(interfaceClassName) ||
(ignoredInterfaceClassName.endsWith(StringPool.STAR) &&
interfaceClassName.startsWith(
ignoredInterfaceClassName.substring(
0, ignoredInterfaceClassName.length() - 1))))) {
return true;
}
}
return false;
}
protected void registerApplicationContext(
ApplicationContext applicationContext, String bundleSymbolicName) {
HashMapDictionary<String, Object> properties =
new HashMapDictionary<>();
properties.put(
"org.springframework.context.service.name", bundleSymbolicName);
registerService(
_bundleContext, applicationContext,
Arrays.asList(ApplicationContext.class.getName()), properties);
}
protected void registerService(BundleContext bundleContext, Object bean) {
Set<Class<?>> interfaces = null;
try {
interfaces = getInterfaces(bean);
}
catch (Exception e) {
_log.log(Logger.LOG_ERROR, "Unable to register service " + bean, e);
}
interfaces.add(bean.getClass());
List<String> names = new ArrayList<>(interfaces.size());
for (Class<?> interfaceClass : interfaces) {
String interfaceClassName = interfaceClass.getName();
if (!isIgnoredInterface(interfaceClassName)) {
names.add(interfaceClassName);
}
}
if (names.isEmpty()) {
_log.log(
Logger.LOG_DEBUG,
"Skipping registration because of an empty list of interfaces");
return;
}
Bundle bundle = bundleContext.getBundle();
registerService(
bundleContext, bean, names,
getBeanProperties(bundle.getSymbolicName(), bean));
}
protected void registerService(
BundleContext bundleContext, Object bean, List<String> interfaces,
Dictionary<String, Object> properties) {
ServiceRegistration<?> serviceRegistration =
bundleContext.registerService(
interfaces.toArray(new String[interfaces.size()]), bean,
properties);
_serviceRegistrations.add(serviceRegistration);
}
private final ApplicationContext _applicationContext;
private final BundleContext _bundleContext;
private final Logger _log;
private final Set<ServiceRegistration<?>> _serviceRegistrations =
new HashSet<>();
}