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.portlet;
016    
017    import com.liferay.portal.kernel.model.Portlet;
018    import com.liferay.portal.kernel.model.PortletApp;
019    import com.liferay.portal.kernel.model.PortletConstants;
020    import com.liferay.portal.kernel.portlet.InvokerFilterContainer;
021    import com.liferay.portal.kernel.portlet.InvokerPortlet;
022    import com.liferay.portal.kernel.portlet.InvokerPortletFactory;
023    import com.liferay.portal.kernel.portlet.PortletBag;
024    import com.liferay.portal.kernel.portlet.PortletBagPool;
025    import com.liferay.portal.kernel.portlet.PortletConfigFactoryUtil;
026    import com.liferay.portal.kernel.portlet.PortletContextFactoryUtil;
027    import com.liferay.portal.kernel.portlet.PortletInstanceFactory;
028    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
029    import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
030    import com.liferay.portal.kernel.util.ClassLoaderUtil;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.registry.Registry;
033    import com.liferay.registry.RegistryUtil;
034    import com.liferay.registry.ServiceReference;
035    import com.liferay.registry.ServiceTracker;
036    import com.liferay.registry.ServiceTrackerCustomizer;
037    
038    import java.util.Map;
039    import java.util.concurrent.ConcurrentHashMap;
040    
041    import javax.portlet.PortletConfig;
042    import javax.portlet.PortletContext;
043    import javax.portlet.PortletException;
044    
045    import javax.servlet.ServletContext;
046    
047    /**
048     * @author Brian Wing Shun Chan
049     * @author Shuyang Zhou
050     */
051    @DoPrivileged
052    public class PortletInstanceFactoryImpl implements PortletInstanceFactory {
053    
054            public PortletInstanceFactoryImpl() {
055                    _pool = new ConcurrentHashMap<>();
056    
057                    Registry registry = RegistryUtil.getRegistry();
058    
059                    _serviceTracker = registry.trackServices(
060                            InvokerPortletFactory.class,
061                            new InvokerPortletFactoryTrackerCustomizer());
062    
063                    _serviceTracker.open();
064            }
065    
066            @Override
067            public void clear(Portlet portlet) {
068                    clear(portlet, true);
069            }
070    
071            @Override
072            public void clear(Portlet portlet, boolean resetRemotePortletBag) {
073                    String rootPortletId = portlet.getRootPortletId();
074    
075                    Map<String, InvokerPortlet> portletInstances = _pool.remove(
076                            rootPortletId);
077    
078                    if (portletInstances != null) {
079                            InvokerPortlet rootInvokerPortletInstance = portletInstances.remove(
080                                    rootPortletId);
081    
082                            if (rootInvokerPortletInstance != null) {
083                                    rootInvokerPortletInstance.destroy();
084                            }
085    
086                            portletInstances.clear();
087                    }
088    
089                    PortletApp portletApp = portlet.getPortletApp();
090    
091                    if (resetRemotePortletBag && portletApp.isWARFile()) {
092                            PortletBag portletBag = PortletBagPool.remove(rootPortletId);
093    
094                            if (portletBag != null) {
095                                    portletBag.destroy();
096                            }
097                    }
098            }
099    
100            @Override
101            public InvokerPortlet create(Portlet portlet, ServletContext servletContext)
102                    throws PortletException {
103    
104                    return create (portlet, servletContext, false);
105            }
106    
107            @Override
108            public InvokerPortlet create(
109                            Portlet portlet, ServletContext servletContext,
110                            boolean destroyPrevious)
111                    throws PortletException {
112    
113                    if (destroyPrevious) {
114                            destroyRelated(portlet);
115                    }
116    
117                    boolean instanceable = false;
118    
119                    boolean deployed = !portlet.isUndeployedPortlet();
120    
121                    if (portlet.isInstanceable() && deployed &&
122                            PortletConstants.hasInstanceId(portlet.getPortletId())) {
123    
124                            instanceable = true;
125                    }
126    
127                    String rootPortletId = portlet.getRootPortletId();
128    
129                    InvokerPortlet rootInvokerPortletInstance = null;
130    
131                    Map<String, InvokerPortlet> portletInstances = null;
132    
133                    if (deployed) {
134                            portletInstances = _pool.get(rootPortletId);
135    
136                            if (portletInstances == null) {
137                                    portletInstances = new ConcurrentHashMap<>();
138    
139                                    _pool.put(rootPortletId, portletInstances);
140                            }
141                            else {
142                                    if (instanceable) {
143                                            InvokerPortlet instanceInvokerPortletInstance =
144                                                    portletInstances.get(portlet.getPortletId());
145    
146                                            if (instanceInvokerPortletInstance != null) {
147                                                    return instanceInvokerPortletInstance;
148                                            }
149                                    }
150    
151                                    rootInvokerPortletInstance = portletInstances.get(
152                                            rootPortletId);
153                            }
154                    }
155    
156                    if (rootInvokerPortletInstance == null) {
157                            PortletBag portletBag = PortletBagPool.get(rootPortletId);
158    
159                            // Portlet bag should never be null unless the portlet has been
160                            // undeployed
161    
162                            if (portletBag == null) {
163                                    PortletBagFactory portletBagFactory = new PortletBagFactory();
164    
165                                    portletBagFactory.setClassLoader(
166                                            ClassLoaderUtil.getPortalClassLoader());
167                                    portletBagFactory.setServletContext(servletContext);
168                                    portletBagFactory.setWARFile(false);
169    
170                                    try {
171                                            portletBag = portletBagFactory.create(portlet);
172                                    }
173                                    catch (Exception e) {
174                                            throw new PortletException(e);
175                                    }
176                            }
177    
178                            PortletConfig portletConfig = PortletConfigFactoryUtil.create(
179                                    portlet, servletContext);
180    
181                            rootInvokerPortletInstance = init(
182                                    portlet, portletConfig, portletBag.getPortletInstance());
183    
184                            if (deployed) {
185                                    portletInstances.put(rootPortletId, rootInvokerPortletInstance);
186                            }
187                    }
188    
189                    if (!instanceable) {
190                            return rootInvokerPortletInstance;
191                    }
192    
193                    javax.portlet.Portlet portletInstance =
194                            rootInvokerPortletInstance.getPortletInstance();
195    
196                    PortletConfig portletConfig = PortletConfigFactoryUtil.create(
197                            portlet, servletContext);
198    
199                    PortletContext portletContext = portletConfig.getPortletContext();
200                    boolean checkAuthToken = rootInvokerPortletInstance.isCheckAuthToken();
201                    boolean facesPortlet = rootInvokerPortletInstance.isFacesPortlet();
202                    boolean strutsPortlet = rootInvokerPortletInstance.isStrutsPortlet();
203                    boolean strutsBridgePortlet =
204                            rootInvokerPortletInstance.isStrutsBridgePortlet();
205    
206                    InvokerPortlet instanceInvokerPortletInstance =
207                            _invokerPortletFactory.create(
208                                    portlet, portletInstance, portletConfig, portletContext,
209                                    (InvokerFilterContainer)rootInvokerPortletInstance,
210                                    checkAuthToken, facesPortlet, strutsPortlet,
211                                    strutsBridgePortlet);
212    
213                    if (deployed) {
214                            portletInstances.put(
215                                    portlet.getPortletId(), instanceInvokerPortletInstance);
216                    }
217    
218                    return instanceInvokerPortletInstance;
219            }
220    
221            @Override
222            public void delete(Portlet portlet) {
223                    if (PortletConstants.hasInstanceId(portlet.getPortletId())) {
224                            Map<String, InvokerPortlet> portletInstances = _pool.get(
225                                    portlet.getRootPortletId());
226    
227                            if (portletInstances != null) {
228                                    portletInstances.remove(portlet.getPortletId());
229                            }
230                    }
231            }
232    
233            public void destroy() {
234    
235                    // LPS-10473
236    
237            }
238    
239            @Override
240            public void destroy(Portlet portlet) {
241                    _serviceTracker.close();
242    
243                    clear(portlet);
244    
245                    destroyRelated(portlet);
246    
247                    PortletLocalServiceUtil.destroyPortlet(portlet);
248            }
249    
250            protected void destroyRelated(Portlet portlet) {
251                    PortletConfigFactoryUtil.destroy(portlet);
252                    PortletContextFactoryUtil.destroy(portlet);
253            }
254    
255            protected InvokerPortlet init(
256                            Portlet portlet, PortletConfig portletConfig,
257                            javax.portlet.Portlet portletInstance)
258                    throws PortletException {
259    
260                    PortletContext portletContext = portletConfig.getPortletContext();
261    
262                    InvokerFilterContainer invokerFilterContainer =
263                            new InvokerFilterContainerImpl(portlet, portletContext);
264    
265                    InvokerPortlet invokerPortlet = _invokerPortletFactory.create(
266                            portlet, portletInstance, portletContext, invokerFilterContainer);
267    
268                    invokerPortlet.init(portletConfig);
269    
270                    return invokerPortlet;
271            }
272    
273            private InvokerPortletFactory _invokerPortletFactory;
274            private final Map<String, Map<String, InvokerPortlet>> _pool;
275            private long _serviceRanking;
276            private final ServiceTracker<InvokerPortletFactory, InvokerPortletFactory>
277                    _serviceTracker;
278    
279            private class InvokerPortletFactoryTrackerCustomizer
280                    implements ServiceTrackerCustomizer
281                            <InvokerPortletFactory, InvokerPortletFactory> {
282    
283                    @Override
284                    public synchronized InvokerPortletFactory addingService(
285                            ServiceReference<InvokerPortletFactory> serviceReference) {
286    
287                            Registry registry = RegistryUtil.getRegistry();
288    
289                            InvokerPortletFactory invokerPortletFactory = registry.getService(
290                                    serviceReference);
291    
292                            long serviceRanking = GetterUtil.getLong(
293                                    serviceReference.getProperty("service.ranking"));
294    
295                            if ((_invokerPortletFactory == null) ||
296                                    (serviceRanking > _serviceRanking)) {
297    
298                                    _invokerPortletFactory = invokerPortletFactory;
299                                    _serviceRanking = serviceRanking;
300                            }
301    
302                            return invokerPortletFactory;
303                    }
304    
305                    @Override
306                    public void modifiedService(
307                            ServiceReference<InvokerPortletFactory> serviceReference,
308                            InvokerPortletFactory invokerPortletFactory) {
309                    }
310    
311                    @Override
312                    public synchronized void removedService(
313                            ServiceReference<InvokerPortletFactory> serviceReference,
314                            InvokerPortletFactory invokerPortletFactory) {
315    
316                            Registry registry = RegistryUtil.getRegistry();
317    
318                            registry.ungetService(serviceReference);
319    
320                            serviceReference = registry.getServiceReference(
321                                    InvokerPortletFactory.class);
322    
323                            if (serviceReference != null) {
324                                    _invokerPortletFactory = registry.getService(serviceReference);
325    
326                                    _serviceRanking = GetterUtil.getLong(
327                                            serviceReference.getProperty("service.ranking"));
328                            }
329                    }
330    
331            }
332    
333    }