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                            else {
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                    }
185                    catch (RemoteException re) {
186                            throw new RuntimeException(re);
187                    }
188                    finally {
189                            _lock.unlock();
190                    }
191            }
192    
193            public static boolean registerSPIProvider(SPIProvider spiProvider) {
194                    String spiProviderName = spiProvider.getName();
195    
196                    SPIProvider previousSPIProvider = null;
197    
198                    _lock.lock();
199    
200                    try {
201                            previousSPIProvider = _spiProviders.putIfAbsent(
202                                    spiProviderName, spiProvider);
203                    }
204                    finally {
205                            _lock.unlock();
206                    }
207    
208                    if (previousSPIProvider != null) {
209                            if (_log.isWarnEnabled()) {
210                                    _log.warn(
211                                            "Not registering SPI provider " + spiProvider +
212                                                    " because it duplicates " + previousSPIProvider);
213                            }
214    
215                            return false;
216                    }
217                    else {
218                            if (_log.isInfoEnabled()) {
219                                    _log.info("Registered SPI provider " + spiProvider);
220                            }
221    
222                            return true;
223                    }
224            }
225    
226            public static void shutdown() {
227                    try {
228                            UnicastRemoteObject.unexportObject(_mpiImpl, true);
229                    }
230                    catch (NoSuchObjectException nsoe) {
231                            if (_log.isWarnEnabled()) {
232                                    _log.warn("Unable to unexport " + _mpiImpl, nsoe);
233                            }
234                    }
235            }
236    
237            public static boolean unregisterSPI(SPI spi) {
238                    _lock.lock();
239    
240                    try {
241                            MPI mpi = spi.getMPI();
242    
243                            if (mpi != _mpi) {
244                                    if (_log.isWarnEnabled()) {
245                                            _log.warn(
246                                                    "Not unregistering SPI " + spi + " with foreign MPI " +
247                                                            mpi + " versus " + _mpi);
248                                    }
249    
250                                    return false;
251                            }
252    
253                            String spiProviderName = spi.getSPIProviderName();
254    
255                            SPIProvider spiProvider = _spiProviders.get(spiProviderName);
256    
257                            if (spiProvider == null) {
258                                    if (_log.isWarnEnabled()) {
259                                            _log.warn(
260                                                    "Not unregistering SPI " + spi +
261                                                            " with unknown SPI provider " + spiProviderName);
262                                    }
263    
264                                    return false;
265                            }
266    
267                            SPIConfiguration spiConfiguration = spi.getSPIConfiguration();
268    
269                            String spiId = spiConfiguration.getSPIId();
270    
271                            SPIKey spiKey = new SPIKey(spiProviderName, spiId);
272    
273                            if (_spis.remove(spiKey, spi)) {
274                                    SPIRegistryUtil.unregisterSPI(spi);
275    
276                                    for (String servletContextName :
277                                                    spiConfiguration.getServletContextNames()) {
278    
279                                            List<MessagingConfigurator> messagingConfigurators =
280                                                    MessagingConfiguratorRegistry.getMessagingConfigurators(
281                                                            servletContextName);
282    
283                                            if (messagingConfigurators != null) {
284                                                    for (MessagingConfigurator messagingConfigurator :
285                                                                    messagingConfigurators) {
286    
287                                                            messagingConfigurator.connect();
288                                                    }
289                                            }
290                                    }
291    
292                                    if (_log.isInfoEnabled()) {
293                                            _log.info("Unregistered SPI " + spi);
294                                    }
295    
296                                    return true;
297                            }
298                            else {
299                                    if (_log.isWarnEnabled()) {
300                                            _log.warn("Not unregistering unregistered SPI " + spi);
301                                    }
302    
303                                    return false;
304                            }
305                    }
306                    catch (RemoteException re) {
307                            throw new RuntimeException(re);
308                    }
309                    finally {
310                            _lock.unlock();
311                    }
312            }
313    
314            public static boolean unregisterSPIProvider(SPIProvider spiProvider) {
315                    _lock.lock();
316    
317                    try {
318                            String spiProviderName = spiProvider.getName();
319    
320                            if (_spiProviders.remove(spiProviderName, spiProvider)) {
321                                    for (Map.Entry<SPIKey, SPI> entry : _spis.entrySet()) {
322                                            SPIKey spiKey = entry.getKey();
323    
324                                            if (!spiProviderName.equals(spiKey._spiProviderName)) {
325                                                    continue;
326                                            }
327    
328                                            SPI spi = entry.getValue();
329    
330                                            try {
331                                                    spi.destroy();
332    
333                                                    if (_log.isInfoEnabled()) {
334                                                            _log.info(
335                                                                    "Unregistered SPI " + spi +
336                                                                            " while unregistering SPI provider " +
337                                                                                    spiProvider);
338                                                    }
339                                            }
340                                            catch (RemoteException re) {
341                                                    _log.error(
342                                                            "Unable to unregister SPI " + spi +
343                                                                    " while unregistering SPI provider " +
344                                                                            spiProvider,
345                                                            re);
346                                            }
347                                    }
348    
349                                    if (_log.isInfoEnabled()) {
350                                            _log.info("Unregistered SPI provider " + spiProvider);
351                                    }
352    
353                                    return true;
354                            }
355                            else {
356                                    if (_log.isWarnEnabled()) {
357                                            _log.warn(
358                                                    "Not unregistering unregistered SPI provider " +
359                                                            spiProvider);
360                                    }
361    
362                                    return false;
363                            }
364                    }
365                    finally {
366                            _lock.unlock();
367                    }
368            }
369    
370            private static SPI _checkSPILiveness(SPI spi) {
371                    boolean alive = false;
372    
373                    try {
374                            alive = spi.isAlive();
375                    }
376                    catch (RemoteException re) {
377                            _log.error(re);
378                    }
379    
380                    if (alive) {
381                            return spi;
382                    }
383    
384                    unregisterSPI(spi);
385    
386                    return null;
387            }
388    
389            private static Log _log = LogFactoryUtil.getLog(MPIHelperUtil.class);
390    
391            private static Intraband _intraband;
392            private static Lock _lock = new ReentrantLock();
393            private static MPI _mpi;
394            private static MPI _mpiImpl;
395            private static ConcurrentMap<String, SPIProvider> _spiProviders =
396                    new ConcurrentHashMap<String, SPIProvider>();
397            private static ConcurrentMap<SPIKey, SPI> _spis =
398                    new ConcurrentHashMap<SPIKey, SPI>();
399    
400            private static class MPIImpl implements MPI {
401    
402                    @Override
403                    public boolean isAlive() {
404                            return true;
405                    }
406    
407            }
408    
409            private static class SPIKey {
410    
411                    public SPIKey(String spiProviderName, String spiId) {
412                            _spiProviderName = spiProviderName;
413                            _spiId = spiId;
414                    }
415    
416                    @Override
417                    public boolean equals(Object obj) {
418                            SPIKey spiKey = (SPIKey)obj;
419    
420                            if (Validator.equals(
421                                            _spiProviderName, spiKey._spiProviderName) &&
422                                    Validator.equals(_spiId, spiKey._spiId)) {
423    
424                                    return true;
425                            }
426    
427                            return false;
428                    }
429    
430                    @Override
431                    public int hashCode() {
432                            return _spiProviderName.hashCode() * 11 + _spiId.hashCode();
433                    }
434    
435                    @Override
436                    public String toString() {
437                            return _spiProviderName.concat(StringPool.POUND).concat(_spiId);
438                    }
439    
440                    private String _spiId;
441                    private String _spiProviderName;
442    
443            }
444    
445            static {
446    
447                    // Keep strong reference to prevent garbage collection
448    
449                    _mpiImpl = new MPIImpl();
450    
451                    try {
452                            if (PropsUtil.getProps() != null) {
453                                    System.setProperty(
454                                            PropsKeys.INTRABAND_IMPL,
455                                            PropsUtil.get(PropsKeys.INTRABAND_IMPL));
456                                    System.setProperty(
457                                            PropsKeys.INTRABAND_TIMEOUT_DEFAULT,
458                                            PropsUtil.get(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
459                                    System.setProperty(
460                                            PropsKeys.INTRABAND_WELDER_IMPL,
461                                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_IMPL));
462                            }
463    
464                            _intraband = IntrabandFactoryUtil.createIntraband();
465    
466                            _mpi = (MPI)UnicastRemoteObject.exportObject(_mpiImpl, 0);
467                    }
468                    catch (Exception e) {
469                            throw new ExceptionInInitializerError(e);
470                    }
471            }
472    
473    }