1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.deploy.hot;
24  
25  import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
26  import com.liferay.portal.job.Scheduler;
27  import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
28  import com.liferay.portal.kernel.deploy.hot.HotDeployException;
29  import com.liferay.portal.kernel.deploy.hot.HotDeployListener;
30  import com.liferay.portal.kernel.language.LanguageUtil;
31  import com.liferay.portal.kernel.lar.PortletDataHandler;
32  import com.liferay.portal.kernel.portlet.ConfigurationAction;
33  import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
34  import com.liferay.portal.kernel.portlet.PortletLayoutListener;
35  import com.liferay.portal.kernel.search.Indexer;
36  import com.liferay.portal.kernel.servlet.PortletServlet;
37  import com.liferay.portal.kernel.servlet.ServletContextProvider;
38  import com.liferay.portal.kernel.servlet.URLEncoder;
39  import com.liferay.portal.kernel.smtp.MessageListener;
40  import com.liferay.portal.kernel.util.ClassUtil;
41  import com.liferay.portal.kernel.util.GetterUtil;
42  import com.liferay.portal.kernel.util.LocaleUtil;
43  import com.liferay.portal.kernel.util.ObjectValuePair;
44  import com.liferay.portal.kernel.util.PropertiesUtil;
45  import com.liferay.portal.kernel.util.StringUtil;
46  import com.liferay.portal.kernel.util.Validator;
47  import com.liferay.portal.model.Portlet;
48  import com.liferay.portal.model.PortletCategory;
49  import com.liferay.portal.security.permission.ResourceActionsUtil;
50  import com.liferay.portal.service.PortletLocalServiceUtil;
51  import com.liferay.portal.service.ServiceComponentLocalServiceUtil;
52  import com.liferay.portal.servlet.PortletContextPool;
53  import com.liferay.portal.servlet.PortletContextWrapper;
54  import com.liferay.portal.smtp.SMTPServerUtil;
55  import com.liferay.portal.util.PortalInstances;
56  import com.liferay.portal.util.PortalUtil;
57  import com.liferay.portal.util.PropsUtil;
58  import com.liferay.portal.util.WebAppPool;
59  import com.liferay.portal.util.WebKeys;
60  import com.liferay.portlet.PortletInstanceFactory;
61  import com.liferay.portlet.PortletPreferencesSerializer;
62  import com.liferay.portlet.PortletResourceBundles;
63  import com.liferay.util.CollectionFactory;
64  import com.liferay.util.Http;
65  
66  import java.util.HashSet;
67  import java.util.Iterator;
68  import java.util.List;
69  import java.util.Locale;
70  import java.util.Map;
71  import java.util.MissingResourceException;
72  import java.util.Properties;
73  import java.util.ResourceBundle;
74  import java.util.Set;
75  
76  import javax.portlet.PreferencesValidator;
77  
78  import javax.servlet.ServletContext;
79  
80  import org.apache.commons.logging.Log;
81  import org.apache.commons.logging.LogFactory;
82  import org.apache.portals.bridges.struts.StrutsPortlet;
83  
84  /**
85   * <a href="PortletHotDeployListener.java.html"><b><i>View Source</i></b></a>
86   *
87   * @author Brian Wing Shun Chan
88   * @author Brian Myunghun Kim
89   * @author Ivica Cardic
90   *
91   */
92  public class PortletHotDeployListener implements HotDeployListener {
93  
94      public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
95          String servletContextName = null;
96  
97          try {
98  
99              // Servlet context
100 
101             ServletContext ctx = event.getServletContext();
102 
103             servletContextName = ctx.getServletContextName();
104 
105             if (_log.isDebugEnabled()) {
106                 _log.debug("Invoking deploy for " + servletContextName);
107             }
108 
109             // Company ids
110 
111             long[] companyIds = PortalInstances.getCompanyIds();
112 
113             // Initialize portlets
114 
115             String[] xmls = new String[] {
116                 Http.URLtoString(ctx.getResource(
117                     "/WEB-INF/" + PortalUtil.PORTLET_XML_FILE_NAME_STANDARD)),
118                 Http.URLtoString(ctx.getResource(
119                     "/WEB-INF/" + PortalUtil.PORTLET_XML_FILE_NAME_CUSTOM)),
120                 Http.URLtoString(ctx.getResource(
121                     "/WEB-INF/liferay-portlet.xml")),
122                 Http.URLtoString(ctx.getResource("/WEB-INF/web.xml"))
123             };
124 
125             if (xmls[0] == null) {
126                 return;
127             }
128 
129             if (_log.isInfoEnabled()) {
130                 _log.info("Registering portlets for " + servletContextName);
131             }
132 
133             List portlets = PortletLocalServiceUtil.initWAR(
134                 servletContextName, xmls, event.getPluginPackage());
135 
136             // Class loader
137 
138             ClassLoader portletClassLoader = event.getContextClassLoader();
139 
140             ctx.setAttribute(
141                 PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
142 
143             // Portlet context wrapper
144 
145             boolean strutsBridges = false;
146 
147             Iterator itr1 = portlets.iterator();
148 
149             while (itr1.hasNext()) {
150                 Portlet portlet = (Portlet)itr1.next();
151 
152                 Class portletClass = portletClassLoader.loadClass(
153                     portlet.getPortletClass());
154 
155                 javax.portlet.Portlet portletInstance =
156                     (javax.portlet.Portlet)portletClass.newInstance();
157 
158                 if (ClassUtil.isSubclass(portletClass,
159                     StrutsPortlet.class.getName())) {
160 
161                     strutsBridges = true;
162                 }
163 
164                 ConfigurationAction configurationActionInstance = null;
165 
166                 if (Validator.isNotNull(
167                         portlet.getConfigurationActionClass())) {
168 
169                     configurationActionInstance =
170                         (ConfigurationAction)portletClassLoader.loadClass(
171                             portlet.getConfigurationActionClass()).
172                                 newInstance();
173                 }
174 
175                 Indexer indexerInstance = null;
176 
177                 if (Validator.isNotNull(portlet.getIndexerClass())) {
178                     indexerInstance = (Indexer)portletClassLoader.loadClass(
179                         portlet.getIndexerClass()).newInstance();
180                 }
181 
182                 Scheduler schedulerInstance = null;
183 
184                 if (Validator.isNotNull(portlet.getSchedulerClass())) {
185                     schedulerInstance = (Scheduler)portletClassLoader.loadClass(
186                         portlet.getSchedulerClass()).newInstance();
187                 }
188 
189                 FriendlyURLMapper friendlyURLMapperInstance = null;
190 
191                 if (Validator.isNotNull(portlet.getFriendlyURLMapperClass())) {
192                     friendlyURLMapperInstance =
193                         (FriendlyURLMapper)portletClassLoader.loadClass(
194                             portlet.getFriendlyURLMapperClass()).newInstance();
195                 }
196 
197                 URLEncoder urlEncoderInstance = null;
198 
199                 if (Validator.isNotNull(portlet.getURLEncoderClass())) {
200                     urlEncoderInstance =
201                         (URLEncoder)portletClassLoader.loadClass(
202                             portlet.getURLEncoderClass()).newInstance();
203                 }
204 
205                 PortletDataHandler portletDataHandlerInstance = null;
206 
207                 if (Validator.isNotNull(portlet.getPortletDataHandlerClass())) {
208                     portletDataHandlerInstance =
209                         (PortletDataHandler)portletClassLoader.loadClass(
210                             portlet.getPortletDataHandlerClass()).newInstance();
211                 }
212 
213                 PortletLayoutListener portletLayoutListenerInstance = null;
214 
215                 if (Validator.isNotNull(
216                         portlet.getPortletLayoutListenerClass())) {
217 
218                     portletLayoutListenerInstance =
219                         (PortletLayoutListener)portletClassLoader.loadClass(
220                             portlet.getPortletLayoutListenerClass()).
221                                 newInstance();
222                 }
223 
224                 MessageListener smtpMessageListenerInstance = null;
225 
226                 if (Validator.isNotNull(
227                         portlet.getSmtpMessageListenerClass())) {
228 
229                     smtpMessageListenerInstance =
230                         (MessageListener)portletClassLoader.loadClass(
231                             portlet.getSmtpMessageListenerClass()).
232                                 newInstance();
233 
234                     SMTPServerUtil.addListener(smtpMessageListenerInstance);
235                 }
236 
237                 PreferencesValidator prefsValidatorInstance = null;
238 
239                 if (Validator.isNotNull(portlet.getPreferencesValidator())) {
240                     prefsValidatorInstance =
241                         (PreferencesValidator)portletClassLoader.loadClass(
242                             portlet.getPreferencesValidator()).newInstance();
243 
244                     try {
245                         if (GetterUtil.getBoolean(PropsUtil.get(
246                                 PropsUtil.PREFERENCE_VALIDATE_ON_STARTUP))) {
247 
248                             prefsValidatorInstance.validate(
249                                 PortletPreferencesSerializer.fromDefaultXML(
250                                     portlet.getDefaultPreferences()));
251                         }
252                     }
253                     catch (Exception e1) {
254                         _log.warn(
255                             "Portlet with the name " + portlet.getPortletId() +
256                                 " does not have valid default preferences");
257                     }
258                 }
259 
260                 Map resourceBundles = null;
261 
262                 if (Validator.isNotNull(portlet.getResourceBundle())) {
263                     resourceBundles = CollectionFactory.getHashMap();
264 
265                     Iterator itr2 = portlet.getSupportedLocales().iterator();
266 
267                     while (itr2.hasNext()) {
268                         String supportedLocale = (String)itr2.next();
269 
270                         Locale locale = LocaleUtil.fromLanguageId(
271                             supportedLocale);
272 
273                         try {
274                             ResourceBundle resourceBundle =
275                                 ResourceBundle.getBundle(
276                                     portlet.getResourceBundle(), locale,
277                                     portletClassLoader);
278 
279                             resourceBundles.put(
280                                 LocaleUtil.toLanguageId(locale),
281                                 resourceBundle);
282                         }
283                         catch (MissingResourceException mre) {
284                             _log.warn(mre.getMessage());
285                         }
286                     }
287                 }
288 
289                 Map customUserAttributes = CollectionFactory.getHashMap();
290 
291                 Iterator itr2 =
292                     portlet.getCustomUserAttributes().entrySet().iterator();
293 
294                 while (itr2.hasNext()) {
295                     Map.Entry entry = (Map.Entry)itr2.next();
296 
297                     String attrCustomClass = (String)entry.getValue();
298 
299                     customUserAttributes.put(
300                         attrCustomClass,
301                         portletClassLoader.loadClass(
302                             attrCustomClass).newInstance());
303                 }
304 
305                 PortletContextWrapper pcw = new PortletContextWrapper(
306                     portlet.getPortletId(), ctx, portletInstance,
307                     configurationActionInstance, indexerInstance,
308                     schedulerInstance, friendlyURLMapperInstance,
309                     urlEncoderInstance, portletDataHandlerInstance,
310                     portletLayoutListenerInstance,
311                     smtpMessageListenerInstance, prefsValidatorInstance,
312                     resourceBundles, customUserAttributes);
313 
314                 PortletContextPool.put(portlet.getPortletId(), pcw);
315             }
316 
317             // Struts bridges
318 
319             if (!strutsBridges) {
320                 strutsBridges = GetterUtil.getBoolean(
321                     ctx.getInitParameter("struts-bridges-context-provider"));
322             }
323 
324             if (strutsBridges) {
325                 ctx.setAttribute(
326                     ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
327                     new LiferayServletContextProvider());
328             }
329 
330             // Portlet display
331 
332             String xml = Http.URLtoString(ctx.getResource(
333                 "/WEB-INF/liferay-display.xml"));
334 
335             PortletCategory newPortletCategory =
336                 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
337 
338             for (int i = 0; i < companyIds.length; i++) {
339                 long companyId = companyIds[i];
340 
341                 PortletCategory portletCategory =
342                     (PortletCategory)WebAppPool.get(
343                         String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
344 
345                 if (portletCategory != null) {
346                     portletCategory.merge(newPortletCategory);
347                 }
348                 else {
349                     _log.error(
350                         "Unable to register portlet for company " + companyId +
351                             " because it does not exist");
352                 }
353             }
354 
355             // Portlet properties
356 
357             String portletPropsName = ctx.getInitParameter(
358                 "portlet_properties");
359 
360             if (Validator.isNotNull(portletPropsName)) {
361                 if (_log.isDebugEnabled()) {
362                     _log.debug(
363                         "Loading portlet properties " + portletPropsName);
364                 }
365 
366                 Properties portletProps = new Properties();
367 
368                 PropertiesUtil.load(
369                     portletProps,
370                     StringUtil.read(portletClassLoader, portletPropsName));
371 
372                 if (_log.isDebugEnabled()) {
373                     String portletPropsString = PropertiesUtil.list(
374                         portletProps);
375 
376                     _log.debug(portletPropsString);
377                 }
378 
379                 processProperties(
380                     servletContextName, portletClassLoader, portletProps);
381             }
382 
383             // Service builder properties
384 
385             processServiceBuilder(ctx, portletClassLoader);
386 
387             // Variables
388 
389             _vars.put(
390                 servletContextName, new ObjectValuePair(companyIds, portlets));
391 
392             if (_log.isInfoEnabled()) {
393                 _log.info(
394                     "Portlets for " + servletContextName +
395                         " registered successfully");
396             }
397         }
398         catch (Exception e2) {
399             throw new HotDeployException(
400                 "Error registering portlets for " + servletContextName, e2);
401         }
402     }
403 
404     public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
405         String servletContextName = null;
406 
407         try {
408             ServletContext ctx = event.getServletContext();
409 
410             servletContextName = ctx.getServletContextName();
411 
412             if (_log.isDebugEnabled()) {
413                 _log.debug("Invoking undeploy for " + servletContextName);
414             }
415 
416             ObjectValuePair ovp =
417                 (ObjectValuePair)_vars.remove(servletContextName);
418 
419             if (ovp == null) {
420                 return;
421             }
422 
423             long[] companyIds = (long[])ovp.getKey();
424             List portlets = (List)ovp.getValue();
425 
426             Set portletIds = new HashSet();
427 
428             if (portlets != null) {
429                 if (_log.isInfoEnabled()) {
430                     _log.info(
431                         "Unregistering portlets for " + servletContextName);
432                 }
433 
434                 Iterator itr = portlets.iterator();
435 
436                 while (itr.hasNext()) {
437                     Portlet portlet = (Portlet)itr.next();
438 
439                     SMTPServerUtil.deleteListener(
440                         portlet.getSmtpMessageListenerInstance());
441 
442                     PortletInstanceFactory.destroy(portlet);
443 
444                     portletIds.add(portlet.getPortletId());
445                 }
446             }
447 
448             if (portletIds.size() > 0) {
449                 for (int i = 0; i < companyIds.length; i++) {
450                     long companyId = companyIds[i];
451 
452                     PortletCategory portletCategory =
453                         (PortletCategory)WebAppPool.get(
454                             String.valueOf(companyId),
455                             WebKeys.PORTLET_CATEGORY);
456 
457                     portletCategory.separate(portletIds);
458                 }
459             }
460 
461             PortletResourceBundles.remove(servletContextName);
462 
463             if (_log.isInfoEnabled()) {
464                 _log.info(
465                     "Portlets for " + servletContextName +
466                         " unregistered successfully");
467             }
468         }
469         catch (Exception e) {
470             throw new HotDeployException(
471                 "Error unregistering portlets for " + servletContextName, e);
472         }
473     }
474 
475     protected void processProperties(
476             String servletContextName, ClassLoader portletClassLoader,
477             Properties portletProps)
478         throws Exception {
479 
480         String languageBundleName = portletProps.getProperty("language.bundle");
481 
482         if (Validator.isNotNull(languageBundleName)) {
483             Locale[] locales = LanguageUtil.getAvailableLocales();
484 
485             for (int i = 0; i < locales.length; i++) {
486                 ResourceBundle bundle = ResourceBundle.getBundle(
487                     languageBundleName, locales[i], portletClassLoader);
488 
489                 PortletResourceBundles.put(
490                     servletContextName, LocaleUtil.toLanguageId(locales[i]),
491                     bundle);
492             }
493         }
494 
495         String[] resourceActionConfigs = StringUtil.split(
496             portletProps.getProperty("resource.actions.configs"));
497 
498         for (int i = 0; i < resourceActionConfigs.length; i++) {
499             ResourceActionsUtil.read(
500                 servletContextName, portletClassLoader,
501                 resourceActionConfigs[i]);
502         }
503     }
504 
505     protected void processServiceBuilder(
506             ServletContext ctx, ClassLoader portletClassLoader)
507         throws Exception {
508 
509         if (portletClassLoader.getResourceAsStream(
510                 "portlet-service.properties") == null) {
511 
512             return;
513         }
514 
515         Properties serviceBuilderProps = new Properties();
516 
517         PropertiesUtil.load(
518             serviceBuilderProps,
519             StringUtil.read(portletClassLoader, "portlet-service.properties"));
520 
521         String buildNamespace = GetterUtil.getString(
522             serviceBuilderProps.getProperty("build.namespace"));
523         long buildNumber = GetterUtil.getLong(
524             serviceBuilderProps.getProperty("build.number"));
525         long buildDate = GetterUtil.getLong(
526             serviceBuilderProps.getProperty("build.date"));
527 
528         if (_log.isDebugEnabled()) {
529             _log.debug("Build namespace " + buildNamespace);
530             _log.debug("Build number " + buildNumber);
531             _log.debug("Build date " + buildDate);
532         }
533 
534         ServiceComponentLocalServiceUtil.updateServiceComponent(
535             ctx, portletClassLoader, buildNamespace, buildNumber, buildDate);
536     }
537 
538     private static Log _log = LogFactory.getLog(PortletHotDeployListener.class);
539 
540     private static Map _vars = CollectionFactory.getHashMap();
541 
542 }