/**
* 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.kernel.messaging.config;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.Destination;
import com.liferay.portal.kernel.messaging.DestinationConfiguration;
import com.liferay.portal.kernel.messaging.DestinationEventListener;
import com.liferay.portal.kernel.messaging.DestinationFactory;
import com.liferay.portal.kernel.messaging.DestinationFactoryUtil;
import com.liferay.portal.kernel.messaging.MessageBus;
import com.liferay.portal.kernel.messaging.MessageBusEventListener;
import com.liferay.portal.kernel.messaging.MessageListener;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.messaging.DestinationConfigurationProcessCallable;
import com.liferay.portal.kernel.nio.intraband.rpc.IntrabandRPCUtil;
import com.liferay.portal.kernel.resiliency.spi.SPI;
import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
import com.liferay.portal.kernel.security.pacl.permission.PortalMessageBusPermission;
import com.liferay.portal.kernel.util.ClassLoaderPool;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.registry.Filter;
import com.liferay.registry.Registry;
import com.liferay.registry.RegistryUtil;
import com.liferay.registry.ServiceRegistrar;
import com.liferay.registry.dependency.ServiceDependencyListener;
import com.liferay.registry.dependency.ServiceDependencyManager;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Michael C. Han
*/
public abstract class AbstractMessagingConfigurator
implements MessagingConfigurator {
public void afterPropertiesSet() {
final ServiceDependencyManager serviceDependencyManager =
new ServiceDependencyManager();
serviceDependencyManager.addServiceDependencyListener(
new ServiceDependencyListener() {
@Override
public void dependenciesFulfilled() {
Registry registry = RegistryUtil.getRegistry();
_messageBus = registry.getService(MessageBus.class);
initialize();
}
@Override
public void destroy() {
}
});
serviceDependencyManager.registerDependencies(
DestinationFactory.class, MessageBus.class);
}
@Override
public void connect() {
if (SPIUtil.isSPI() && _portalMessagingConfigurator) {
return;
}
Registry registry = RegistryUtil.getRegistry();
_messageListenerServiceRegistrar = registry.getServiceRegistrar(
MessageListener.class);
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
try {
ClassLoader operatingClassLoader = getOperatingClassloader();
currentThread.setContextClassLoader(operatingClassLoader);
for (Map.Entry<String, List<MessageListener>> messageListeners :
_messageListeners.entrySet()) {
String destinationName = messageListeners.getKey();
ServiceDependencyManager serviceDependencyManager =
new ServiceDependencyManager();
serviceDependencyManager.addServiceDependencyListener(
new DestinationServiceDependencyListener(
destinationName, messageListeners.getValue()));
Filter filter = registry.getFilter(
"(&(destination.name=" + destinationName +
")(objectClass=" + Destination.class.getName() + "))");
serviceDependencyManager.registerDependencies(filter);
}
}
finally {
currentThread.setContextClassLoader(contextClassLoader);
}
}
@Override
public void destroy() {
if (_messageListenerServiceRegistrar != null) {
_messageListenerServiceRegistrar.destroy();
}
if (_destinationEventListenerServiceRegistrar != null) {
_destinationEventListenerServiceRegistrar.destroy();
}
if (_destinationServiceRegistrar != null) {
_destinationServiceRegistrar.destroy();
}
if (_messageBusEventListenerServiceRegistrar != null) {
_messageBusEventListenerServiceRegistrar.destroy();
}
_destinationConfigurations.clear();
_destinationEventListeners.clear();
_messageListeners.clear();
for (Destination destination : _destinations) {
destination.destroy();
}
_destinations.clear();
_messageBusEventListeners.clear();
ClassLoader operatingClassLoader = getOperatingClassloader();
String servletContextName = ClassLoaderPool.getContextName(
operatingClassLoader);
MessagingConfiguratorRegistry.unregisterMessagingConfigurator(
servletContextName, this);
}
@Override
public void disconnect() {
if (SPIUtil.isSPI() && _portalMessagingConfigurator) {
return;
}
for (Map.Entry<String, List<MessageListener>> messageListeners :
_messageListeners.entrySet()) {
String destinationName = messageListeners.getKey();
for (MessageListener messageListener :
messageListeners.getValue()) {
_messageBus.unregisterMessageListener(
destinationName, messageListener);
}
}
}
@Override
public void setDestinationConfigurations(
Set<DestinationConfiguration> destinationConfigurations) {
_destinationConfigurations.addAll(destinationConfigurations);
}
@Override
public void setDestinationEventListeners(
Map<String, List<DestinationEventListener>> destinationEventListeners) {
_destinationEventListeners.putAll(destinationEventListeners);
}
@Override
public void setDestinations(List<Destination> destinations) {
_destinations.addAll(destinations);
}
@Override
public void setMessageBusEventListeners(
List<MessageBusEventListener> messageBusEventListeners) {
_messageBusEventListeners.addAll(messageBusEventListeners);
}
@Override
public void setMessageListeners(
Map<String, List<MessageListener>> messageListeners) {
for (List<MessageListener> messageListenersList :
messageListeners.values()) {
for (MessageListener messageListener : messageListenersList) {
Class<?> messageListenerClass = messageListener.getClass();
try {
Method setMessageBusMethod = messageListenerClass.getMethod(
"setMessageBus", MessageBus.class);
setMessageBusMethod.setAccessible(true);
setMessageBusMethod.invoke(messageListener, _messageBus);
continue;
}
catch (Exception e) {
}
try {
Method setMessageBusMethod =
messageListenerClass.getDeclaredMethod(
"setMessageBus", MessageBus.class);
setMessageBusMethod.setAccessible(true);
setMessageBusMethod.invoke(messageListener, _messageBus);
}
catch (Exception e) {
}
}
}
_messageListeners.putAll(messageListeners);
}
/**
* @param replacementDestinations
* @deprecated As of 7.0.0, replaced by {@link #setDestinations(List)}
*/
@Deprecated
@Override
public void setReplacementDestinations(
List<Destination> replacementDestinations) {
_destinations.addAll(replacementDestinations);
}
protected abstract ClassLoader getOperatingClassloader();
protected void initialize() {
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
ClassLoader operatingClassLoader = getOperatingClassloader();
if (contextClassLoader == operatingClassLoader) {
_portalMessagingConfigurator = true;
}
registerMessageBusEventListeners();
registerDestinations();
registerDestinationEventListeners();
connect();
String servletContextName = ClassLoaderPool.getContextName(
operatingClassLoader);
if ((servletContextName != null) &&
!servletContextName.equals(StringPool.NULL)) {
MessagingConfiguratorRegistry.registerMessagingConfigurator(
servletContextName, this);
}
}
protected void registerDestinationEventListeners() {
if (_destinationEventListeners.isEmpty()) {
return;
}
Registry registry = RegistryUtil.getRegistry();
_destinationEventListenerServiceRegistrar =
registry.getServiceRegistrar(DestinationEventListener.class);
for (final Map.Entry<String, List<DestinationEventListener>> entry :
_destinationEventListeners.entrySet()) {
final String destinationName = entry.getKey();
ServiceDependencyManager serviceDependencyManager =
new ServiceDependencyManager();
serviceDependencyManager.addServiceDependencyListener(
new ServiceDependencyListener() {
@Override
public void dependenciesFulfilled() {
Map<String, Object> properties = new HashMap<>();
properties.put("destination.name", destinationName);
for (DestinationEventListener destinationEventListener :
entry.getValue()) {
_destinationEventListenerServiceRegistrar.
registerService(
DestinationEventListener.class,
destinationEventListener, properties);
}
}
@Override
public void destroy() {
}
});
Filter filter = registry.getFilter(
"(&(destination.name=" + destinationName + ")(objectClass=" +
Destination.class.getName() + "))");
serviceDependencyManager.registerDependencies(filter);
}
}
protected void registerDestinations() {
for (DestinationConfiguration destinationConfiguration :
_destinationConfigurations) {
try {
PortalMessageBusPermission.checkListen(
destinationConfiguration.getDestinationName());
}
catch (SecurityException se) {
if (_log.isInfoEnabled()) {
_log.info(
"Rejecting destination " +
destinationConfiguration.getDestinationName());
}
continue;
}
_destinations.add(
DestinationFactoryUtil.createDestination(
destinationConfiguration));
}
if (_destinations.isEmpty()) {
return;
}
Registry registry = RegistryUtil.getRegistry();
_destinationServiceRegistrar = registry.getServiceRegistrar(
Destination.class);
for (Destination destination : _destinations) {
String destinationName = destination.getName();
try {
PortalMessageBusPermission.checkListen(destinationName);
}
catch (SecurityException se) {
if (_log.isInfoEnabled()) {
_log.info("Rejecting destination " + destinationName);
}
continue;
}
Map<String, Object> properties = new HashMap<>();
properties.put("destination.name", destinationName);
_destinationServiceRegistrar.registerService(
Destination.class, destination, properties);
}
}
protected void registerMessageBusEventListeners() {
if (_messageBusEventListeners.isEmpty()) {
return;
}
Registry registry = RegistryUtil.getRegistry();
_messageBusEventListenerServiceRegistrar = registry.getServiceRegistrar(
MessageBusEventListener.class);
for (MessageBusEventListener messageBusEventListener :
_messageBusEventListeners) {
_messageBusEventListenerServiceRegistrar.registerService(
MessageBusEventListener.class, messageBusEventListener);
}
}
private static final Log _log = LogFactoryUtil.getLog(
AbstractMessagingConfigurator.class);
private final Set<DestinationConfiguration> _destinationConfigurations =
new HashSet<>();
private final Map<String, List<DestinationEventListener>>
_destinationEventListeners = new HashMap<>();
private ServiceRegistrar<DestinationEventListener>
_destinationEventListenerServiceRegistrar;
private final List<Destination> _destinations = new ArrayList<>();
private ServiceRegistrar<Destination> _destinationServiceRegistrar;
private volatile MessageBus _messageBus;
private final List<MessageBusEventListener> _messageBusEventListeners =
new ArrayList<>();
private ServiceRegistrar<MessageBusEventListener>
_messageBusEventListenerServiceRegistrar;
private final Map<String, List<MessageListener>> _messageListeners =
new HashMap<>();
private ServiceRegistrar<MessageListener> _messageListenerServiceRegistrar;
private boolean _portalMessagingConfigurator;
private class DestinationServiceDependencyListener
implements ServiceDependencyListener {
public DestinationServiceDependencyListener(
String destinationName, List<MessageListener> messageListeners) {
_destinationName = destinationName;
_messageListeners = messageListeners;
}
@Override
public void dependenciesFulfilled() {
ClassLoader operatingClassLoader = getOperatingClassloader();
if (SPIUtil.isSPI()) {
SPI spi = SPIUtil.getSPI();
try {
RegistrationReference registrationReference =
spi.getRegistrationReference();
IntrabandRPCUtil.execute(
registrationReference,
new DestinationConfigurationProcessCallable(
_destinationName));
}
catch (Exception e) {
StringBundler sb = new StringBundler(4);
sb.append("Unable to install ");
sb.append(
DestinationConfigurationProcessCallable.class.
getName());
sb.append(" on MPI for ");
sb.append(_destinationName);
_log.error(sb.toString(), e);
}
}
Map<String, Object> properties = new HashMap<>();
properties.put("destination.name", _destinationName);
properties.put(
"message.listener.operating.class.loader",
operatingClassLoader);
for (MessageListener messageListener : _messageListeners) {
_messageListenerServiceRegistrar.registerService(
MessageListener.class, messageListener, properties);
}
}
@Override
public void destroy() {
}
private final String _destinationName;
private final List<MessageListener> _messageListeners;
}
}