001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.resiliency.mpi;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.messaging.config.MessagingConfigurator;
020    import com.liferay.portal.kernel.messaging.config.MessagingConfiguratorRegistry;
021    import com.liferay.portal.kernel.nio.intraband.Intraband;
022    import com.liferay.portal.kernel.nio.intraband.IntrabandFactoryUtil;
023    import com.liferay.portal.kernel.resiliency.spi.SPI;
024    import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
025    import com.liferay.portal.kernel.resiliency.spi.SPIRegistryUtil;
026    import com.liferay.portal.kernel.resiliency.spi.provider.SPIProvider;
027    import com.liferay.portal.kernel.util.PropsKeys;
028    import com.liferay.portal.kernel.util.PropsUtil;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.Validator;
031    
032    import java.rmi.NoSuchObjectException;
033    import java.rmi.RemoteException;
034    import java.rmi.server.UnicastRemoteObject;
035    
036    import java.util.ArrayList;
037    import java.util.List;
038    import java.util.Map;
039    import java.util.concurrent.ConcurrentHashMap;
040    import java.util.concurrent.ConcurrentMap;
041    import java.util.concurrent.locks.Lock;
042    import java.util.concurrent.locks.ReentrantLock;
043    
044    /**
045     * @author Shuyang Zhou
046     */
047    public class MPIHelperUtil {
048    
049            public static Intraband getIntraband() {
050                    return _intraband;
051            }
052    
053            public static MPI getMPI() {
054                    return _mpi;
055            }
056    
057            public static SPI getSPI(String spiProviderName, String spiId) {
058                    SPIKey spiKey = new SPIKey(spiProviderName, spiId);
059    
060                    SPI spi = _spis.get(spiKey);
061    
062                    if (spi != null) {
063                            spi = _checkSPILiveness(spi);
064                    }
065    
066                    return spi;
067            }
068    
069            public static SPIProvider getSPIProvider(String spiProviderName) {
070                    return _spiProviders.get(spiProviderName);
071            }
072    
073            public static List<SPIProvider> getSPIProviders() {
074                    return new ArrayList<SPIProvider>(_spiProviders.values());
075            }
076    
077            public static List<SPI> getSPIs() {
078                    List<SPI> spis = new ArrayList<SPI>();
079    
080                    for (SPI spi : _spis.values()) {
081                            spi = _checkSPILiveness(spi);
082    
083                            if (spi != null) {
084                                    spis.add(spi);
085                            }
086                    }
087    
088                    return spis;
089            }
090    
091            public static List<SPI> getSPIs(String spiProviderName) {
092                    List<SPI> spis = new ArrayList<SPI>();
093    
094                    for (Map.Entry<SPIKey, SPI> entry : _spis.entrySet()) {
095                            SPIKey spiKey = entry.getKey();
096    
097                            if (!spiProviderName.equals(spiKey._spiProviderName)) {
098                                    continue;
099                            }
100    
101                            SPI spi = entry.getValue();
102    
103                            spi = _checkSPILiveness(spi);
104    
105                            if (spi != null) {
106                                    spis.add(spi);
107                            }
108                    }
109    
110                    return spis;
111            }
112    
113            public static boolean registerSPI(SPI spi) {
114                    _lock.lock();
115    
116                    try {
117                            MPI mpi = spi.getMPI();
118    
119                            if (mpi != _mpi) {
120                                    if (_log.isWarnEnabled()) {
121                                            _log.warn(
122                                                    "Not registering SPI " + spi + " with foreign MPI " +
123                                                            mpi + " versus " + _mpi);
124                                    }
125    
126                                    return false;
127                            }
128    
129                            String spiProviderName = spi.getSPIProviderName();
130    
131                            SPIProvider spiProvider = _spiProviders.get(spiProviderName);
132    
133                            if (spiProvider == null) {
134                                    if (_log.isWarnEnabled()) {
135                                            _log.warn(
136                                                    "Not registering SPI " + spi +
137                                                            " with unknown SPI provider " + spiProviderName);
138                                    }
139    
140                                    return false;
141                            }
142    
143                            SPIConfiguration spiConfiguration = spi.getSPIConfiguration();
144    
145                            SPIKey spiKey = new SPIKey(
146                                    spiProviderName, spiConfiguration.getSPIId());
147    
148                            SPI previousSPI = _spis.putIfAbsent(spiKey, spi);
149    
150                            if (previousSPI != null) {
151                                    if (_log.isWarnEnabled()) {
152                                            _log.warn(
153                                                    "Not registering SPI " + spi +
154                                                            " because it duplicates " + previousSPI);
155                                    }
156    
157                                    return false;
158                            }
159    
160                            SPIRegistryUtil.registerSPI(spi);
161    
162                            for (String servletContextName :
163                                            spiConfiguration.getServletContextNames()) {
164    
165                                    List<MessagingConfigurator> messagingConfigurators =
166                                            MessagingConfiguratorRegistry.getMessagingConfigurators(
167                                                    servletContextName);
168    
169                                    if (messagingConfigurators != null) {
170                                            for (MessagingConfigurator messagingConfigurator :
171                                                            messagingConfigurators) {
172    
173                                                    messagingConfigurator.disconnect();
174                                            }
175                                    }
176                            }
177    
178                            if (_log.isInfoEnabled()) {
179                                    _log.info("Registered SPI " + spi);
180                            }
181    
182                            return true;
183                    }
184                    catch (RemoteException re) {
185                            throw new RuntimeException(re);
186                    }
187                    finally {
188                            _lock.unlock();
189                    }
190            }
191    
192            public static boolean registerSPIProvider(SPIProvider spiProvider) {
193                    String spiProviderName = spiProvider.getName();
194    
195                    SPIProvider previousSPIProvider = null;
196    
197                    _lock.lock();
198    
199                    try {
200                            previousSPIProvider = _spiProviders.putIfAbsent(
201                                    spiProviderName, spiProvider);
202                    }
203                    finally {
204                            _lock.unlock();
205                    }
206    
207                    if (previousSPIProvider != null) {
208                            if (_log.isWarnEnabled()) {
209                                    _log.warn(
210                                            "Not registering SPI provider " + spiProvider +
211                                                    " because it duplicates " + previousSPIProvider);
212                            }
213    
214                            return false;
215                    }
216    
217                    if (_log.isInfoEnabled()) {
218                            _log.info("Registered SPI provider " + spiProvider);
219                    }
220    
221                    return true;
222            }
223    
224            public static void shutdown() {
225                    try {
226                            UnicastRemoteObject.unexportObject(_mpiImpl, true);
227                    }
228                    catch (NoSuchObjectException nsoe) {
229                            if (_log.isWarnEnabled()) {
230                                    _log.warn("Unable to unexport " + _mpiImpl, nsoe);
231                            }
232                    }
233            }
234    
235            public static boolean unregisterSPI(SPI spi) {
236                    _lock.lock();
237    
238                    try {
239                            MPI mpi = spi.getMPI();
240    
241                            if (mpi != _mpi) {
242                                    if (_log.isWarnEnabled()) {
243                                            _log.warn(
244                                                    "Not unregistering SPI " + spi + " with foreign MPI " +
245                                                            mpi + " versus " + _mpi);
246                                    }
247    
248                                    return false;
249                            }
250    
251                            String spiProviderName = spi.getSPIProviderName();
252    
253                            SPIProvider spiProvider = _spiProviders.get(spiProviderName);
254    
255                            if (spiProvider == null) {
256                                    if (_log.isWarnEnabled()) {
257                                            _log.warn(
258                                                    "Not unregistering SPI " + spi +
259                                                            " with unknown SPI provider " + spiProviderName);
260                                    }
261    
262                                    return false;
263                            }
264    
265                            SPIConfiguration spiConfiguration = spi.getSPIConfiguration();
266    
267                            String spiId = spiConfiguration.getSPIId();
268    
269                            SPIKey spiKey = new SPIKey(spiProviderName, spiId);
270    
271                            if (_spis.remove(spiKey, spi)) {
272                                    SPIRegistryUtil.unregisterSPI(spi);
273    
274                                    for (String servletContextName :
275                                                    spiConfiguration.getServletContextNames()) {
276    
277                                            List<MessagingConfigurator> messagingConfigurators =
278                                                    MessagingConfiguratorRegistry.getMessagingConfigurators(
279                                                            servletContextName);
280    
281                                            if (messagingConfigurators != null) {
282                                                    for (MessagingConfigurator messagingConfigurator :
283                                                                    messagingConfigurators) {
284    
285                                                            messagingConfigurator.connect();
286                                                    }
287                                            }
288                                    }
289    
290                                    if (_log.isInfoEnabled()) {
291                                            _log.info("Unregistered SPI " + spi);
292                                    }
293    
294                                    return true;
295                            }
296    
297                            if (_log.isWarnEnabled()) {
298                                    _log.warn("Not unregistering unregistered SPI " + spi);
299                            }
300    
301                            return false;
302                    }
303                    catch (RemoteException re) {
304                            throw new RuntimeException(re);
305                    }
306                    finally {
307                            _lock.unlock();
308                    }
309            }
310    
311            public static boolean unregisterSPIProvider(SPIProvider spiProvider) {
312                    _lock.lock();
313    
314                    try {
315                            String spiProviderName = spiProvider.getName();
316    
317                            if (_spiProviders.remove(spiProviderName, spiProvider)) {
318                                    for (Map.Entry<SPIKey, SPI> entry : _spis.entrySet()) {
319                                            SPIKey spiKey = entry.getKey();
320    
321                                            if (!spiProviderName.equals(spiKey._spiProviderName)) {
322                                                    continue;
323                                            }
324    
325                                            SPI spi = entry.getValue();
326    
327                                            try {
328                                                    spi.destroy();
329    
330                                                    if (_log.isInfoEnabled()) {
331                                                            _log.info(
332                                                                    "Unregistered SPI " + spi +
333                                                                            " while unregistering SPI provider " +
334                                                                                    spiProvider);
335                                                    }
336                                            }
337                                            catch (RemoteException re) {
338                                                    _log.error(
339                                                            "Unable to unregister SPI " + spi +
340                                                                    " while unregistering SPI provider " +
341                                                                            spiProvider,
342                                                            re);
343                                            }
344                                    }
345    
346                                    if (_log.isInfoEnabled()) {
347                                            _log.info("Unregistered SPI provider " + spiProvider);
348                                    }
349    
350                                    return true;
351                            }
352    
353                            if (_log.isWarnEnabled()) {
354                                    _log.warn(
355                                            "Not unregistering unregistered SPI provider " +
356                                                    spiProvider);
357                            }
358    
359                            return false;
360                    }
361                    finally {
362                            _lock.unlock();
363                    }
364            }
365    
366            private static SPI _checkSPILiveness(SPI spi) {
367                    boolean alive = false;
368    
369                    try {
370                            alive = spi.isAlive();
371                    }
372                    catch (RemoteException re) {
373                            _log.error(re);
374                    }
375    
376                    if (alive) {
377                            return spi;
378                    }
379    
380                    unregisterSPI(spi);
381    
382                    return null;
383            }
384    
385            private static Log _log = LogFactoryUtil.getLog(MPIHelperUtil.class);
386    
387            private static Intraband _intraband;
388            private static Lock _lock = new ReentrantLock();
389            private static MPI _mpi;
390            private static MPI _mpiImpl;
391            private static ConcurrentMap<String, SPIProvider> _spiProviders =
392                    new ConcurrentHashMap<String, SPIProvider>();
393            private static ConcurrentMap<SPIKey, SPI> _spis =
394                    new ConcurrentHashMap<SPIKey, SPI>();
395    
396            private static class MPIImpl implements MPI {
397    
398                    @Override
399                    public boolean isAlive() {
400                            return true;
401                    }
402    
403            }
404    
405            private static class SPIKey {
406    
407                    public SPIKey(String spiProviderName, String spiId) {
408                            _spiProviderName = spiProviderName;
409                            _spiId = spiId;
410                    }
411    
412                    @Override
413                    public boolean equals(Object obj) {
414                            SPIKey spiKey = (SPIKey)obj;
415    
416                            if (Validator.equals(
417                                            _spiProviderName, spiKey._spiProviderName) &&
418                                    Validator.equals(_spiId, spiKey._spiId)) {
419    
420                                    return true;
421                            }
422    
423                            return false;
424                    }
425    
426                    @Override
427                    public int hashCode() {
428                            return _spiProviderName.hashCode() * 11 + _spiId.hashCode();
429                    }
430    
431                    @Override
432                    public String toString() {
433                            return _spiProviderName.concat(StringPool.POUND).concat(_spiId);
434                    }
435    
436                    private String _spiId;
437                    private String _spiProviderName;
438    
439            }
440    
441            static {
442    
443                    // Keep strong reference to prevent garbage collection
444    
445                    _mpiImpl = new MPIImpl();
446    
447                    try {
448                            if (PropsUtil.getProps() != null) {
449                                    System.setProperty(
450                                            PropsKeys.INTRABAND_IMPL,
451                                            PropsUtil.get(PropsKeys.INTRABAND_IMPL));
452                                    System.setProperty(
453                                            PropsKeys.INTRABAND_TIMEOUT_DEFAULT,
454                                            PropsUtil.get(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
455                                    System.setProperty(
456                                            PropsKeys.INTRABAND_WELDER_IMPL,
457                                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_IMPL));
458                            }
459    
460                            _intraband = IntrabandFactoryUtil.createIntraband();
461    
462                            _mpi = (MPI)UnicastRemoteObject.exportObject(_mpiImpl, 0);
463                    }
464                    catch (Exception e) {
465                            throw new ExceptionInInitializerError(e);
466                    }
467            }
468    
469    }