/** * 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.resiliency.mpi; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.messaging.config.MessagingConfigurator; import com.liferay.portal.kernel.messaging.config.MessagingConfiguratorRegistry; import com.liferay.portal.kernel.nio.intraband.Intraband; import com.liferay.portal.kernel.nio.intraband.IntrabandFactoryUtil; import com.liferay.portal.kernel.nio.intraband.SystemDataType; import com.liferay.portal.kernel.nio.intraband.rpc.BootstrapRPCDatagramReceiveHandler; import com.liferay.portal.kernel.resiliency.spi.SPI; import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration; import com.liferay.portal.kernel.resiliency.spi.SPIRegistryUtil; import com.liferay.portal.kernel.resiliency.spi.provider.SPIProvider; import com.liferay.portal.kernel.util.CentralizedThreadLocal; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * @author Shuyang Zhou */ public class MPIHelperUtil { public static SPI checkSPILiveness(SPI spi) { boolean alive = false; try { alive = spi.isAlive(); } catch (RemoteException re) { _log.error(re); } if (alive) { return spi; } unregisterSPI(spi); return null; } public static Intraband getIntraband() { return _intraband; } public static MPI getMPI() { return _mpi; } public static SPI getSPI(String spiProviderName, String spiId) { SPIProviderContainer spiProviderContainer = _spiProviderContainers.get( spiProviderName); if (spiProviderContainer == null) { return null; } SPI spi = spiProviderContainer.getSPI(spiId); if (spi != null) { spi = checkSPILiveness(spi); } return spi; } public static SPIProvider getSPIProvider(String spiProviderName) { SPIProviderContainer spiProviderContainer = _spiProviderContainers.get( spiProviderName); if (spiProviderContainer == null) { return null; } return spiProviderContainer.getSPIProvider(); } public static List<SPIProvider> getSPIProviders() { List<SPIProvider> spiProviders = new ArrayList<>(); for (SPIProviderContainer spiProviderContainer : _spiProviderContainers.values()) { spiProviders.add(spiProviderContainer.getSPIProvider()); } return spiProviders; } public static List<SPI> getSPIs() { List<SPI> spis = new ArrayList<>(); for (SPIProviderContainer spiProviderContainer : _spiProviderContainers.values()) { for (SPI spi : spiProviderContainer.getSPIs()) { spi = checkSPILiveness(spi); if (spi != null) { spis.add(spi); } } } return spis; } public static List<SPI> getSPIs(String spiProviderName) { List<SPI> spis = new ArrayList<>(); SPIProviderContainer spiProviderContainer = _spiProviderContainers.get( spiProviderName); if (spiProviderContainer != null) { for (SPI spi : spiProviderContainer.getSPIs()) { spi = checkSPILiveness(spi); if (spi != null) { spis.add(spi); } } } return spis; } public static boolean registerSPI(SPI spi) { try { MPI mpi = spi.getMPI(); if (mpi != _mpi) { if (_log.isWarnEnabled()) { _log.warn( "Not registering SPI " + spi + " with foreign MPI " + mpi + " versus " + _mpi); } return false; } String spiProviderName = spi.getSPIProviderName(); SPIProviderContainer spiProviderContainer = _spiProviderContainers.get(spiProviderName); if (spiProviderContainer == null) { if (_log.isWarnEnabled()) { _log.warn( "Not registering SPI " + spi + " with unknown SPI provider " + spiProviderName); } return false; } SPIConfiguration spiConfiguration = spi.getSPIConfiguration(); SPI previousSPI = spiProviderContainer.putSPIIfAbsent( spiConfiguration.getSPIId(), spi); if (previousSPI != null) { if (_log.isWarnEnabled()) { _log.warn( "Not registering SPI " + spi + " because it duplicates " + previousSPI); } return false; } SPIRegistryUtil.registerSPI(spi); for (String servletContextName : spiConfiguration.getServletContextNames()) { List<MessagingConfigurator> messagingConfigurators = MessagingConfiguratorRegistry.getMessagingConfigurators( servletContextName); if (messagingConfigurators != null) { for (MessagingConfigurator messagingConfigurator : messagingConfigurators) { messagingConfigurator.disconnect(); } } } if (_log.isInfoEnabled()) { _log.info("Registered SPI " + spi); } return true; } catch (RemoteException re) { throw new RuntimeException(re); } } public static boolean registerSPIProvider(SPIProvider spiProvider) { String spiProviderName = spiProvider.getName(); SPIProviderContainer previousSPIProviderContainer = _spiProviderContainers.putIfAbsent( spiProviderName, new SPIProviderContainer(spiProvider)); if (previousSPIProviderContainer != null) { if (_log.isWarnEnabled()) { _log.warn( "Not registering SPI provider " + spiProvider + " because it duplicates " + previousSPIProviderContainer.getSPIProvider()); } return false; } if (_log.isInfoEnabled()) { _log.info("Registered SPI provider " + spiProvider); } return true; } public static void shutdown() { try { UnicastRemoteObject.unexportObject(_mpiImpl, true); } catch (NoSuchObjectException nsoe) { if (_log.isWarnEnabled()) { _log.warn("Unable to unexport " + _mpiImpl, nsoe); } } try { _intraband.close(); } catch (Exception e) { if (_log.isWarnEnabled()) { _log.warn("Unable to close intraband", e); } } } public static boolean unregisterSPI(SPI spi) { try { if (spi == _unregisteringSPIThreadLocal.get()) { _unregisterSPI(spi); return true; } MPI mpi = spi.getMPI(); if (mpi != _mpi) { if (_log.isWarnEnabled()) { _log.warn( "Not unregistering SPI " + spi + " with foreign MPI " + mpi + " versus " + _mpi); } return false; } String spiProviderName = spi.getSPIProviderName(); SPIProviderContainer spiProviderContainer = _spiProviderContainers.get(spiProviderName); if (spiProviderContainer == null) { if (_log.isWarnEnabled()) { _log.warn( "Not unregistering SPI " + spi + " with unknown SPI provider " + spiProviderName); } return false; } SPIConfiguration spiConfiguration = spi.getSPIConfiguration(); if (spiProviderContainer.removeSPI( spiConfiguration.getSPIId(), spi)) { _unregisterSPI(spi); return true; } if (_log.isWarnEnabled()) { _log.warn("Not unregistering unregistered SPI " + spi); } return false; } catch (RemoteException re) { throw new RuntimeException(re); } } public static boolean unregisterSPIProvider(SPIProvider spiProvider) { String spiProviderName = spiProvider.getName(); SPIProviderContainer spiProviderContainer = _spiProviderContainers.get( spiProviderName); if ((spiProviderContainer != null) && (spiProviderContainer.getSPIProvider() == spiProvider) && _spiProviderContainers.remove( spiProviderName, spiProviderContainer)) { Collection<SPI> spis = spiProviderContainer.getSPIs(); Iterator<SPI> iterator = spis.iterator(); while (iterator.hasNext()) { SPI spi = iterator.next(); iterator.remove(); _unregisteringSPIThreadLocal.set(spi); try { spi.stop(); spi.destroy(); if (_log.isInfoEnabled()) { _log.info( "Unregistered SPI " + spi + " while unregistering SPI provider " + spiProvider); } } catch (RemoteException re) { _log.error( "Unable to unregister SPI " + spi + " while unregistering SPI provider " + spiProvider, re); } finally { _unregisteringSPIThreadLocal.remove(); } } if (_log.isInfoEnabled()) { _log.info("Unregistered SPI provider " + spiProvider); } return true; } if (_log.isWarnEnabled()) { _log.warn( "Not unregistering unregistered SPI provider " + spiProvider); } return false; } private static void _unregisterSPI(SPI spi) throws RemoteException { SPIRegistryUtil.unregisterSPI(spi); SPIConfiguration spiConfiguration = spi.getSPIConfiguration(); for (String servletContextName : spiConfiguration.getServletContextNames()) { List<MessagingConfigurator> messagingConfigurators = MessagingConfiguratorRegistry.getMessagingConfigurators( servletContextName); if (messagingConfigurators == null) { continue; } for (MessagingConfigurator messagingConfigurator : messagingConfigurators) { messagingConfigurator.connect(); } } if (_log.isInfoEnabled()) { _log.info("Unregistered SPI " + spi); } } private static final Log _log = LogFactoryUtil.getLog(MPIHelperUtil.class); private static final Intraband _intraband; private static final MPI _mpi; private static final MPI _mpiImpl; private static final ConcurrentMap<String, SPIProviderContainer> _spiProviderContainers = new ConcurrentHashMap<>(); private static final ThreadLocal<SPI> _unregisteringSPIThreadLocal = new CentralizedThreadLocal<>(true); private static class MPIImpl implements MPI { @Override public boolean isAlive() { return true; } } private static class SPIProviderContainer { public SPIProviderContainer(SPIProvider spiProvider) { _spiProvider = spiProvider; } public SPI getSPI(String spiId) { return _spis.get(spiId); } public SPIProvider getSPIProvider() { return _spiProvider; } public Collection<SPI> getSPIs() { return _spis.values(); } public SPI putSPIIfAbsent(String spiId, SPI spi) { return _spis.putIfAbsent(spiId, spi); } public boolean removeSPI(String spiId, SPI spi) { return _spis.remove(spiId, spi); } private final SPIProvider _spiProvider; private final ConcurrentMap<String, SPI> _spis = new ConcurrentHashMap<>(); } static { // Keep strong reference to prevent garbage collection _mpiImpl = new MPIImpl(); try { if (PropsUtil.getProps() != null) { System.setProperty( PropsKeys.INTRABAND_IMPL, PropsUtil.get(PropsKeys.INTRABAND_IMPL)); System.setProperty( PropsKeys.INTRABAND_TIMEOUT_DEFAULT, PropsUtil.get(PropsKeys.INTRABAND_TIMEOUT_DEFAULT)); System.setProperty( PropsKeys.INTRABAND_WELDER_IMPL, PropsUtil.get(PropsKeys.INTRABAND_WELDER_IMPL)); } _intraband = IntrabandFactoryUtil.createIntraband(); _intraband.registerDatagramReceiveHandler( SystemDataType.RPC.getValue(), new BootstrapRPCDatagramReceiveHandler()); _mpi = (MPI)UnicastRemoteObject.exportObject(_mpiImpl, 0); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } }