001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                    // Ready
357    
358                    for (Portlet portlet : portlets) {
359                            boolean ready = GetterUtil.getBoolean(
360                                    servletContext.getInitParameter(
361                                            "portlets-ready-by-default"), true);
362    
363                            portlet.setReady(ready);
364                    }
365    
366                    // ClpMessageListener
367    
368                    registerClpMessageListeners(servletContext, portletClassLoader);
369    
370                    // Variables
371    
372                    _vars.put(
373                            servletContextName,
374                            new ObjectValuePair<long[], List<Portlet>>(
375                                    companyIds, portlets));
376    
377                    if (_log.isInfoEnabled()) {
378                            if (portlets.size() == 1) {
379                                    _log.info(
380                                            "1 portlet for " + servletContextName +
381                                                    " is available for use");
382                            }
383                            else {
384                                    _log.info(
385                                            portlets.size() + " portlets for " + servletContextName +
386                                                    " are available for use");
387                            }
388                    }
389            }
390    
391            protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
392                    ServletContext servletContext = event.getServletContext();
393    
394                    String servletContextName = servletContext.getServletContextName();
395    
396                    if (_log.isDebugEnabled()) {
397                            _log.debug("Invoking undeploy for " + servletContextName);
398                    }
399    
400                    ObjectValuePair<long[], List<Portlet>> ovp =
401                            _vars.remove(servletContextName);
402    
403                    if (ovp == null) {
404                            return;
405                    }
406    
407                    long[] companyIds = ovp.getKey();
408                    List<Portlet> portlets = ovp.getValue();
409    
410                    Set<String> portletIds = new HashSet<String>();
411    
412                    if (portlets != null) {
413                            if (_log.isInfoEnabled()) {
414                                    _log.info(
415                                            "Unregistering portlets for " + servletContextName);
416                            }
417    
418                            Iterator<Portlet> itr = portlets.iterator();
419    
420                            while (itr.hasNext()) {
421                                    Portlet portlet = itr.next();
422    
423                                    destroyPortlet(portlet, portletIds);
424                            }
425                    }
426    
427                    if (portletIds.size() > 0) {
428                            for (int i = 0; i < companyIds.length; i++) {
429                                    long companyId = companyIds[i];
430    
431                                    PortletCategory portletCategory =
432                                            (PortletCategory)WebAppPool.get(
433                                                    String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
434    
435                                    portletCategory.separate(portletIds);
436                            }
437                    }
438    
439                    PortletResourceBundles.remove(servletContextName);
440    
441                    unregisterClpMessageListeners(servletContext);
442    
443                    if (_log.isInfoEnabled()) {
444                            if (portlets.size() == 1) {
445                                    _log.info(
446                                            "1 portlet for " + servletContextName +
447                                                    " was unregistered");
448                            }
449                            else {
450                                    _log.info(
451                                            portlets.size() + " portlets for " + servletContextName +
452                                                    " was unregistered");
453                            }
454                    }
455            }
456    
457            protected void initLogger(ClassLoader portletClassLoader) {
458                    Log4JUtil.configureLog4J(
459                            portletClassLoader.getResource("META-INF/portal-log4j.xml"));
460            }
461    
462            protected PortletBag initPortlet(
463                            Portlet portlet, PortletBagFactory portletBagFactory)
464                    throws Exception {
465    
466                    PortletBag portletBag = portletBagFactory.create(portlet);
467    
468                    if (portletBag == null) {
469                            return null;
470                    }
471    
472                    javax.portlet.Portlet portletInstance = portletBag.getPortletInstance();
473    
474                    if (ClassUtil.isSubclass(
475                                    portletInstance.getClass(), StrutsPortlet.class.getName())) {
476    
477                            _strutsBridges = true;
478                    }
479    
480                    return portletBag;
481            }
482    
483            protected void initPortletApp(
484                            Portlet portlet, String servletContextName,
485                            ServletContext servletContext, ClassLoader portletClassLoader)
486                    throws Exception {
487    
488                    PortletContextBag portletContextBag = new PortletContextBag(
489                            servletContextName);
490    
491                    PortletContextBagPool.put(servletContextName, portletContextBag);
492    
493                    PortletApp portletApp = portlet.getPortletApp();
494    
495                    servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
496    
497                    Map<String, String> customUserAttributes =
498                            portletApp.getCustomUserAttributes();
499    
500                    for (Map.Entry<String, String> entry :
501                                    customUserAttributes.entrySet()) {
502    
503                            String attrCustomClass = entry.getValue();
504    
505                            CustomUserAttributes customUserAttributesInstance =
506                                    (CustomUserAttributes)portletClassLoader.loadClass(
507                                            attrCustomClass).newInstance();
508    
509                            portletContextBag.getCustomUserAttributes().put(
510                                    attrCustomClass, customUserAttributesInstance);
511                    }
512    
513                    Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
514    
515                    for (PortletFilter portletFilter : portletFilters) {
516                            javax.portlet.filter.PortletFilter portletFilterInstance =
517                                    (javax.portlet.filter.PortletFilter)newInstance(
518                                            portletClassLoader,
519                                            new Class<?>[] {
520                                                    javax.portlet.filter.ActionFilter.class,
521                                                    javax.portlet.filter.EventFilter.class,
522                                                    javax.portlet.filter.PortletFilter.class,
523                                                    javax.portlet.filter.RenderFilter.class,
524                                                    javax.portlet.filter.ResourceFilter.class
525                                            },
526                                            portletFilter.getFilterClass());
527    
528                            portletContextBag.getPortletFilters().put(
529                                    portletFilter.getFilterName(), portletFilterInstance);
530                    }
531    
532                    InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
533                            portlet, servletContext);
534    
535                    invokerPortlet.setPortletFilters();
536    
537                    Set<PortletURLListener> portletURLListeners =
538                            portletApp.getPortletURLListeners();
539    
540                    for (PortletURLListener portletURLListener : portletURLListeners) {
541                            PortletURLGenerationListener portletURLListenerInstance =
542                                    (PortletURLGenerationListener)newInstance(
543                                            portletClassLoader, PortletURLGenerationListener.class,
544                                            portletURLListener.getListenerClass());
545    
546                            portletContextBag.getPortletURLListeners().put(
547                                    portletURLListener.getListenerClass(),
548                                    portletURLListenerInstance);
549    
550                            PortletURLListenerFactory.create(portletURLListener);
551                    }
552            }
553    
554            protected void processPortletProperties(
555                            String servletContextName, ClassLoader portletClassLoader)
556                    throws Exception {
557    
558                    Configuration portletPropertiesConfiguration = null;
559    
560                    try {
561                            portletPropertiesConfiguration =
562                                    ConfigurationFactoryUtil.getConfiguration(
563                                            portletClassLoader, "portlet");
564                    }
565                    catch (Exception e) {
566                            if (_log.isDebugEnabled()) {
567                                    _log.debug("Unable to read portlet.properties");
568                            }
569    
570                            return;
571                    }
572    
573                    Properties portletProperties =
574                            portletPropertiesConfiguration.getProperties();
575    
576                    if (portletProperties.size() == 0) {
577                            return;
578                    }
579    
580                    String languageBundleName = portletProperties.getProperty(
581                            "language.bundle");
582    
583                    if (Validator.isNotNull(languageBundleName)) {
584                            Locale[] locales = LanguageUtil.getAvailableLocales();
585    
586                            for (int i = 0; i < locales.length; i++) {
587                                    ResourceBundle resourceBundle = ResourceBundle.getBundle(
588                                            languageBundleName, locales[i], portletClassLoader);
589    
590                                    PortletResourceBundles.put(
591                                            servletContextName, LocaleUtil.toLanguageId(locales[i]),
592                                            resourceBundle);
593                            }
594                    }
595    
596                    String[] resourceActionConfigs = StringUtil.split(
597                            portletProperties.getProperty("resource.actions.configs"));
598    
599                    for (int i = 0; i < resourceActionConfigs.length; i++) {
600                            ResourceActionsUtil.read(
601                                    servletContextName, portletClassLoader,
602                                    resourceActionConfigs[i]);
603                    }
604            }
605    
606            private static Log _log = LogFactoryUtil.getLog(
607                    PortletHotDeployListener.class);
608    
609            private static Map<String, ObjectValuePair<long[], List<Portlet>>> _vars =
610                    new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
611    
612            private boolean _portletAppInitialized;
613            private boolean _strutsBridges;
614    
615    }