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