001    /**
002     * Copyright (c) 2000-2011 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.deploy.hot;
016    
017    import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
018    import com.liferay.portal.kernel.configuration.Configuration;
019    import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
020    import com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener;
021    import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
022    import com.liferay.portal.kernel.deploy.hot.HotDeployException;
023    import com.liferay.portal.kernel.language.LanguageUtil;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.portlet.PortletBag;
027    import com.liferay.portal.kernel.scheduler.SchedulerEngineUtil;
028    import com.liferay.portal.kernel.scheduler.SchedulerEntry;
029    import com.liferay.portal.kernel.search.Indexer;
030    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
031    import com.liferay.portal.kernel.servlet.PortletServlet;
032    import com.liferay.portal.kernel.servlet.ServletContextProvider;
033    import com.liferay.portal.kernel.util.ClassUtil;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.HttpUtil;
036    import com.liferay.portal.kernel.util.LocaleUtil;
037    import com.liferay.portal.kernel.util.ObjectValuePair;
038    import com.liferay.portal.kernel.util.StringUtil;
039    import com.liferay.portal.kernel.util.Validator;
040    import com.liferay.portal.kernel.webdav.WebDAVUtil;
041    import com.liferay.portal.kernel.workflow.WorkflowHandler;
042    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
043    import com.liferay.portal.model.Portlet;
044    import com.liferay.portal.model.PortletApp;
045    import com.liferay.portal.model.PortletCategory;
046    import com.liferay.portal.model.PortletFilter;
047    import com.liferay.portal.model.PortletURLListener;
048    import com.liferay.portal.poller.PollerProcessorUtil;
049    import com.liferay.portal.pop.POPServerUtil;
050    import com.liferay.portal.security.permission.ResourceActionsUtil;
051    import com.liferay.portal.service.PortletLocalServiceUtil;
052    import com.liferay.portal.service.ResourceActionLocalServiceUtil;
053    import com.liferay.portal.service.ResourceCodeLocalServiceUtil;
054    import com.liferay.portal.util.Portal;
055    import com.liferay.portal.util.PortalInstances;
056    import com.liferay.portal.util.PropsValues;
057    import com.liferay.portal.util.WebAppPool;
058    import com.liferay.portal.util.WebKeys;
059    import com.liferay.portal.xmlrpc.XmlRpcServlet;
060    import com.liferay.portlet.CustomUserAttributes;
061    import com.liferay.portlet.InvokerPortlet;
062    import com.liferay.portlet.PortletBagFactory;
063    import com.liferay.portlet.PortletContextBag;
064    import com.liferay.portlet.PortletContextBagPool;
065    import com.liferay.portlet.PortletFilterFactory;
066    import com.liferay.portlet.PortletInstanceFactoryUtil;
067    import com.liferay.portlet.PortletResourceBundles;
068    import com.liferay.portlet.PortletURLListenerFactory;
069    import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
070    import com.liferay.portlet.asset.model.AssetRendererFactory;
071    import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
072    import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
073    import com.liferay.util.log4j.Log4JUtil;
074    
075    import java.util.HashMap;
076    import java.util.HashSet;
077    import java.util.Iterator;
078    import java.util.List;
079    import java.util.Locale;
080    import java.util.Map;
081    import java.util.Properties;
082    import java.util.ResourceBundle;
083    import java.util.Set;
084    
085    import javax.portlet.PortletURLGenerationListener;
086    
087    import javax.servlet.ServletContext;
088    
089    import org.apache.portals.bridges.struts.StrutsPortlet;
090    
091    /**
092     * @author Brian Wing Shun Chan
093     * @author Brian Myunghun Kim
094     * @author Ivica Cardic
095     * @author Raymond Augé
096     */
097    public class PortletHotDeployListener extends BaseHotDeployListener {
098    
099            public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
100                    try {
101                            doInvokeDeploy(event);
102                    }
103                    catch (Throwable t) {
104                            throwHotDeployException(
105                                    event, "Error registering portlets for ", t);
106                    }
107            }
108    
109            public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
110                    try {
111                            doInvokeUndeploy(event);
112                    }
113                    catch (Throwable t) {
114                            throwHotDeployException(
115                                    event, "Error unregistering portlets for ", t);
116                    }
117            }
118    
119            protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
120                    throws Exception {
121    
122                    PortletApp portletApp = portlet.getPortletApp();
123    
124                    Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
125    
126                    for (PortletFilter portletFilter : portletFilters) {
127                            PortletFilterFactory.destroy(portletFilter);
128                    }
129    
130                    Set<PortletURLListener> portletURLListeners =
131                            portletApp.getPortletURLListeners();
132    
133                    for (PortletURLListener portletURLListener : portletURLListeners) {
134                            PortletURLListenerFactory.destroy(portletURLListener);
135                    }
136    
137                    Indexer indexer = portlet.getIndexerInstance();
138    
139                    if (indexer != null) {
140                            IndexerRegistryUtil.unregister(indexer);
141                    }
142    
143                    if (PropsValues.SCHEDULER_ENABLED){
144                            List<SchedulerEntry> schedulerEntries =
145                                    portlet.getSchedulerEntries();
146    
147                            if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) {
148                                    for (SchedulerEntry schedulerEntry : schedulerEntries) {
149                                            SchedulerEngineUtil.unschedule(schedulerEntry);
150                                    }
151                            }
152                    }
153    
154                    PollerProcessorUtil.deletePollerProcessor(portlet.getPortletId());
155    
156                    POPServerUtil.deleteListener(portlet.getPopMessageListenerInstance());
157    
158                    SocialActivityInterpreterLocalServiceUtil.deleteActivityInterpreter(
159                            portlet.getSocialActivityInterpreterInstance());
160    
161                    SocialRequestInterpreterLocalServiceUtil.deleteRequestInterpreter(
162                            portlet.getSocialRequestInterpreterInstance());
163    
164                    WebDAVUtil.deleteStorage(portlet.getWebDAVStorageInstance());
165    
166                    XmlRpcServlet.unregisterMethod(portlet.getXmlRpcMethodInstance());
167    
168                    List<AssetRendererFactory> assetRendererFactories =
169                            portlet.getAssetRendererFactoryInstances();
170    
171                    if (assetRendererFactories != null) {
172                            AssetRendererFactoryRegistryUtil.unregister(assetRendererFactories);
173                    }
174    
175                    List<WorkflowHandler> workflowHandlers =
176                            portlet.getWorkflowHandlerInstances();
177    
178                    if (workflowHandlers != null) {
179                            WorkflowHandlerRegistryUtil.unregister(workflowHandlers);
180                    }
181    
182                    PortletInstanceFactoryUtil.destroy(portlet);
183    
184                    portletIds.add(portlet.getPortletId());
185            }
186    
187            protected void doInvokeDeploy(HotDeployEvent event) throws Exception {
188    
189                    // Servlet context
190    
191                    ServletContext servletContext = event.getServletContext();
192    
193                    String servletContextName = servletContext.getServletContextName();
194    
195                    if (_log.isDebugEnabled()) {
196                            _log.debug("Invoking deploy for " + servletContextName);
197                    }
198    
199                    // Company ids
200    
201                    long[] companyIds = PortalInstances.getCompanyIds();
202    
203                    // Initialize portlets
204    
205                    String[] xmls = new String[] {
206                            HttpUtil.URLtoString(servletContext.getResource(
207                                    "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
208                            HttpUtil.URLtoString(servletContext.getResource(
209                                    "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
210                            HttpUtil.URLtoString(servletContext.getResource(
211                                    "/WEB-INF/liferay-portlet.xml")),
212                            HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
213                    };
214    
215                    if (xmls[0] == null) {
216                            return;
217                    }
218    
219                    if (_log.isInfoEnabled()) {
220                            _log.info("Registering portlets for " + servletContextName);
221                    }
222    
223                    List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
224                            servletContextName, servletContext, xmls, event.getPluginPackage());
225    
226                    // Class loader
227    
228                    ClassLoader portletClassLoader = event.getContextClassLoader();
229    
230                    servletContext.setAttribute(
231                            PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
232    
233                    // Logger
234    
235                    initLogger(portletClassLoader);
236    
237                    // Portlet context wrapper
238    
239                    _portletAppInitialized = false;
240                    _strutsBridges = false;
241    
242                    PortletBagFactory portletBagFactory = new PortletBagFactory();
243    
244                    portletBagFactory.setClassLoader(portletClassLoader);
245                    portletBagFactory.setServletContext(servletContext);
246                    portletBagFactory.setWARFile(true);
247    
248                    Iterator<Portlet> itr = portlets.iterator();
249    
250                    while (itr.hasNext()) {
251                            Portlet portlet = itr.next();
252    
253                            PortletBag portletBag = initPortlet(portlet, portletBagFactory);
254    
255                            if (portletBag == null) {
256                                    itr.remove();
257                            }
258                            else {
259                                    if (!_portletAppInitialized) {
260                                            initPortletApp(
261                                                    portlet, servletContextName, servletContext,
262                                                    portletClassLoader);
263    
264                                            _portletAppInitialized = true;
265                                    }
266                            }
267                    }
268    
269                    // Struts bridges
270    
271                    if (!_strutsBridges) {
272                            _strutsBridges = GetterUtil.getBoolean(
273                                    servletContext.getInitParameter(
274                                            "struts-bridges-context-provider"));
275                    }
276    
277                    if (_strutsBridges) {
278                            servletContext.setAttribute(
279                                    ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
280                                    new LiferayServletContextProvider());
281                    }
282    
283                    // Portlet display
284    
285                    String xml = HttpUtil.URLtoString(servletContext.getResource(
286                            "/WEB-INF/liferay-display.xml"));
287    
288                    PortletCategory newPortletCategory =
289                            PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
290    
291                    for (int i = 0; i < companyIds.length; i++) {
292                            long companyId = companyIds[i];
293    
294                            PortletCategory portletCategory =
295                                    (PortletCategory)WebAppPool.get(
296                                            String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
297    
298                            if (portletCategory != null) {
299                                    portletCategory.merge(newPortletCategory);
300                            }
301                            else {
302                                    _log.error(
303                                            "Unable to register portlet for company " + companyId +
304                                                    " because it does not exist");
305                            }
306                    }
307    
308                    // Portlet properties
309    
310                    processPortletProperties(servletContextName, portletClassLoader);
311    
312                    // Resource actions, resource codes, and check
313    
314                    itr = portlets.iterator();
315    
316                    while (itr.hasNext()) {
317                            Portlet portlet = itr.next();
318    
319                            List<String> modelNames =
320                                    ResourceActionsUtil.getPortletModelResources(
321                                            portlet.getPortletId());
322    
323                            for (long companyId : companyIds) {
324                                    ResourceCodeLocalServiceUtil.checkResourceCodes(
325                                            companyId, portlet.getPortletId());
326    
327                                    for (String modelName : modelNames) {
328                                            ResourceCodeLocalServiceUtil.checkResourceCodes(
329                                                    companyId, modelName);
330                                    }
331                            }
332    
333                            List<String> portletActions =
334                                    ResourceActionsUtil.getPortletResourceActions(
335                                            portlet.getPortletId());
336    
337                            ResourceActionLocalServiceUtil.checkResourceActions(
338                                    portlet.getPortletId(), portletActions);
339    
340                            for (String modelName : modelNames) {
341                                    List<String> modelActions =
342                                            ResourceActionsUtil.getModelResourceActions(modelName);
343    
344                                    ResourceActionLocalServiceUtil.checkResourceActions(
345                                            modelName, modelActions);
346                            }
347    
348                            for (long companyId : companyIds) {
349                                    Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
350                                            companyId, portlet.getPortletId());
351    
352                                    PortletLocalServiceUtil.checkPortlet(curPortlet);
353                            }
354                    }
355    
356                    // ClpMessageListener
357    
358                    registerClpMessageListeners(servletContext, portletClassLoader);
359    
360                    // Variables
361    
362                    _vars.put(
363                            servletContextName,
364                            new ObjectValuePair<long[], List<Portlet>>(
365                                    companyIds, portlets));
366    
367                    if (_log.isInfoEnabled()) {
368                            if (portlets.size() == 1) {
369                                    _log.info(
370                                            "1 portlet for " + servletContextName +
371                                                    " is available for use");
372                            }
373                            else {
374                                    _log.info(
375                                            portlets.size() + " portlets for " + servletContextName +
376                                                    " are available for use");
377                            }
378                    }
379            }
380    
381            protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
382                    ServletContext servletContext = event.getServletContext();
383    
384                    String servletContextName = servletContext.getServletContextName();
385    
386                    if (_log.isDebugEnabled()) {
387                            _log.debug("Invoking undeploy for " + servletContextName);
388                    }
389    
390                    ObjectValuePair<long[], List<Portlet>> ovp =
391                            _vars.remove(servletContextName);
392    
393                    if (ovp == null) {
394                            return;
395                    }
396    
397                    long[] companyIds = ovp.getKey();
398                    List<Portlet> portlets = ovp.getValue();
399    
400                    Set<String> portletIds = new HashSet<String>();
401    
402                    if (portlets != null) {
403                            if (_log.isInfoEnabled()) {
404                                    _log.info(
405                                            "Unregistering portlets for " + servletContextName);
406                            }
407    
408                            Iterator<Portlet> itr = portlets.iterator();
409    
410                            while (itr.hasNext()) {
411                                    Portlet portlet = itr.next();
412    
413                                    destroyPortlet(portlet, portletIds);
414                            }
415                    }
416    
417                    if (portletIds.size() > 0) {
418                            for (int i = 0; i < companyIds.length; i++) {
419                                    long companyId = companyIds[i];
420    
421                                    PortletCategory portletCategory =
422                                            (PortletCategory)WebAppPool.get(
423                                                    String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
424    
425                                    portletCategory.separate(portletIds);
426                            }
427                    }
428    
429                    PortletResourceBundles.remove(servletContextName);
430    
431                    unregisterClpMessageListeners(servletContext);
432    
433                    if (_log.isInfoEnabled()) {
434                            if (portlets.size() == 1) {
435                                    _log.info(
436                                            "1 portlet for " + servletContextName +
437                                                    " was unregistered");
438                            }
439                            else {
440                                    _log.info(
441                                            portlets.size() + " portlets for " + servletContextName +
442                                                    " was unregistered");
443                            }
444                    }
445            }
446    
447            protected void initLogger(ClassLoader portletClassLoader) {
448                    Log4JUtil.configureLog4J(
449                            portletClassLoader.getResource("META-INF/portal-log4j.xml"));
450            }
451    
452            protected PortletBag initPortlet(
453                            Portlet portlet, PortletBagFactory portletBagFactory)
454                    throws Exception {
455    
456                    PortletBag portletBag = portletBagFactory.create(portlet);
457    
458                    if (portletBag == null) {
459                            return null;
460                    }
461    
462                    javax.portlet.Portlet portletInstance = portletBag.getPortletInstance();
463    
464                    if (ClassUtil.isSubclass(
465                                    portletInstance.getClass(), StrutsPortlet.class.getName())) {
466    
467                            _strutsBridges = true;
468                    }
469    
470                    return portletBag;
471            }
472    
473            protected void initPortletApp(
474                            Portlet portlet, String servletContextName,
475                            ServletContext servletContext, ClassLoader portletClassLoader)
476                    throws Exception {
477    
478                    PortletContextBag portletContextBag = new PortletContextBag(
479                            servletContextName);
480    
481                    PortletContextBagPool.put(servletContextName, portletContextBag);
482    
483                    PortletApp portletApp = portlet.getPortletApp();
484    
485                    servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
486    
487                    Map<String, String> customUserAttributes =
488                            portletApp.getCustomUserAttributes();
489    
490                    for (Map.Entry<String, String> entry :
491                                    customUserAttributes.entrySet()) {
492    
493                            String attrCustomClass = entry.getValue();
494    
495                            CustomUserAttributes customUserAttributesInstance =
496                                    (CustomUserAttributes)portletClassLoader.loadClass(
497                                            attrCustomClass).newInstance();
498    
499                            portletContextBag.getCustomUserAttributes().put(
500                                    attrCustomClass, customUserAttributesInstance);
501                    }
502    
503                    Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
504    
505                    for (PortletFilter portletFilter : portletFilters) {
506                            javax.portlet.filter.PortletFilter portletFilterInstance =
507                                    (javax.portlet.filter.PortletFilter)newInstance(
508                                            portletClassLoader,
509                                            new Class<?>[] {
510                                                    javax.portlet.filter.ActionFilter.class,
511                                                    javax.portlet.filter.EventFilter.class,
512                                                    javax.portlet.filter.PortletFilter.class,
513                                                    javax.portlet.filter.RenderFilter.class,
514                                                    javax.portlet.filter.ResourceFilter.class
515                                            },
516                                            portletFilter.getFilterClass());
517    
518                            portletContextBag.getPortletFilters().put(
519                                    portletFilter.getFilterName(), portletFilterInstance);
520                    }
521    
522                    InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
523                            portlet, servletContext);
524    
525                    invokerPortlet.setPortletFilters();
526    
527                    Set<PortletURLListener> portletURLListeners =
528                            portletApp.getPortletURLListeners();
529    
530                    for (PortletURLListener portletURLListener : portletURLListeners) {
531                            PortletURLGenerationListener portletURLListenerInstance =
532                                    (PortletURLGenerationListener)newInstance(
533                                            portletClassLoader, PortletURLGenerationListener.class,
534                                            portletURLListener.getListenerClass());
535    
536                            portletContextBag.getPortletURLListeners().put(
537                                    portletURLListener.getListenerClass(),
538                                    portletURLListenerInstance);
539    
540                            PortletURLListenerFactory.create(portletURLListener);
541                    }
542            }
543    
544            protected void processPortletProperties(
545                            String servletContextName, ClassLoader portletClassLoader)
546                    throws Exception {
547    
548                    Configuration portletPropertiesConfiguration = null;
549    
550                    try {
551                            portletPropertiesConfiguration =
552                                    ConfigurationFactoryUtil.getConfiguration(
553                                            portletClassLoader, "portlet");
554                    }
555                    catch (Exception e) {
556                            if (_log.isDebugEnabled()) {
557                                    _log.debug("Unable to read portlet.properties");
558                            }
559    
560                            return;
561                    }
562    
563                    Properties portletProperties =
564                            portletPropertiesConfiguration.getProperties();
565    
566                    if (portletProperties.size() == 0) {
567                            return;
568                    }
569    
570                    String languageBundleName = portletProperties.getProperty(
571                            "language.bundle");
572    
573                    if (Validator.isNotNull(languageBundleName)) {
574                            Locale[] locales = LanguageUtil.getAvailableLocales();
575    
576                            for (int i = 0; i < locales.length; i++) {
577                                    ResourceBundle resourceBundle = ResourceBundle.getBundle(
578                                            languageBundleName, locales[i], portletClassLoader);
579    
580                                    PortletResourceBundles.put(
581                                            servletContextName, LocaleUtil.toLanguageId(locales[i]),
582                                            resourceBundle);
583                            }
584                    }
585    
586                    String[] resourceActionConfigs = StringUtil.split(
587                            portletProperties.getProperty("resource.actions.configs"));
588    
589                    for (int i = 0; i < resourceActionConfigs.length; i++) {
590                            ResourceActionsUtil.read(
591                                    servletContextName, portletClassLoader,
592                                    resourceActionConfigs[i]);
593                    }
594            }
595    
596            private static Log _log = LogFactoryUtil.getLog(
597                    PortletHotDeployListener.class);
598    
599            private static Map<String, ObjectValuePair<long[], List<Portlet>>> _vars =
600                    new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
601    
602            private boolean _portletAppInitialized;
603            private boolean _strutsBridges;
604    
605    }