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