1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet;
16  
17  import com.liferay.portal.dao.shard.ShardPollerProcessorWrapper;
18  import com.liferay.portal.kernel.lar.PortletDataHandler;
19  import com.liferay.portal.kernel.log.Log;
20  import com.liferay.portal.kernel.log.LogFactoryUtil;
21  import com.liferay.portal.kernel.poller.PollerProcessor;
22  import com.liferay.portal.kernel.pop.MessageListener;
23  import com.liferay.portal.kernel.portlet.ConfigurationAction;
24  import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
25  import com.liferay.portal.kernel.portlet.PortletBag;
26  import com.liferay.portal.kernel.portlet.PortletBagPool;
27  import com.liferay.portal.kernel.portlet.PortletLayoutListener;
28  import com.liferay.portal.kernel.portlet.Route;
29  import com.liferay.portal.kernel.portlet.Router;
30  import com.liferay.portal.kernel.scheduler.SchedulerEngineUtil;
31  import com.liferay.portal.kernel.scheduler.SchedulerEntry;
32  import com.liferay.portal.kernel.scheduler.SchedulerException;
33  import com.liferay.portal.kernel.search.Indexer;
34  import com.liferay.portal.kernel.search.IndexerRegistryUtil;
35  import com.liferay.portal.kernel.search.OpenSearch;
36  import com.liferay.portal.kernel.servlet.ServletContextPool;
37  import com.liferay.portal.kernel.servlet.URLEncoder;
38  import com.liferay.portal.kernel.util.LocaleUtil;
39  import com.liferay.portal.kernel.util.MethodInvoker;
40  import com.liferay.portal.kernel.util.MethodWrapper;
41  import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
42  import com.liferay.portal.kernel.util.PrefsPropsUtil;
43  import com.liferay.portal.kernel.util.ProxyFactory;
44  import com.liferay.portal.kernel.util.SetUtil;
45  import com.liferay.portal.kernel.util.StringUtil;
46  import com.liferay.portal.kernel.util.Validator;
47  import com.liferay.portal.kernel.webdav.WebDAVStorage;
48  import com.liferay.portal.kernel.webdav.WebDAVUtil;
49  import com.liferay.portal.kernel.workflow.WorkflowHandler;
50  import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
51  import com.liferay.portal.kernel.xml.Document;
52  import com.liferay.portal.kernel.xml.Element;
53  import com.liferay.portal.kernel.xml.SAXReaderUtil;
54  import com.liferay.portal.kernel.xmlrpc.Method;
55  import com.liferay.portal.model.Portlet;
56  import com.liferay.portal.model.PortletApp;
57  import com.liferay.portal.poller.PollerProcessorUtil;
58  import com.liferay.portal.pop.POPServerUtil;
59  import com.liferay.portal.service.PortletLocalServiceUtil;
60  import com.liferay.portal.util.PortalUtil;
61  import com.liferay.portal.util.PropsValues;
62  import com.liferay.portal.xmlrpc.XmlRpcServlet;
63  import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
64  import com.liferay.portlet.asset.model.AssetRendererFactory;
65  import com.liferay.portlet.expando.model.CustomAttributesDisplay;
66  import com.liferay.portlet.social.model.SocialActivityInterpreter;
67  import com.liferay.portlet.social.model.SocialRequestInterpreter;
68  import com.liferay.portlet.social.model.impl.SocialActivityInterpreterImpl;
69  import com.liferay.portlet.social.model.impl.SocialRequestInterpreterImpl;
70  import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
71  import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
72  import com.liferay.util.portlet.PortletProps;
73  
74  import java.util.ArrayList;
75  import java.util.HashMap;
76  import java.util.List;
77  import java.util.Locale;
78  import java.util.Map;
79  import java.util.MissingResourceException;
80  import java.util.ResourceBundle;
81  import java.util.Set;
82  
83  import javax.portlet.PreferencesValidator;
84  
85  import javax.servlet.ServletContext;
86  
87  /**
88   * <a href="PortletBagFactory.java.html"><b><i>View Source</i></b></a>
89   *
90   * @author Brian Wing Shun Chan
91   * @author Brian Myunghun Kim
92   * @author Ivica Cardic
93   * @author Raymond Augé
94   */
95  public class PortletBagFactory {
96  
97      public PortletBag create(Portlet portlet) throws Exception {
98          PortletApp portletApp = portlet.getPortletApp();
99  
100         if (!portletApp.isWARFile() && _warFile) {
101             String contextPath = PortalUtil.getPathContext();
102 
103             _servletContext = ServletContextPool.get(contextPath);
104 
105             _classLoader = PortalClassLoaderUtil.getClassLoader();
106         }
107 
108         Class<?> portletClass = null;
109 
110         try {
111             portletClass = _classLoader.loadClass(portlet.getPortletClass());
112         }
113         catch (Throwable e) {
114             _log.error(e, e);
115 
116             PortletLocalServiceUtil.destroyPortlet(portlet);
117 
118             return null;
119         }
120 
121         javax.portlet.Portlet portletInstance =
122             (javax.portlet.Portlet)portletClass.newInstance();
123 
124         ConfigurationAction configurationActionInstance =
125             newConfigurationAction(portlet);
126 
127         Indexer indexerInstance = newIndexer(portlet);
128 
129         OpenSearch openSearchInstance = newOpenSearch(portlet);
130 
131         initSchedulers(portlet);
132 
133         FriendlyURLMapper friendlyURLMapperInstance = newFriendlyURLMapper(
134             portlet);
135 
136         URLEncoder urlEncoderInstance = newURLEncoder(portlet);
137 
138         PortletDataHandler portletDataHandlerInstance = newPortletDataHandler(
139             portlet);
140 
141         PortletLayoutListener portletLayoutListenerInstance =
142             newPortletLayoutListener(portlet);
143 
144         PollerProcessor pollerProcessorInstance = newPollerProcessor(portlet);
145 
146         MessageListener popMessageListenerInstance = newPOPMessageListener(
147             portlet);
148 
149         SocialActivityInterpreter socialActivityInterpreterInstance =
150             initSocialActivityInterpreterInstance(portlet);
151 
152         SocialRequestInterpreter socialRequestInterpreterInstance = null;
153 
154         if (Validator.isNotNull(portlet.getSocialRequestInterpreterClass())) {
155             socialRequestInterpreterInstance =
156                 (SocialRequestInterpreter)newInstance(
157                     SocialRequestInterpreter.class,
158                     portlet.getSocialRequestInterpreterClass());
159 
160             socialRequestInterpreterInstance = new SocialRequestInterpreterImpl(
161                 portlet.getPortletId(), socialRequestInterpreterInstance);
162 
163             SocialRequestInterpreterLocalServiceUtil.addRequestInterpreter(
164                 socialRequestInterpreterInstance);
165         }
166 
167         WebDAVStorage webDAVStorageInstance = null;
168 
169         if (Validator.isNotNull(portlet.getWebDAVStorageClass())) {
170             webDAVStorageInstance = (WebDAVStorage)newInstance(
171                 WebDAVStorage.class, portlet.getWebDAVStorageClass());
172 
173             webDAVStorageInstance.setToken(portlet.getWebDAVStorageToken());
174 
175             WebDAVUtil.addStorage(webDAVStorageInstance);
176         }
177 
178         Method xmlRpcMethodInstance = null;
179 
180         if (Validator.isNotNull(portlet.getXmlRpcMethodClass())) {
181             xmlRpcMethodInstance = (Method)newInstance(
182                 Method.class, portlet.getXmlRpcMethodClass());
183 
184             XmlRpcServlet.registerMethod(xmlRpcMethodInstance);
185         }
186 
187         ControlPanelEntry controlPanelEntryInstance = null;
188 
189         if (Validator.isNotNull(portlet.getControlPanelEntryClass())) {
190             controlPanelEntryInstance = (ControlPanelEntry)newInstance(
191                 ControlPanelEntry.class, portlet.getControlPanelEntryClass());
192         }
193 
194         List<AssetRendererFactory> assetRendererFactoryInstances =
195             newAssetRendererFactoryInstances(portlet);
196 
197         List<CustomAttributesDisplay> customAttributesDisplayInstances =
198             new ArrayList<CustomAttributesDisplay>();
199 
200         for (String customAttributesDisplayClass :
201                 portlet.getCustomAttributesDisplayClasses()) {
202 
203             CustomAttributesDisplay customAttributesDisplayInstance =
204                 (CustomAttributesDisplay)newInstance(
205                     CustomAttributesDisplay.class,
206                     customAttributesDisplayClass);
207 
208             customAttributesDisplayInstance.setClassNameId(
209                 PortalUtil.getClassNameId(
210                     customAttributesDisplayInstance.getClassName()));
211             customAttributesDisplayInstance.setPortletId(
212                 portlet.getPortletId());
213 
214             customAttributesDisplayInstances.add(
215                 customAttributesDisplayInstance);
216         }
217 
218         List<WorkflowHandler> workflowHandlerInstances =
219             new ArrayList<WorkflowHandler>();
220 
221         for (String workflowHandlerClass :
222                 portlet.getWorkflowHandlerClasses()) {
223 
224             WorkflowHandler workflowHandlerInstance =
225                 (WorkflowHandler)newInstance(
226                     WorkflowHandler.class, workflowHandlerClass);
227 
228             workflowHandlerInstances.add(workflowHandlerInstance);
229 
230             WorkflowHandlerRegistryUtil.register(workflowHandlerInstance);
231         }
232 
233         PreferencesValidator preferencesValidatorInstance = null;
234 
235         if (Validator.isNotNull(portlet.getPreferencesValidator())) {
236             preferencesValidatorInstance = (PreferencesValidator)newInstance(
237                 PreferencesValidator.class, portlet.getPreferencesValidator());
238 
239             try {
240                 if (PropsValues.PREFERENCE_VALIDATE_ON_STARTUP) {
241                     preferencesValidatorInstance.validate(
242                         PortletPreferencesSerializer.fromDefaultXML(
243                             portlet.getDefaultPreferences()));
244                 }
245             }
246             catch (Exception e) {
247                 _log.warn(
248                     "Portlet with the name " + portlet.getPortletId() +
249                         " does not have valid default preferences");
250             }
251         }
252 
253         Map<String, ResourceBundle> resourceBundles = null;
254 
255         if (Validator.isNotNull(portlet.getResourceBundle())) {
256             resourceBundles = new HashMap<String, ResourceBundle>();
257 
258             initResourceBundle(
259                 resourceBundles, portlet, LocaleUtil.getDefault());
260 
261             Set<String> supportedLocales = portlet.getSupportedLocales();
262 
263             if (supportedLocales.isEmpty()) {
264                 supportedLocales = SetUtil.fromArray(PropsValues.LOCALES);
265             }
266 
267             for (String supportedLocale : supportedLocales) {
268                 Locale locale = LocaleUtil.fromLanguageId(supportedLocale);
269 
270                 initResourceBundle(resourceBundles, portlet, locale);
271             }
272         }
273 
274         PortletBag portletBag = new PortletBagImpl(
275             portlet.getPortletId(), _servletContext, portletInstance,
276             configurationActionInstance, indexerInstance, openSearchInstance,
277             friendlyURLMapperInstance, urlEncoderInstance,
278             portletDataHandlerInstance, portletLayoutListenerInstance,
279             pollerProcessorInstance, popMessageListenerInstance,
280             socialActivityInterpreterInstance, socialRequestInterpreterInstance,
281             webDAVStorageInstance, xmlRpcMethodInstance,
282             controlPanelEntryInstance, assetRendererFactoryInstances,
283             customAttributesDisplayInstances, workflowHandlerInstances,
284             preferencesValidatorInstance, resourceBundles);
285 
286         PortletBagPool.put(portlet.getPortletId(), portletBag);
287 
288         try {
289             PortletInstanceFactoryUtil.create(portlet, _servletContext);
290         }
291         catch (Exception e) {
292             _log.error(e, e);
293         }
294 
295         return portletBag;
296     }
297 
298     public void setClassLoader(ClassLoader classLoader) {
299         _classLoader = classLoader;
300     }
301 
302     public void setServletContext(ServletContext servletContext) {
303         _servletContext = servletContext;
304     }
305 
306     public void setWARFile(boolean warFile) {
307         _warFile = warFile;
308     }
309 
310     protected void initResourceBundle(
311         Map<String, ResourceBundle> resourceBundles, Portlet portlet,
312         Locale locale) {
313 
314         try {
315             ResourceBundle resourceBundle = ResourceBundle.getBundle(
316                 portlet.getResourceBundle(), locale, _classLoader);
317 
318             resourceBundles.put(
319                 LocaleUtil.toLanguageId(locale), resourceBundle);
320         }
321         catch (MissingResourceException mre) {
322             _log.warn(mre.getMessage());
323         }
324     }
325 
326     protected void initScheduler(SchedulerEntry schedulerEntry)
327         throws Exception {
328 
329         String propertyKey = schedulerEntry.getPropertyKey();
330 
331         if (Validator.isNotNull(propertyKey)) {
332             String triggerValue = null;
333 
334             if (_warFile) {
335                 Thread currentThread = Thread.currentThread();
336 
337                 ClassLoader contextClassLoader =
338                     currentThread.getContextClassLoader();
339 
340                 try {
341                     currentThread.setContextClassLoader(_classLoader);
342 
343                     MethodWrapper methodWrapper = new MethodWrapper(
344                         PortletProps.class.getName(), "get", propertyKey);
345 
346                     triggerValue = (String)MethodInvoker.invoke(
347                         methodWrapper, false);
348                 }
349                 finally {
350                     currentThread.setContextClassLoader(contextClassLoader);
351                 }
352             }
353             else {
354                 triggerValue = PrefsPropsUtil.getString(propertyKey);
355             }
356 
357             if (_log.isDebugEnabled()) {
358                 _log.debug(
359                     "Scheduler property key " + propertyKey +
360                         " has trigger value " + triggerValue);
361             }
362 
363             if (Validator.isNull(triggerValue)) {
364                 throw new SchedulerException(
365                     "Property key " + propertyKey + " requires a value");
366             }
367 
368             schedulerEntry.setTriggerValue(triggerValue);
369         }
370 
371         SchedulerEngineUtil.schedule(schedulerEntry, _classLoader);
372     }
373 
374     protected void initSchedulers(Portlet portlet) throws Exception {
375         if (!PropsValues.SCHEDULER_ENABLED){
376             return;
377         }
378 
379         List<SchedulerEntry> schedulerEntries = portlet.getSchedulerEntries();
380 
381         if ((schedulerEntries == null) || schedulerEntries.isEmpty()) {
382             return;
383         }
384 
385         for (SchedulerEntry schedulerEntry : schedulerEntries) {
386             initScheduler(schedulerEntry);
387         }
388     }
389 
390     protected SocialActivityInterpreter initSocialActivityInterpreterInstance(
391             Portlet portlet)
392         throws Exception {
393 
394         if (Validator.isNull(portlet.getSocialActivityInterpreterClass())) {
395             return null;
396         }
397 
398         SocialActivityInterpreter socialActivityInterpreterInstance =
399             (SocialActivityInterpreter)newInstance(
400                 SocialActivityInterpreter.class,
401                 portlet.getSocialActivityInterpreterClass());
402 
403         socialActivityInterpreterInstance =
404             new SocialActivityInterpreterImpl(
405                 portlet.getPortletId(), socialActivityInterpreterInstance);
406 
407         SocialActivityInterpreterLocalServiceUtil.addActivityInterpreter(
408             socialActivityInterpreterInstance);
409 
410         return socialActivityInterpreterInstance;
411     }
412 
413     protected AssetRendererFactory newAssetRendererFactoryInstance(
414             Portlet portlet, String assetRendererFactoryClass)
415         throws Exception {
416 
417         AssetRendererFactory assetRendererFactoryInstance =
418             (AssetRendererFactory)newInstance(
419                 AssetRendererFactory.class, assetRendererFactoryClass);
420 
421         assetRendererFactoryInstance.setClassNameId(
422             PortalUtil.getClassNameId(
423                 assetRendererFactoryInstance.getClassName()));
424         assetRendererFactoryInstance.setPortletId(portlet.getPortletId());
425 
426         AssetRendererFactoryRegistryUtil.register(assetRendererFactoryInstance);
427 
428         return assetRendererFactoryInstance;
429     }
430 
431     protected List<AssetRendererFactory> newAssetRendererFactoryInstances(
432             Portlet portlet)
433         throws Exception {
434 
435         List<AssetRendererFactory> assetRendererFactoryInstances =
436             new ArrayList<AssetRendererFactory>();
437 
438         for (String assetRendererFactoryClass :
439                 portlet.getAssetRendererFactoryClasses()) {
440 
441             AssetRendererFactory assetRendererFactoryInstance =
442                 newAssetRendererFactoryInstance(
443                     portlet, assetRendererFactoryClass);
444 
445             assetRendererFactoryInstances.add(assetRendererFactoryInstance);
446         }
447 
448         return assetRendererFactoryInstances;
449     }
450 
451     protected ConfigurationAction newConfigurationAction(Portlet portlet)
452         throws Exception {
453 
454         if (Validator.isNull(portlet.getConfigurationActionClass())) {
455             return null;
456         }
457 
458         return (ConfigurationAction)newInstance(
459             ConfigurationAction.class, portlet.getConfigurationActionClass());
460     }
461 
462     protected FriendlyURLMapper newFriendlyURLMapper(Portlet portlet)
463         throws Exception {
464 
465         if (Validator.isNull(portlet.getFriendlyURLMapperClass())) {
466             return null;
467         }
468 
469         FriendlyURLMapper friendlyURLMapper = (FriendlyURLMapper)newInstance(
470             FriendlyURLMapper.class, portlet.getFriendlyURLMapperClass());
471 
472         Router router = newFriendlyURLRouter(portlet);
473 
474         friendlyURLMapper.setRouter(router);
475 
476         return friendlyURLMapper;
477     }
478 
479     protected Router newFriendlyURLRouter(Portlet portlet) throws Exception {
480         if (Validator.isNull(portlet.getFriendlyURLRoutes())) {
481             return null;
482         }
483 
484         Router router = new RouterImpl();
485 
486         String xml = StringUtil.read(
487             _classLoader, portlet.getFriendlyURLRoutes());
488 
489         Document document = SAXReaderUtil.read(xml, true);
490 
491         Element rootElement = document.getRootElement();
492 
493         for (Element routeElement : rootElement.elements("route")) {
494             String pattern = routeElement.elementText("pattern");
495 
496             Route route = router.addRoute(pattern);
497 
498             for (Element defaultParameterElement :
499                     routeElement.elements("default-parameter")) {
500 
501                 String name = defaultParameterElement.attributeValue("name");
502                 String value = defaultParameterElement.getText();
503 
504                 route.addDefaultParameter(name, value);
505             }
506         }
507 
508         return router;
509     }
510 
511     protected Indexer newIndexer(Portlet portlet) throws Exception {
512         if (Validator.isNull(portlet.getIndexerClass())) {
513             return null;
514         }
515 
516         Indexer indexerInstance = (Indexer)newInstance(
517             Indexer.class, portlet.getIndexerClass());
518 
519         IndexerRegistryUtil.register(indexerInstance);
520 
521         return indexerInstance;
522     }
523 
524     protected Object newInstance(Class<?> interfaceClass, String implClassName)
525         throws Exception {
526 
527         return newInstance(new Class[] {interfaceClass}, implClassName);
528     }
529 
530     protected Object newInstance(
531             Class<?>[] interfaceClasses, String implClassName)
532         throws Exception {
533 
534         if (_warFile) {
535             return ProxyFactory.newInstance(
536                 _classLoader, interfaceClasses, implClassName);
537         }
538         else {
539             Class<?> classObj = _classLoader.loadClass(implClassName);
540 
541             return classObj.newInstance();
542         }
543     }
544 
545     protected OpenSearch newOpenSearch(Portlet portlet) throws Exception {
546         if (Validator.isNull(portlet.getOpenSearchClass())) {
547             return null;
548         }
549 
550         return (OpenSearch)newInstance(
551             OpenSearch.class, portlet.getOpenSearchClass());
552     }
553 
554     protected PollerProcessor newPollerProcessor(Portlet portlet)
555         throws Exception {
556 
557         if (Validator.isNull(portlet.getPollerProcessorClass())) {
558             return null;
559         }
560 
561         PollerProcessor pollerProcessorInstance = (PollerProcessor)newInstance(
562             PollerProcessor.class, portlet.getPollerProcessorClass());
563 
564         PollerProcessorUtil.addPollerProcessor(
565             portlet.getPortletId(),
566             new ShardPollerProcessorWrapper(pollerProcessorInstance));
567 
568         return pollerProcessorInstance;
569     }
570 
571     protected MessageListener newPOPMessageListener(Portlet portlet)
572         throws Exception {
573 
574         if (Validator.isNull(portlet.getPopMessageListenerClass())) {
575             return null;
576         }
577 
578         MessageListener popMessageListenerInstance =
579             (MessageListener)newInstance(
580                 MessageListener.class, portlet.getPopMessageListenerClass());
581 
582         POPServerUtil.addListener(popMessageListenerInstance);
583 
584         return popMessageListenerInstance;
585     }
586 
587     protected PortletDataHandler newPortletDataHandler(Portlet portlet)
588         throws Exception {
589 
590         if (Validator.isNull(portlet.getPortletDataHandlerClass())) {
591             return null;
592         }
593 
594         return (PortletDataHandler)newInstance(
595             PortletDataHandler.class, portlet.getPortletDataHandlerClass());
596     }
597 
598     protected PortletLayoutListener newPortletLayoutListener(Portlet portlet)
599         throws Exception {
600 
601         if (Validator.isNull(portlet.getPortletLayoutListenerClass())) {
602             return null;
603         }
604 
605         return (PortletLayoutListener)newInstance(
606             PortletLayoutListener.class,
607             portlet.getPortletLayoutListenerClass());
608     }
609 
610     protected URLEncoder newURLEncoder(Portlet portlet) throws Exception {
611         if (Validator.isNull(portlet.getURLEncoderClass())) {
612             return null;
613         }
614 
615         return (URLEncoder)newInstance(
616             URLEncoder.class, portlet.getURLEncoderClass());
617     }
618 
619     private static Log _log = LogFactoryUtil.getLog(PortletBagFactory.class);
620 
621     private ClassLoader _classLoader;
622     private ServletContext _servletContext;
623     private boolean _warFile;
624 
625 }