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.nio.intraband.SystemDataType;
024    import com.liferay.portal.kernel.nio.intraband.rpc.BootstrapRPCDatagramReceiveHandler;
025    import com.liferay.portal.kernel.resiliency.spi.SPI;
026    import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
027    import com.liferay.portal.kernel.resiliency.spi.SPIRegistryUtil;
028    import com.liferay.portal.kernel.resiliency.spi.provider.SPIProvider;
029    import com.liferay.portal.kernel.util.PropsKeys;
030    import com.liferay.portal.kernel.util.PropsUtil;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.Validator;
033    
034    import java.rmi.NoSuchObjectException;
035    import java.rmi.RemoteException;
036    import java.rmi.server.UnicastRemoteObject;
037    
038    import java.util.ArrayList;
039    import java.util.List;
040    import java.util.Map;
041    import java.util.concurrent.ConcurrentHashMap;
042    import java.util.concurrent.ConcurrentMap;
043    import java.util.concurrent.locks.Lock;
044    import java.util.concurrent.locks.ReentrantLock;
045    
046    /**
047     * @author Shuyang Zhou
048     */
049    public class MPIHelperUtil {
050    
051            public static Intraband getIntraband() {
052                    return _intraband;
053            }
054    
055            public static MPI getMPI() {
056                    return _mpi;
057            }
058    
059            public static SPI getSPI(String spiProviderName, String spiId) {
060                    SPIKey spiKey = new SPIKey(spiProviderName, spiId);
061    
062                    SPI spi = _spis.get(spiKey);
063    
064                    if (spi != null) {
065                            spi = _checkSPILiveness(spi);
066                    }
067    
068                    return spi;
069            }
070    
071            public static SPIProvider getSPIProvider(String spiProviderName) {
072                    return _spiProviders.get(spiProviderName);
073            }
074    
075            public static List<SPIProvider> getSPIProviders() {
076                    return new ArrayList<SPIProvider>(_spiProviders.values());
077            }
078    
079            public static List<SPI> getSPIs() {
080                    List<SPI> spis = new ArrayList<SPI>();
081    
082                    for (SPI spi : _spis.values()) {
083                            spi = _checkSPILiveness(spi);
084    
085                            if (spi != null) {
086                                    spis.add(spi);
087                            }
088                    }
089    
090                    return spis;
091            }
092    
093            public static List<SPI> getSPIs(String spiProviderName) {
094                    List<SPI> spis = new ArrayList<SPI>();
095    
096                    for (Map.Entry<SPIKey, SPI> entry : _spis.entrySet()) {
097                            SPIKey spiKey = entry.getKey();
098    
099                            if (!spiProviderName.equals(spiKey._spiProviderName)) {
100                                    continue;
101                            }
102    
103                            SPI spi = entry.getValue();
104    
105                            spi = _checkSPILiveness(spi);
106    
107                            if (spi != null) {
108                                    spis.add(spi);
109                            }
110                    }
111    
112                    return spis;
113            }
114    
115            public static boolean registerSPI(SPI spi) {
116                    _lock.lock();
117    
118                    try {
119                            MPI mpi = spi.getMPI();
120    
121                            if (mpi != _mpi) {
122                                    if (_log.isWarnEnabled()) {
123                                            _log.warn(
124                                                    "Not registering SPI " + spi + " with foreign MPI " +
125                                                            mpi + " versus " + _mpi);
126                                    }
127    
128                                    return false;
129                            }
130    
131                            String spiProviderName = spi.getSPIProviderName();
132    
133                            SPIProvider spiProvider = _spiProviders.get(spiProviderName);
134    
135                            if (spiProvider == null) {
136                                    if (_log.isWarnEnabled()) {
137                                            _log.warn(
138                                                    "Not registering SPI " + spi +
139                                                            " with unknown SPI provider " + spiProviderName);
140                                    }
141    
142                                    return false;
143                            }
144    
145                            SPIConfiguration spiConfiguration = spi.getSPIConfiguration();
146    
147                            SPIKey spiKey = new SPIKey(
148                                    spiProviderName, spiConfiguration.getSPIId());
149    
150                            SPI previousSPI = _spis.putIfAbsent(spiKey, spi);
151    
152                            if (previousSPI != null) {
153                                    if (_log.isWarnEnabled()) {
154                                            _log.warn(
155                                                    "Not registering SPI " + spi +
156                                                            " because it duplicates " + previousSPI);
157                                    }
158    
159                                    return false;
160                            }
161    
162                            SPIRegistryUtil.registerSPI(spi);
163    
164                            for (String servletContextName :
165                                            spiConfiguration.getServletContextNames()) {
166    
167                                    List<MessagingConfigurator> messagingConfigurators =
168                                            MessagingConfiguratorRegistry.getMessagingConfigurators(
169                                                    servletContextName);
170    
171                                    if (messagingConfigurators != null) {
172                                            for (MessagingConfigurator messagingConfigurator :
173                                                            messagingConfigurators) {
174    
175                                                    messagingConfigurator.disconnect();
176                                            }
177                                    }
178                            }
179    
180                            if (_log.isInfoEnabled()) {
181                                    _log.info("Registered SPI " + spi);
182                            }
183    
184                            return true;
185                    }
186                    catch (RemoteException re) {
187                            throw new RuntimeException(re);
188                    }
189                    finally {
190                            _lock.unlock();
191                    }
192            }
193    
194            public static boolean registerSPIProvider(SPIProvider spiProvider) {
195                    String spiProviderName = spiProvider.getName();
196    
197                    SPIProvider previousSPIProvider = null;
198    
199                    _lock.lock();
200    
201                    try {
202                            previousSPIProvider = _spiProviders.putIfAbsent(
203                                    spiProviderName, spiProvider);
204                    }
205                    finally {
206                            _lock.unlock();
207                    }
208    
209                    if (previousSPIProvider != null) {
210                            if (_log.isWarnEnabled()) {
211                                    _log.warn(
212                                            "Not registering SPI provider " + spiProvider +
213                                                    " because it duplicates " + previousSPIProvider);
214                            }
215    
216                            return false;
217                    }
218    
219                    if (_log.isInfoEnabled()) {
220                            _log.info("Registered SPI provider " + spiProvider);
221                    }
222    
223                    return true;
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    
299                            if (_log.isWarnEnabled()) {
300                                    _log.warn("Not unregistering unregistered SPI " + spi);
301                            }
302    
303                            return false;
304                    }
305                    catch (RemoteException re) {
306                            throw new RuntimeException(re);
307                    }
308                    finally {
309                            _lock.unlock();
310                    }
311            }
312    
313            public static boolean unregisterSPIProvider(SPIProvider spiProvider) {
314                    _lock.lock();
315    
316                    try {
317                            String spiProviderName = spiProvider.getName();
318    
319                            if (_spiProviders.remove(spiProviderName, spiProvider)) {
320                                    for (Map.Entry<SPIKey, SPI> entry : _spis.entrySet()) {
321                                            SPIKey spiKey = entry.getKey();
322    
323                                            if (!spiProviderName.equals(spiKey._spiProviderName)) {
324                                                    continue;
325                                            }
326    
327                                            SPI spi = entry.getValue();
328    
329                                            try {
330                                                    spi.destroy();
331    
332                                                    if (_log.isInfoEnabled()) {
333                                                            _log.info(
334                                                                    "Unregistered SPI " + spi +
335                                                                            " while unregistering SPI provider " +
336                                                                                    spiProvider);
337                                                    }
338                                            }
339                                            catch (RemoteException re) {
340                                                    _log.error(
341                                                            "Unable to unregister SPI " + spi +
342                                                                    " while unregistering SPI provider " +
343                                                                            spiProvider,
344                                                            re);
345                                            }
346                                    }
347    
348                                    if (_log.isInfoEnabled()) {
349                                            _log.info("Unregistered SPI provider " + spiProvider);
350                                    }
351    
352                                    return true;
353                            }
354    
355                            if (_log.isWarnEnabled()) {
356                                    _log.warn(
357                                            "Not unregistering unregistered SPI provider " +
358                                                    spiProvider);
359                            }
360    
361                            return false;
362                    }
363                    finally {
364                            _lock.unlock();
365                    }
366            }
367    
368            private static SPI _checkSPILiveness(SPI spi) {
369                    boolean alive = false;
370    
371                    try {
372                            alive = spi.isAlive();
373                    }
374                    catch (RemoteException re) {
375                            _log.error(re);
376                    }
377    
378                    if (alive) {
379                            return spi;
380                    }
381    
382                    unregisterSPI(spi);
383    
384                    return null;
385            }
386    
387            private static Log _log = LogFactoryUtil.getLog(MPIHelperUtil.class);
388    
389            private static Intraband _intraband;
390            private static Lock _lock = new ReentrantLock();
391            private static MPI _mpi;
392            private static MPI _mpiImpl;
393            private static ConcurrentMap<String, SPIProvider> _spiProviders =
394                    new ConcurrentHashMap<String, SPIProvider>();
395            private static ConcurrentMap<SPIKey, SPI> _spis =
396                    new ConcurrentHashMap<SPIKey, SPI>();
397    
398            private static class MPIImpl implements MPI {
399    
400                    @Override
401                    public boolean isAlive() {
402                            return true;
403                    }
404    
405            }
406    
407            private static class SPIKey {
408    
409                    public SPIKey(String spiProviderName, String spiId) {
410                            _spiProviderName = spiProviderName;
411                            _spiId = spiId;
412                    }
413    
414                    @Override
415                    public boolean equals(Object obj) {
416                            SPIKey spiKey = (SPIKey)obj;
417    
418                            if (Validator.equals(
419                                            _spiProviderName, spiKey._spiProviderName) &&
420                                    Validator.equals(_spiId, spiKey._spiId)) {
421    
422                                    return true;
423                            }
424    
425                            return false;
426                    }
427    
428                    @Override
429                    public int hashCode() {
430                            return _spiProviderName.hashCode() * 11 + _spiId.hashCode();
431                    }
432    
433                    @Override
434                    public String toString() {
435                            return _spiProviderName.concat(StringPool.POUND).concat(_spiId);
436                    }
437    
438                    private String _spiId;
439                    private String _spiProviderName;
440    
441            }
442    
443            static {
444    
445                    // Keep strong reference to prevent garbage collection
446    
447                    _mpiImpl = new MPIImpl();
448    
449                    try {
450                            if (PropsUtil.getProps() != null) {
451                                    System.setProperty(
452                                            PropsKeys.INTRABAND_IMPL,
453                                            PropsUtil.get(PropsKeys.INTRABAND_IMPL));
454                                    System.setProperty(
455                                            PropsKeys.INTRABAND_TIMEOUT_DEFAULT,
456                                            PropsUtil.get(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
457                                    System.setProperty(
458                                            PropsKeys.INTRABAND_WELDER_IMPL,
459                                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_IMPL));
460                            }
461    
462                            _intraband = IntrabandFactoryUtil.createIntraband();
463    
464                            _intraband.registerDatagramReceiveHandler(
465                                    SystemDataType.RPC.getValue(),
466                                    new BootstrapRPCDatagramReceiveHandler());
467    
468                            _mpi = (MPI)UnicastRemoteObject.exportObject(_mpiImpl, 0);
469                    }
470                    catch (Exception e) {
471                            throw new ExceptionInInitializerError(e);
472                    }
473            }
474    
475    }