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.kernel.portlet.bridges.mvc;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.ClassUtil;
020    import com.liferay.portal.kernel.util.InstanceFactory;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.registry.ServiceReference;
026    import com.liferay.registry.collections.ServiceReferenceMapper;
027    import com.liferay.registry.collections.ServiceTrackerCollections;
028    import com.liferay.registry.collections.ServiceTrackerMap;
029    import com.liferay.registry.util.StringPlus;
030    
031    import java.util.ArrayList;
032    import java.util.Arrays;
033    import java.util.List;
034    import java.util.Map;
035    import java.util.concurrent.ConcurrentHashMap;
036    
037    /**
038     * @author Sergio Gonz??lez
039     */
040    public class MVCCommandCache {
041    
042            public MVCCommandCache(
043                    MVCCommand emptyMVCCommand, String packagePrefix, String portletName,
044                    Class<? extends MVCCommand> mvcCommandClass, String mvcCommandPostFix) {
045    
046                    _emptyMVCCommand = emptyMVCCommand;
047                    _mvcComandPostFix = mvcCommandPostFix;
048    
049                    if (Validator.isNotNull(packagePrefix) &&
050                            !packagePrefix.endsWith(StringPool.PERIOD)) {
051    
052                            packagePrefix = packagePrefix + StringPool.PERIOD;
053                    }
054    
055                    _packagePrefix = packagePrefix;
056    
057                    _serviceTrackerMap = ServiceTrackerCollections.openSingleValueMap(
058                            mvcCommandClass,
059                            "(&(javax.portlet.name=" + portletName +")(mvc.command.name=*))",
060                            new ServiceReferenceMapper<String, MVCCommand>() {
061    
062                                    @Override
063                                    public void map(
064                                            ServiceReference<MVCCommand> serviceReference,
065                                            Emitter<String> emitter) {
066    
067                                            List<String> mvcCommandNames = StringPlus.asList(
068                                                    serviceReference.getProperty("mvc.command.name"));
069    
070                                            for (String mvcCommandName : mvcCommandNames) {
071                                                    emitter.emit(mvcCommandName);
072                                            }
073                                    }
074    
075                            });
076            }
077    
078            /**
079             * @deprecated As of 7.0.0, replaced by {@link #MVCCommandCache(MVCCommand,
080             *             String, String, Class, String)}
081             */
082            @Deprecated
083            public MVCCommandCache(
084                    MVCCommand emptyMVCCommand, String packagePrefix, String portletName,
085                    String mvcCommandClassName, String mvcCommandPostFix) {
086    
087                    this(
088                            emptyMVCCommand, packagePrefix, portletName,
089                            _getMVCCommandClass(mvcCommandClassName), mvcCommandPostFix);
090            }
091    
092            public void close() {
093                    _serviceTrackerMap.close();
094            }
095    
096            public MVCCommand getMVCCommand(String mvcCommandName) {
097                    String className = null;
098    
099                    MVCCommand mvcCommand = _serviceTrackerMap.getService(mvcCommandName);
100    
101                    if (mvcCommand != null) {
102                            return mvcCommand;
103                    }
104    
105                    try {
106                            mvcCommand = _mvcCommandCache.get(mvcCommandName);
107    
108                            if (mvcCommand != null) {
109                                    return mvcCommand;
110                            }
111    
112                            if (Validator.isNull(_packagePrefix)) {
113                                    return _emptyMVCCommand;
114                            }
115    
116                            StringBundler sb = new StringBundler(4);
117    
118                            sb.append(_packagePrefix);
119                            sb.append(Character.toUpperCase(mvcCommandName.charAt(0)));
120                            sb.append(mvcCommandName.substring(1));
121                            sb.append(_mvcComandPostFix);
122    
123                            className = sb.toString();
124    
125                            mvcCommand = (MVCCommand)InstanceFactory.newInstance(className);
126    
127                            _mvcCommandCache.put(mvcCommandName, mvcCommand);
128    
129                            return mvcCommand;
130                    }
131                    catch (Exception e) {
132                            if (_log.isWarnEnabled()) {
133                                    _log.warn("Unable to instantiate MVCCommand " + className);
134                            }
135    
136                            _mvcCommandCache.put(mvcCommandName, _emptyMVCCommand);
137    
138                            return _emptyMVCCommand;
139                    }
140            }
141    
142            public List<? extends MVCCommand> getMVCCommands(String key) {
143                    List<MVCCommand> mvcCommands = _mvcCommands.get(key);
144    
145                    String[] mvcCommandNames = StringUtil.split(key);
146    
147                    if ((mvcCommands != null) &&
148                            (mvcCommands.size() == mvcCommandNames.length)) {
149    
150                            return mvcCommands;
151                    }
152    
153                    mvcCommands = new ArrayList<>();
154    
155                    for (String mvcCommandName : mvcCommandNames) {
156                            MVCCommand mvcCommand = getMVCCommand(mvcCommandName);
157    
158                            if (mvcCommand != _emptyMVCCommand) {
159                                    mvcCommands.add(mvcCommand);
160                            }
161                            else {
162                                    if (_log.isWarnEnabled()) {
163                                            _log.warn("Unable to find MVCCommand " + key);
164                                    }
165                            }
166                    }
167    
168                    _mvcCommands.put(key, mvcCommands);
169    
170                    for (MVCCommand mvcCommand : mvcCommands) {
171                            String mvcCommandClassName = ClassUtil.getClassName(mvcCommand);
172    
173                            List<String> keys = _mvcCommandKeys.get(mvcCommandClassName);
174    
175                            if (keys == null) {
176                                    keys = new ArrayList<>();
177    
178                                    _mvcCommandKeys.put(mvcCommandClassName, keys);
179                            }
180    
181                            keys.add(key);
182                    }
183    
184                    return mvcCommands;
185            }
186    
187            public boolean isEmpty() {
188                    return _mvcCommandCache.isEmpty();
189            }
190    
191            private static Class<? extends MVCCommand> _getMVCCommandClass(
192                    String mvcCommandClassName) {
193    
194                    Class<? extends MVCCommand> mvcCommandClass = null;
195    
196                    for (Class<? extends MVCCommand> curMVCCommandClass :
197                                    _mvcCommandClasses) {
198    
199                            if (mvcCommandClassName.equals(curMVCCommandClass.getName())) {
200                                    mvcCommandClass = curMVCCommandClass;
201    
202                                    break;
203                            }
204                    }
205    
206                    if (mvcCommandClass == null) {
207                            throw new IllegalArgumentException();
208                    }
209    
210                    return mvcCommandClass;
211            }
212    
213            private static final Log _log = LogFactoryUtil.getLog(
214                    MVCCommandCache.class);
215    
216            private static final List<Class<? extends MVCCommand>> _mvcCommandClasses =
217                    Arrays.asList(
218                            MVCActionCommand.class, MVCRenderCommand.class,
219                            MVCResourceCommand.class);
220    
221            private final MVCCommand _emptyMVCCommand;
222            private final String _mvcComandPostFix;
223            private final Map<String, MVCCommand> _mvcCommandCache =
224                    new ConcurrentHashMap<>();
225            private final Map<String, List<String>> _mvcCommandKeys =
226                    new ConcurrentHashMap<>();
227            private final Map<String, List<MVCCommand>> _mvcCommands =
228                    new ConcurrentHashMap<>();
229            private final String _packagePrefix;
230            private final ServiceTrackerMap<String, ? extends MVCCommand>
231                    _serviceTrackerMap;
232    
233    }