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