/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portlet; import com.liferay.portal.kernel.model.Portlet; import com.liferay.portal.kernel.model.PortletApp; import com.liferay.portal.kernel.model.PortletConstants; import com.liferay.portal.kernel.portlet.InvokerFilterContainer; import com.liferay.portal.kernel.portlet.InvokerPortlet; import com.liferay.portal.kernel.portlet.InvokerPortletFactory; import com.liferay.portal.kernel.portlet.PortletBag; import com.liferay.portal.kernel.portlet.PortletBagPool; import com.liferay.portal.kernel.portlet.PortletConfigFactoryUtil; import com.liferay.portal.kernel.portlet.PortletContextFactoryUtil; import com.liferay.portal.kernel.portlet.PortletInstanceFactory; import com.liferay.portal.kernel.security.pacl.DoPrivileged; import com.liferay.portal.kernel.service.PortletLocalServiceUtil; import com.liferay.portal.kernel.util.ClassLoaderUtil; import com.liferay.portal.kernel.util.ReflectionUtil; import com.liferay.registry.Registry; import com.liferay.registry.RegistryUtil; import com.liferay.registry.ServiceTracker; import com.liferay.registry.ServiceTrackerFieldUpdaterCustomizer; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.portlet.PortletConfig; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.servlet.ServletContext; /** * @author Brian Wing Shun Chan * @author Shuyang Zhou */ @DoPrivileged public class PortletInstanceFactoryImpl implements PortletInstanceFactory { public void afterPropertiesSet() throws Exception { Registry registry = RegistryUtil.getRegistry(); _serviceTracker = registry.trackServices( InvokerPortletFactory.class, new ServiceTrackerFieldUpdaterCustomizer <InvokerPortletFactory, InvokerPortletFactory>( ReflectionUtil.getDeclaredField( PortletInstanceFactoryImpl.class, "_invokerPortletFactory"), this, _defaultInvokerPortletFactory) { @Override protected void afterServiceUpdate( InvokerPortletFactory oldInvokerPortletFactory, InvokerPortletFactory newInvokerPortletFactory) { _pool.clear(); } }); _serviceTracker.open(); } @Override public void clear(Portlet portlet) { clear(portlet, true); } @Override public void clear(Portlet portlet, boolean resetRemotePortletBag) { String rootPortletId = portlet.getRootPortletId(); Map<String, InvokerPortlet> portletInstances = _pool.remove( rootPortletId); if (portletInstances != null) { InvokerPortlet rootInvokerPortletInstance = portletInstances.remove( rootPortletId); if (rootInvokerPortletInstance != null) { rootInvokerPortletInstance.destroy(); } portletInstances.clear(); } PortletApp portletApp = portlet.getPortletApp(); if (resetRemotePortletBag && portletApp.isWARFile()) { PortletBag portletBag = PortletBagPool.remove(rootPortletId); if (portletBag != null) { portletBag.destroy(); } } } @Override public InvokerPortlet create(Portlet portlet, ServletContext servletContext) throws PortletException { return create(portlet, servletContext, false); } @Override public InvokerPortlet create( Portlet portlet, ServletContext servletContext, boolean destroyPrevious) throws PortletException { if (destroyPrevious) { destroyRelated(portlet); } boolean instanceable = false; boolean deployed = !portlet.isUndeployedPortlet(); if (portlet.isInstanceable() && deployed && PortletConstants.hasInstanceId(portlet.getPortletId())) { instanceable = true; } String rootPortletId = portlet.getRootPortletId(); InvokerPortlet rootInvokerPortletInstance = null; Map<String, InvokerPortlet> portletInstances = null; if (deployed) { portletInstances = _pool.get(rootPortletId); if (portletInstances == null) { portletInstances = new ConcurrentHashMap<>(); _pool.put(rootPortletId, portletInstances); } else { if (instanceable) { InvokerPortlet instanceInvokerPortletInstance = portletInstances.get(portlet.getPortletId()); if (instanceInvokerPortletInstance != null) { return instanceInvokerPortletInstance; } } rootInvokerPortletInstance = portletInstances.get( rootPortletId); } } if (rootInvokerPortletInstance == null) { PortletBag portletBag = PortletBagPool.get(rootPortletId); // Portlet bag should never be null unless the portlet has been // undeployed if (portletBag == null) { PortletBagFactory portletBagFactory = new PortletBagFactory(); portletBagFactory.setClassLoader( ClassLoaderUtil.getPortalClassLoader()); portletBagFactory.setServletContext(servletContext); portletBagFactory.setWARFile(false); try { portletBag = portletBagFactory.create(portlet); } catch (Exception e) { throw new PortletException(e); } } PortletConfig portletConfig = PortletConfigFactoryUtil.create( portlet, servletContext); rootInvokerPortletInstance = init( portlet, portletConfig, portletBag.getPortletInstance()); if (deployed) { portletInstances.put(rootPortletId, rootInvokerPortletInstance); } } if (!instanceable) { return rootInvokerPortletInstance; } javax.portlet.Portlet portletInstance = rootInvokerPortletInstance.getPortletInstance(); PortletConfig portletConfig = PortletConfigFactoryUtil.create( portlet, servletContext); PortletContext portletContext = portletConfig.getPortletContext(); boolean checkAuthToken = rootInvokerPortletInstance.isCheckAuthToken(); boolean facesPortlet = rootInvokerPortletInstance.isFacesPortlet(); boolean strutsPortlet = rootInvokerPortletInstance.isStrutsPortlet(); boolean strutsBridgePortlet = rootInvokerPortletInstance.isStrutsBridgePortlet(); InvokerPortlet instanceInvokerPortletInstance = _invokerPortletFactory.create( portlet, portletInstance, portletConfig, portletContext, (InvokerFilterContainer)rootInvokerPortletInstance, checkAuthToken, facesPortlet, strutsPortlet, strutsBridgePortlet); if (deployed) { portletInstances.put( portlet.getPortletId(), instanceInvokerPortletInstance); } return instanceInvokerPortletInstance; } @Override public void delete(Portlet portlet) { if (PortletConstants.hasInstanceId(portlet.getPortletId())) { Map<String, InvokerPortlet> portletInstances = _pool.get( portlet.getRootPortletId()); if (portletInstances != null) { portletInstances.remove(portlet.getPortletId()); } } } public void destroy() { // LPS-10473 _serviceTracker.close(); } @Override public void destroy(Portlet portlet) { clear(portlet); destroyRelated(portlet); PortletLocalServiceUtil.destroyPortlet(portlet); } public void setDefaultInvokerPortletFactory( InvokerPortletFactory defaultInvokerPortletFactory) { _defaultInvokerPortletFactory = defaultInvokerPortletFactory; _invokerPortletFactory = defaultInvokerPortletFactory; } protected void destroyRelated(Portlet portlet) { PortletConfigFactoryUtil.destroy(portlet); PortletContextFactoryUtil.destroy(portlet); } protected InvokerPortlet init( Portlet portlet, PortletConfig portletConfig, javax.portlet.Portlet portletInstance) throws PortletException { PortletContext portletContext = portletConfig.getPortletContext(); InvokerFilterContainer invokerFilterContainer = InvokerFilterContainerImpl.EMPTY_INVOKER_FILTER_CONTAINER; if (!portlet.isUndeployedPortlet()) { invokerFilterContainer = new InvokerFilterContainerImpl( portlet, portletContext); } InvokerPortlet invokerPortlet = _invokerPortletFactory.create( portlet, portletInstance, portletContext, invokerFilterContainer); invokerPortlet.init(portletConfig); return invokerPortlet; } private InvokerPortletFactory _defaultInvokerPortletFactory; private volatile InvokerPortletFactory _invokerPortletFactory; private final Map<String, Map<String, InvokerPortlet>> _pool = new ConcurrentHashMap<>(); private ServiceTracker<InvokerPortletFactory, InvokerPortletFactory> _serviceTracker; }