1
22
23 package com.liferay.portal.deploy.hot;
24
25 import com.liferay.portal.events.EventsProcessor;
26 import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
27 import com.liferay.portal.kernel.configuration.Configuration;
28 import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
29 import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
30 import com.liferay.portal.kernel.deploy.hot.HotDeployException;
31 import com.liferay.portal.kernel.events.Action;
32 import com.liferay.portal.kernel.events.InvokerSimpleAction;
33 import com.liferay.portal.kernel.events.SimpleAction;
34 import com.liferay.portal.kernel.language.LanguageUtil;
35 import com.liferay.portal.kernel.util.GetterUtil;
36 import com.liferay.portal.kernel.util.HttpUtil;
37 import com.liferay.portal.kernel.util.StringPool;
38 import com.liferay.portal.kernel.util.StringUtil;
39 import com.liferay.portal.kernel.util.Validator;
40 import com.liferay.portal.model.ModelListener;
41 import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
42 import com.liferay.portal.servlet.filters.layoutcache.LayoutCacheUtil;
43 import com.liferay.portal.util.DocumentUtil;
44 import com.liferay.portal.util.PortalInstances;
45 import com.liferay.portal.util.PropsKeys;
46 import com.liferay.portal.util.PropsUtil;
47 import com.liferay.portal.util.PropsValues;
48
49 import java.lang.reflect.Field;
50
51 import java.util.ArrayList;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Properties;
56
57 import javax.servlet.ServletContext;
58
59 import org.apache.commons.logging.Log;
60 import org.apache.commons.logging.LogFactory;
61
62 import org.dom4j.Document;
63 import org.dom4j.Element;
64
65
71 public class HookHotDeployListener extends BaseHotDeployListener {
72
73 public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
74 try {
75 doInvokeDeploy(event);
76 }
77 catch (Exception e) {
78 throwHotDeployException(event, "Error registering hook for ", e);
79 }
80 }
81
82 public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
83 try {
84 doInvokeUndeploy(event);
85 }
86 catch (Exception e) {
87 throwHotDeployException(event, "Error unregistering hook for ", e);
88 }
89 }
90
91 protected boolean containsKey(Properties portalProperties, String key) {
92 if (_log.isDebugEnabled()) {
93 return true;
94 }
95 else {
96 return portalProperties.containsKey(key);
97 }
98 }
99
100 protected void destroyPortalProperties(Properties portalProperties)
101 throws Exception {
102
103 PropsUtil.removeProperties(portalProperties);
104
105 if (_log.isDebugEnabled() &&
106 portalProperties.containsKey(PropsKeys.LOCALES)) {
107
108 _log.debug(
109 "Portlet locales " +
110 portalProperties.getProperty(PropsKeys.LOCALES));
111 _log.debug(
112 "Original locales " + PropsUtil.get(PropsKeys.LOCALES));
113 _log.debug(
114 "Original locales array length " +
115 PropsUtil.getArray(PropsKeys.LOCALES).length);
116 }
117
118 resetPortalProperties(portalProperties);
119 }
120
121 protected void doInvokeDeploy(HotDeployEvent event) throws Exception {
122 ServletContext servletContext = event.getServletContext();
123
124 String servletContextName = servletContext.getServletContextName();
125
126 if (_log.isDebugEnabled()) {
127 _log.debug("Invoking deploy for " + servletContextName);
128 }
129
130 String xml = HttpUtil.URLtoString(
131 servletContext.getResource("/WEB-INF/liferay-hook.xml"));
132
133 if (xml == null) {
134 return;
135 }
136
137 if (_log.isInfoEnabled()) {
138 _log.info("Registering hook for " + servletContextName);
139 }
140
141 ClassLoader portletClassLoader = event.getContextClassLoader();
142
143 Document doc = DocumentUtil.readDocumentFromXML(xml, true);
144
145 Element root = doc.getRootElement();
146
147 List<Element> eventEls = root.elements("event");
148
149 for (Element eventEl : eventEls) {
150 String eventClass = eventEl.elementText("event-class");
151 String eventType = eventEl.elementText("event-type");
152
153 Object obj = initEvent(eventClass, eventType, portletClassLoader);
154
155 if (obj != null) {
156 List<Object> events = _eventsMap.get(eventType);
157
158 if (events == null) {
159 events = new ArrayList<Object>();
160
161 _eventsMap.put(eventType, events);
162 }
163
164 events.add(obj);
165 }
166 }
167
168 List<Element> modelListenerEls = root.elements("model-listener");
169
170 for (Element modelListenerEl : modelListenerEls) {
171 String modelListenerClass = modelListenerEl.elementText(
172 "model-listener-class");
173 String modelName = modelListenerEl.elementText("model-name");
174
175 ModelListener modelListener = initModelListener(
176 modelListenerClass, modelName, portletClassLoader);
177
178 if (modelListener != null) {
179 List<ModelListener> modelListeners = _modelListenersMap.get(
180 modelName);
181
182 if (modelListeners == null) {
183 modelListeners = new ArrayList<ModelListener>();
184
185 _modelListenersMap.put(modelName, modelListeners);
186 }
187
188 modelListeners.add(modelListener);
189 }
190 }
191
192 String portalPropertiesLocation = root.elementText("portal-properties");
193
194 if (Validator.isNotNull(portalPropertiesLocation)) {
195 Configuration portalPropertiesConfiguration = null;
196
197 try {
198 String name = portalPropertiesLocation;
199
200 int pos = name.lastIndexOf(".properties");
201
202 if (pos != -1) {
203 name = name.substring(0, pos);
204 }
205
206 portalPropertiesConfiguration =
207 ConfigurationFactoryUtil.getConfiguration(
208 portletClassLoader, name);
209 }
210 catch (Exception e) {
211 _log.error("Unable to read " + portalPropertiesLocation, e);
212 }
213
214 if (portalPropertiesConfiguration != null) {
215 Properties portalProperties =
216 portalPropertiesConfiguration.getProperties();
217
218 if (portalProperties.size() > 0) {
219 _portalPropertiesMap.put(
220 servletContextName, portalProperties);
221
222 initPortalProperties(portalProperties);
223 }
224 }
225 }
226
227 if (_log.isInfoEnabled()) {
228 _log.info(
229 "Hook for " + servletContextName + " registered successfully");
230 }
231 }
232
233 protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
234 ServletContext servletContext = event.getServletContext();
235
236 String servletContextName = servletContext.getServletContextName();
237
238 if (_log.isDebugEnabled()) {
239 _log.debug("Invoking undeploy for " + servletContextName);
240 }
241
242 for (Map.Entry<String, List<Object>> entry : _eventsMap.entrySet()) {
243 String eventType = entry.getKey();
244 List<Object> events = entry.getValue();
245
246 for (Object obj : events) {
247 EventsProcessor.unregisterEvent(eventType, obj);
248 }
249 }
250
251 for (Map.Entry<String, List<ModelListener>> entry :
252 _modelListenersMap.entrySet()) {
253
254 String modelName = entry.getKey();
255 List<ModelListener> modelListeners = entry.getValue();
256
257 BasePersistenceImpl persistence = getPersistence(modelName);
258
259 for (ModelListener modelListener : modelListeners) {
260 persistence.unregisterListener(modelListener);
261 }
262 }
263
264 Properties portalProperties = _portalPropertiesMap.get(
265 servletContextName);
266
267 if (portalProperties != null) {
268 destroyPortalProperties(portalProperties);
269 }
270
271 if (_log.isInfoEnabled()) {
272 _log.info(
273 "Hook for " + servletContextName +
274 " unregistered successfully");
275 }
276 }
277
278 protected BasePersistenceImpl getPersistence(String modelName) {
279 int pos = modelName.lastIndexOf(StringPool.PERIOD);
280
281 String entityName = modelName.substring(pos + 1);
282
283 pos = modelName.lastIndexOf(".model.");
284
285 String packagePath = modelName.substring(0, pos);
286
287 return (BasePersistenceImpl)PortalBeanLocatorUtil.locate(
288 packagePath + ".service.persistence." + entityName +
289 "Persistence.impl");
290 }
291
292 protected Object initEvent(
293 String eventClass, String eventType, ClassLoader portletClassLoader)
294 throws Exception {
295
296 if (eventType.equals(PropsKeys.APPLICATION_STARTUP_EVENTS)) {
297 SimpleAction simpleAction = new InvokerSimpleAction(
298 (SimpleAction)portletClassLoader.loadClass(
299 eventClass).newInstance());
300
301 long[] companyIds = PortalInstances.getCompanyIds();
302
303 for (long companyId : companyIds) {
304 simpleAction.run(new String[] {String.valueOf(companyId)});
305 }
306
307 return null;
308 }
309
310 if (eventType.equals(PropsKeys.LOGIN_EVENTS_POST) ||
311 eventType.equals(PropsKeys.LOGIN_EVENTS_PRE) ||
312 eventType.equals(PropsKeys.LOGOUT_EVENTS_POST) ||
313 eventType.equals(PropsKeys.LOGOUT_EVENTS_PRE) ||
314 eventType.equals(PropsKeys.SERVLET_SERVICE_EVENTS_POST) ||
315 eventType.equals(PropsKeys.SERVLET_SERVICE_EVENTS_PRE)) {
316
317 Action action = (Action)portletClassLoader.loadClass(
318 eventClass).newInstance();
319
320 EventsProcessor.registerEvent(eventType, action);
321
322 return action;
323 }
324
325 return null;
326 }
327
328 protected ModelListener initModelListener(
329 String modelListenerClass, String modelName,
330 ClassLoader portletClassLoader)
331 throws Exception {
332
333 ModelListener modelListener =
334 (ModelListener)portletClassLoader.loadClass(
335 modelListenerClass).newInstance();
336
337 BasePersistenceImpl persistence = getPersistence(modelName);
338
339 persistence.registerListener(modelListener);
340
341 return modelListener;
342 }
343
344 protected void initPortalProperties(Properties portalProperties)
345 throws Exception {
346
347 PropsUtil.addProperties(portalProperties);
348
349 if (_log.isDebugEnabled() &&
350 portalProperties.containsKey(PropsKeys.LOCALES)) {
351
352 _log.debug(
353 "Portlet locales " +
354 portalProperties.getProperty(PropsKeys.LOCALES));
355 _log.debug(
356 "Merged locales " + PropsUtil.get(PropsKeys.LOCALES));
357 _log.debug(
358 "Merged locales array length " +
359 PropsUtil.getArray(PropsKeys.LOCALES).length);
360 }
361
362 resetPortalProperties(portalProperties);
363 }
364
365 protected void resetPortalProperties(Properties portalProperties)
366 throws Exception {
367
368 for (String fieldName : _PROPS_KEYS_BOOLEAN) {
369 String key = StringUtil.replace(
370 fieldName.toLowerCase(), StringPool.UNDERLINE,
371 StringPool.PERIOD);
372
373 if (!containsKey(portalProperties, key)) {
374 continue;
375 }
376
377 try {
378 Field field = PropsValues.class.getField(fieldName);
379
380 Boolean value = Boolean.valueOf(GetterUtil.getBoolean(
381 PropsUtil.get(key)));
382
383 field.setBoolean(null, value);
384 }
385 catch (Exception e) {
386 _log.error(
387 "Error setting field " + fieldName + ": " + e.getMessage());
388 }
389 }
390
391 for (String fieldName : _PROPS_KEYS_INTEGER) {
392 String key = StringUtil.replace(
393 fieldName.toLowerCase(), StringPool.UNDERLINE,
394 StringPool.PERIOD);
395
396 if (!containsKey(portalProperties, key)) {
397 continue;
398 }
399
400 try {
401 Field field = PropsValues.class.getField(fieldName);
402
403 Integer value = Integer.valueOf(GetterUtil.getInteger(
404 PropsUtil.get(key)));
405
406 field.setInt(null, value);
407 }
408 catch (Exception e) {
409 _log.error(
410 "Error setting field " + fieldName + ": " + e.getMessage());
411 }
412 }
413
414 for (String fieldName : _PROPS_KEYS_LONG) {
415 String key = StringUtil.replace(
416 fieldName.toLowerCase(), StringPool.UNDERLINE,
417 StringPool.PERIOD);
418
419 if (!containsKey(portalProperties, key)) {
420 continue;
421 }
422
423 try {
424 Field field = PropsValues.class.getField(fieldName);
425
426 Long value = Long.valueOf(GetterUtil.getLong(
427 PropsUtil.get(key)));
428
429 field.setLong(null, value);
430 }
431 catch (Exception e) {
432 _log.error(
433 "Error setting field " + fieldName + ": " + e.getMessage());
434 }
435 }
436
437 for (String fieldName : _PROPS_KEYS_STRING) {
438 String key = StringUtil.replace(
439 fieldName.toLowerCase(), StringPool.UNDERLINE,
440 StringPool.PERIOD);
441
442 if (!containsKey(portalProperties, key)) {
443 continue;
444 }
445
446 try {
447 Field field = PropsValues.class.getField(fieldName);
448
449 String value = GetterUtil.getString(PropsUtil.get(key));
450
451 field.set(null, value);
452 }
453 catch (Exception e) {
454 _log.error(
455 "Error setting field " + fieldName + ": " + e.getMessage());
456 }
457 }
458
459 if (containsKey(portalProperties, PropsKeys.LOCALES)) {
460 PropsValues.LOCALES = PropsUtil.getArray(PropsKeys.LOCALES);
461
462 LanguageUtil.init();
463 }
464
465 LayoutCacheUtil.clearCache();
466 }
467
468 private static final String[] _PROPS_KEYS_BOOLEAN = new String[] {
469 "JAVASCRIPT_FAST_LOAD",
470 "LAYOUT_TEMPLATE_CACHE_ENABLED",
471 "LAYOUT_USER_PRIVATE_LAYOUTS_AUTO_CREATE",
472 "LAYOUT_USER_PRIVATE_LAYOUTS_ENABLED",
473 "LAYOUT_USER_PRIVATE_LAYOUTS_MODIFIABLE",
474 "LAYOUT_USER_PUBLIC_LAYOUTS_AUTO_CREATE",
475 "LAYOUT_USER_PUBLIC_LAYOUTS_ENABLED",
476 "LAYOUT_USER_PUBLIC_LAYOUTS_MODIFIABLE",
477 "MY_PLACES_SHOW_COMMUNITY_PRIVATE_SITES_WITH_NO_LAYOUTS",
478 "MY_PLACES_SHOW_COMMUNITY_PUBLIC_SITES_WITH_NO_LAYOUTS",
479 "MY_PLACES_SHOW_ORGANIZATION_PRIVATE_SITES_WITH_NO_LAYOUTS",
480 "MY_PLACES_SHOW_ORGANIZATION_PUBLIC_SITES_WITH_NO_LAYOUTS",
481 "MY_PLACES_SHOW_USER_PRIVATE_SITES_WITH_NO_LAYOUTS",
482 "MY_PLACES_SHOW_USER_PUBLIC_SITES_WITH_NO_LAYOUTS",
483 "ORGANIZATIONS_COUNTRY_REQUIRED",
484 "THEME_CSS_FAST_LOAD"
485 };
486
487 private static final String[] _PROPS_KEYS_INTEGER = new String[] {
488 };
489
490 private static final String[] _PROPS_KEYS_LONG = new String[] {
491 };
492
493 private static final String[] _PROPS_KEYS_STRING = new String[] {
494 "PASSWORDS_PASSWORDPOLICYTOOLKIT_GENERATOR",
495 "PASSWORDS_PASSWORDPOLICYTOOLKIT_STATIC"
496 };
497
498 private static Log _log = LogFactory.getLog(HookHotDeployListener.class);
499
500 private Map<String, List<Object>> _eventsMap =
501 new HashMap<String, List<Object>>();
502 private Map<String, List<ModelListener>> _modelListenersMap =
503 new HashMap<String, List<ModelListener>>();
504 private Map<String, Properties> _portalPropertiesMap =
505 new HashMap<String, Properties>();
506
507 }