001    /**
002     * Copyright (c) 2000-present 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.nio.intraband.proxy;
016    
017    import com.liferay.portal.events.StartupHelperUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
021    import com.liferay.portal.kernel.nio.intraband.rpc.IntrabandRPCUtil;
022    import com.liferay.portal.kernel.process.ProcessCallable;
023    
024    import java.util.concurrent.Future;
025    
026    /**
027     * @author Shuyang Zhou
028     */
029    public class StubHolder<T> {
030    
031            public StubHolder(
032                    T originalT, String stubId, RegistrationReference registrationReference,
033                    StubCreator<T> stubCreator) {
034    
035                    _originalT = originalT;
036                    _stubId = stubId;
037                    _registrationReference = registrationReference;
038                    _stubCreator = stubCreator;
039            }
040    
041            public T getStub() {
042                    if (_stub != null) {
043                            return doGetStub();
044                    }
045    
046                    synchronized (_registrationReference) {
047                            if (_stub != null) {
048                                    return doGetStub();
049                            }
050    
051                            Future<Boolean> future = IntrabandRPCUtil.execute(
052                                    _registrationReference, _startupFinishedProcessCallable);
053    
054                            boolean startupFinished = false;
055    
056                            try {
057                                    startupFinished = future.get();
058                            }
059                            catch (Exception e) {
060                                    if (_log.isWarnEnabled()) {
061                                            _log.warn("Unable to detect SPI's startup status", e);
062                                    }
063                            }
064    
065                            if (!startupFinished) {
066                                    return _originalT;
067                            }
068    
069                            try {
070                                    _stub = _stubCreator.createStub(
071                                            _stubId, _originalT, _registrationReference);
072    
073                                    return _stub;
074                            }
075                            catch (Exception e) {
076                                    if (_log.isWarnEnabled()) {
077                                            _log.warn("Unable to create stub", e);
078                                    }
079    
080                                    return _stubCreator.onCreationFailure(_stubId, _originalT, e);
081                            }
082                    }
083            }
084    
085            public interface StubCreator<T> {
086    
087                    public T createStub(
088                                    String stubId, T originalT,
089                                    RegistrationReference registrationReference)
090                            throws Exception;
091    
092                    public T onCreationFailure(String stubId, T originalT, Exception e);
093    
094                    public T onInvalidation(String stubId, T originalT, T stub);
095    
096            }
097    
098            protected T doGetStub() {
099                    if (_registrationReference.isValid()) {
100                            return _stub;
101                    }
102    
103                    return _stubCreator.onInvalidation(_stubId, _stub, _originalT);
104            }
105    
106            private static final Log _log = LogFactoryUtil.getLog(StubHolder.class);
107    
108            private static final ProcessCallable<Boolean>
109                    _startupFinishedProcessCallable = new StartupFinishedProcessCallable();
110    
111            private final T _originalT;
112            private final RegistrationReference _registrationReference;
113            private volatile T _stub;
114            private final StubCreator<T> _stubCreator;
115            private final String _stubId;
116    
117            private static class StartupFinishedProcessCallable
118                    implements ProcessCallable<Boolean> {
119    
120                    @Override
121                    public Boolean call() {
122                            return StartupHelperUtil.isStartupFinished();
123                    }
124    
125                    private static final long serialVersionUID = 1L;
126    
127            }
128    
129    }