001
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.javadoc.JavadocManagerUtil;
024 import com.liferay.portal.kernel.log.Log;
025 import com.liferay.portal.kernel.log.LogFactoryUtil;
026 import com.liferay.portal.kernel.model.Portlet;
027 import com.liferay.portal.kernel.model.PortletApp;
028 import com.liferay.portal.kernel.model.PortletCategory;
029 import com.liferay.portal.kernel.model.PortletFilter;
030 import com.liferay.portal.kernel.model.PortletURLListener;
031 import com.liferay.portal.kernel.portlet.CustomUserAttributes;
032 import com.liferay.portal.kernel.portlet.InvokerPortlet;
033 import com.liferay.portal.kernel.portlet.PortletBag;
034 import com.liferay.portal.kernel.portlet.PortletBagPool;
035 import com.liferay.portal.kernel.portlet.PortletInstanceFactoryUtil;
036 import com.liferay.portal.kernel.security.permission.ResourceActionsUtil;
037 import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
038 import com.liferay.portal.kernel.service.ResourceActionLocalServiceUtil;
039 import com.liferay.portal.kernel.servlet.DirectServletRegistryUtil;
040 import com.liferay.portal.kernel.servlet.FileTimestampUtil;
041 import com.liferay.portal.kernel.servlet.PortletServlet;
042 import com.liferay.portal.kernel.servlet.ServletContextPool;
043 import com.liferay.portal.kernel.servlet.ServletContextProvider;
044 import com.liferay.portal.kernel.util.ClassUtil;
045 import com.liferay.portal.kernel.util.GetterUtil;
046 import com.liferay.portal.kernel.util.HttpUtil;
047 import com.liferay.portal.kernel.util.Portal;
048 import com.liferay.portal.kernel.util.PropsKeys;
049 import com.liferay.portal.kernel.util.ResourceBundleLoader;
050 import com.liferay.portal.kernel.util.ResourceBundleUtil;
051 import com.liferay.portal.kernel.util.StringUtil;
052 import com.liferay.portal.kernel.util.Validator;
053 import com.liferay.portal.kernel.util.WebKeys;
054 import com.liferay.portal.util.PortalInstances;
055 import com.liferay.portal.util.WebAppPool;
056 import com.liferay.portlet.PortletContextBag;
057 import com.liferay.portlet.PortletContextBagPool;
058 import com.liferay.portlet.PortletFilterFactory;
059 import com.liferay.portlet.PortletURLListenerFactory;
060 import com.liferay.registry.Registry;
061 import com.liferay.registry.RegistryUtil;
062 import com.liferay.registry.ServiceRegistration;
063
064 import java.util.HashMap;
065 import java.util.HashSet;
066 import java.util.Iterator;
067 import java.util.List;
068 import java.util.Map;
069 import java.util.Properties;
070 import java.util.Set;
071
072 import javax.naming.Context;
073 import javax.naming.InitialContext;
074 import javax.naming.NamingException;
075
076 import javax.portlet.PortletURLGenerationListener;
077
078 import javax.servlet.ServletContext;
079
080 import org.apache.portals.bridges.struts.StrutsPortlet;
081
082
088 public class PortletHotDeployListener extends BaseHotDeployListener {
089
090 @Override
091 public void invokeDeploy(HotDeployEvent hotDeployEvent)
092 throws HotDeployException {
093
094 try {
095 doInvokeDeploy(hotDeployEvent);
096 }
097 catch (Throwable t) {
098 throwHotDeployException(
099 hotDeployEvent, "Error registering portlets for ", t);
100 }
101 }
102
103 @Override
104 public void invokeUndeploy(HotDeployEvent hotDeployEvent)
105 throws HotDeployException {
106
107 try {
108 doInvokeUndeploy(hotDeployEvent);
109 }
110 catch (Throwable t) {
111 throwHotDeployException(
112 hotDeployEvent, "Error unregistering portlets for ", t);
113 }
114 }
115
116 protected void checkResourceBundles(
117 ClassLoader classLoader, Portlet portlet) {
118
119 if (Validator.isNull(portlet.getResourceBundle())) {
120 return;
121 }
122
123 Registry registry = RegistryUtil.getRegistry();
124
125 ResourceBundleLoader resourceBundleLoader =
126 ResourceBundleUtil.getResourceBundleLoader(
127 portlet.getResourceBundle(), classLoader);
128
129 Map<String, Object> properties = new HashMap<>();
130
131 properties.put(
132 "resource.bundle.base.name", portlet.getResourceBundle());
133 properties.put("service.ranking", Integer.MIN_VALUE);
134 properties.put("servlet.context.name", portlet.getContextName());
135
136 _resourceBundleLoaderServiceRegistrations.put(
137 portlet.getPortletId(),
138 registry.registerService(
139 ResourceBundleLoader.class, resourceBundleLoader, properties));
140 }
141
142 protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
143 throws Exception {
144
145 PortletApp portletApp = portlet.getPortletApp();
146
147 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
148
149 for (PortletFilter portletFilter : portletFilters) {
150 PortletFilterFactory.destroy(portletFilter);
151 }
152
153 Set<PortletURLListener> portletURLListeners =
154 portletApp.getPortletURLListeners();
155
156 for (PortletURLListener portletURLListener : portletURLListeners) {
157 PortletURLListenerFactory.destroy(portletURLListener);
158 }
159
160 PortletInstanceFactoryUtil.destroy(portlet);
161
162 portletIds.add(portlet.getPortletId());
163
164 ServiceRegistration<ResourceBundleLoader>
165 resourceBundleLoaderServiceRegistration =
166 _resourceBundleLoaderServiceRegistrations.remove(
167 portlet.getPortletId());
168
169 if (resourceBundleLoaderServiceRegistration != null) {
170 resourceBundleLoaderServiceRegistration.unregister();
171 }
172 }
173
174 protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
175 throws Exception {
176
177 ServletContext servletContext = hotDeployEvent.getServletContext();
178
179 String servletContextName = servletContext.getServletContextName();
180
181 if (_log.isDebugEnabled()) {
182 _log.debug("Invoking deploy for " + servletContextName);
183 }
184
185 String[] xmls = new String[] {
186 HttpUtil.URLtoString(
187 servletContext.getResource(
188 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
189 HttpUtil.URLtoString(
190 servletContext.getResource(
191 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
192 HttpUtil.URLtoString(
193 servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
194 HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
195 };
196
197 if ((xmls[0] == null) && (xmls[1] == null)) {
198 return;
199 }
200
201 if (_log.isInfoEnabled()) {
202 _log.info("Registering portlets for " + servletContextName);
203 }
204
205 PortletContextBag portletContextBag = new PortletContextBag(
206 servletContextName);
207
208 PortletContextBagPool.put(servletContextName, portletContextBag);
209
210 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
211 servletContextName, servletContext, xmls,
212 hotDeployEvent.getPluginPackage());
213
214 boolean portletAppInitialized = false;
215
216 boolean strutsBridges = false;
217
218 ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
219
220 Iterator<Portlet> itr = portlets.iterator();
221
222 while (itr.hasNext()) {
223 Portlet portlet = itr.next();
224
225 PortletBag portletBag = PortletBagPool.get(
226 portlet.getRootPortletId());
227
228 if (!portletAppInitialized) {
229 initPortletApp(
230 servletContextName, servletContext, classLoader, portlet);
231
232 portletAppInitialized = true;
233 }
234
235 javax.portlet.Portlet portletInstance =
236 portletBag.getPortletInstance();
237
238 if (ClassUtil.isSubclass(
239 portletInstance.getClass(),
240 StrutsPortlet.class.getName())) {
241
242 strutsBridges = true;
243 }
244 }
245
246 if (!strutsBridges) {
247 strutsBridges = GetterUtil.getBoolean(
248 servletContext.getInitParameter(
249 "struts-bridges-context-provider"));
250 }
251
252 if (strutsBridges) {
253 servletContext.setAttribute(
254 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
255 new LiferayServletContextProvider());
256 }
257
258 String xml = HttpUtil.URLtoString(
259 servletContext.getResource("/WEB-INF/liferay-display.xml"));
260
261 PortletCategory newPortletCategory =
262 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
263
264 long[] companyIds = PortalInstances.getCompanyIds();
265
266 for (long companyId : companyIds) {
267 PortletCategory portletCategory = (PortletCategory)WebAppPool.get(
268 companyId, WebKeys.PORTLET_CATEGORY);
269
270 if (portletCategory != null) {
271 portletCategory.merge(newPortletCategory);
272 }
273 else {
274 _log.error(
275 "Unable to register portlet for company " + companyId +
276 " because it does not exist");
277 }
278 }
279
280 processPortletProperties(servletContextName, classLoader);
281
282 for (Portlet portlet : portlets) {
283 List<String> modelNames =
284 ResourceActionsUtil.getPortletModelResources(
285 portlet.getPortletId());
286
287 List<String> portletActions =
288 ResourceActionsUtil.getPortletResourceActions(
289 portlet.getPortletId());
290
291 ResourceActionLocalServiceUtil.checkResourceActions(
292 portlet.getPortletId(), portletActions);
293
294 checkResourceBundles(classLoader, portlet);
295
296 for (String modelName : modelNames) {
297 List<String> modelActions =
298 ResourceActionsUtil.getModelResourceActions(modelName);
299
300 ResourceActionLocalServiceUtil.checkResourceActions(
301 modelName, modelActions);
302 }
303
304 for (long companyId : companyIds) {
305 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
306 companyId, portlet.getPortletId());
307
308 PortletLocalServiceUtil.checkPortlet(curPortlet);
309 }
310 }
311
312 for (Portlet portlet : portlets) {
313 boolean ready = GetterUtil.getBoolean(
314 servletContext.getInitParameter("portlets-ready-by-default"),
315 true);
316
317 portlet.setReady(ready);
318 }
319
320 JavadocManagerUtil.load(servletContextName, classLoader);
321
322 DirectServletRegistryUtil.clearServlets();
323 FileTimestampUtil.reset();
324
325 _portlets.put(servletContextName, portlets);
326
327 servletContext.setAttribute(WebKeys.PLUGIN_PORTLETS, portlets);
328
329 if (_log.isInfoEnabled()) {
330 if (portlets.size() == 1) {
331 _log.info(
332 "1 portlet for " + servletContextName +
333 " is available for use");
334 }
335 else {
336 _log.info(
337 portlets.size() + " portlets for " + servletContextName +
338 " are available for use");
339 }
340 }
341 }
342
343 protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
344 throws Exception {
345
346 ServletContext servletContext = hotDeployEvent.getServletContext();
347
348 String servletContextName = servletContext.getServletContextName();
349
350 if (_log.isDebugEnabled()) {
351 _log.debug("Invoking undeploy for " + servletContextName);
352 }
353
354 List<Portlet> portlets = _portlets.remove(servletContextName);
355
356 if (portlets == null) {
357 return;
358 }
359
360 Set<String> portletIds = new HashSet<>();
361
362 if (portlets != null) {
363 if (_log.isInfoEnabled()) {
364 _log.info("Unregistering portlets for " + servletContextName);
365 }
366
367 for (Portlet portlet : portlets) {
368 destroyPortlet(portlet, portletIds);
369 }
370 }
371
372 ServletContextPool.remove(servletContextName);
373
374 if (!portletIds.isEmpty()) {
375 long[] companyIds = PortalInstances.getCompanyIds();
376
377 for (long companyId : companyIds) {
378 PortletCategory portletCategory =
379 (PortletCategory)WebAppPool.get(
380 companyId, WebKeys.PORTLET_CATEGORY);
381
382 portletCategory.separate(portletIds);
383 }
384 }
385
386 PortletContextBagPool.remove(servletContextName);
387
388 JavadocManagerUtil.unload(servletContextName);
389
390 DirectServletRegistryUtil.clearServlets();
391
392 if (_log.isInfoEnabled()) {
393 if (portlets.size() == 1) {
394 _log.info(
395 "1 portlet for " + servletContextName +
396 " was unregistered");
397 }
398 else {
399 _log.info(
400 portlets.size() + " portlets for " + servletContextName +
401 " were unregistered");
402 }
403 }
404 }
405
406 protected void initPortletApp(
407 String servletContextName, ServletContext servletContext,
408 ClassLoader classLoader, Portlet portlet)
409 throws Exception {
410
411 PortletContextBag portletContextBag = PortletContextBagPool.get(
412 servletContextName);
413
414 PortletApp portletApp = portlet.getPortletApp();
415
416 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
417
418 Map<String, String> customUserAttributes =
419 portletApp.getCustomUserAttributes();
420
421 for (Map.Entry<String, String> entry :
422 customUserAttributes.entrySet()) {
423
424 String attrCustomClass = entry.getValue();
425
426 Class<?> clazz = classLoader.loadClass(attrCustomClass);
427
428 CustomUserAttributes customUserAttributesInstance =
429 (CustomUserAttributes)clazz.newInstance();
430
431 portletContextBag.getCustomUserAttributes().put(
432 attrCustomClass, customUserAttributesInstance);
433 }
434
435 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
436
437 for (PortletFilter portletFilter : portletFilters) {
438 javax.portlet.filter.PortletFilter portletFilterInstance =
439 (javax.portlet.filter.PortletFilter)newInstance(
440 classLoader,
441 new Class<?>[] {
442 javax.portlet.filter.ActionFilter.class,
443 javax.portlet.filter.EventFilter.class,
444 javax.portlet.filter.PortletFilter.class,
445 javax.portlet.filter.RenderFilter.class,
446 javax.portlet.filter.ResourceFilter.class
447 },
448 portletFilter.getFilterClass());
449
450 portletContextBag.getPortletFilters().put(
451 portletFilter.getFilterName(), portletFilterInstance);
452 }
453
454 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
455 portlet, servletContext);
456
457 invokerPortlet.setPortletFilters();
458
459 Set<PortletURLListener> portletURLListeners =
460 portletApp.getPortletURLListeners();
461
462 for (PortletURLListener portletURLListener : portletURLListeners) {
463 PortletURLGenerationListener portletURLListenerInstance =
464 (PortletURLGenerationListener)newInstance(
465 classLoader, PortletURLGenerationListener.class,
466 portletURLListener.getListenerClass());
467
468 portletContextBag.getPortletURLListeners().put(
469 portletURLListener.getListenerClass(),
470 portletURLListenerInstance);
471
472 PortletURLListenerFactory.create(portletURLListener);
473 }
474 }
475
476 protected void processPortletProperties(
477 String servletContextName, ClassLoader classLoader)
478 throws Exception {
479
480 Configuration portletPropertiesConfiguration = null;
481
482 try {
483 portletPropertiesConfiguration =
484 ConfigurationFactoryUtil.getConfiguration(
485 classLoader, "portlet");
486 }
487 catch (Exception e) {
488 if (_log.isDebugEnabled()) {
489 _log.debug("Unable to read portlet.properties");
490 }
491
492 return;
493 }
494
495 Properties portletProperties =
496 portletPropertiesConfiguration.getProperties();
497
498 if (portletProperties.isEmpty()) {
499 return;
500 }
501
502 String[] resourceActionConfigs = StringUtil.split(
503 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
504
505 for (String resourceActionConfig : resourceActionConfigs) {
506 ResourceActionsUtil.read(
507 servletContextName, classLoader, resourceActionConfig);
508 }
509 }
510
511 protected void unbindDataSource(String servletContextName) {
512 Boolean dataSourceBindState = _dataSourceBindStates.remove(
513 servletContextName);
514
515 if (dataSourceBindState == null) {
516 return;
517 }
518
519 try {
520 if (_log.isDebugEnabled()) {
521 _log.debug("Dynamically unbinding the Liferay data source");
522 }
523
524 Context context = new InitialContext();
525
526 try {
527 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
528
529 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
530 }
531 catch (NamingException ne) {
532 }
533
534 try {
535 context.lookup(_JNDI_JDBC);
536
537 context.destroySubcontext(_JNDI_JDBC);
538 }
539 catch (NamingException ne) {
540 }
541 }
542 catch (Exception e) {
543 if (_log.isWarnEnabled()) {
544 _log.warn(
545 "Unable to dynamically unbind the Liferay data source: " +
546 e.getMessage());
547 }
548 }
549 }
550
551 private static final String _JNDI_JDBC = "java_liferay:jdbc";
552
553 private static final String _JNDI_JDBC_LIFERAY_POOL =
554 _JNDI_JDBC + "/LiferayPool";
555
556 private static final Log _log = LogFactoryUtil.getLog(
557 PortletHotDeployListener.class);
558
559 private static final Map<String, Boolean> _dataSourceBindStates =
560 new HashMap<>();
561 private static final Map<String, List<Portlet>> _portlets = new HashMap<>();
562
563 private final Map<String, ServiceRegistration<ResourceBundleLoader>>
564 _resourceBundleLoaderServiceRegistrations = new HashMap<>();
565
566 }