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
315 Action action = (Action)portletClassLoader.loadClass(
316 eventClass).newInstance();
317
318 EventsProcessor.registerEvent(eventType, action);
319
320 return action;
321 }
322
323 return null;
324 }
325
326 protected ModelListener initModelListener(
327 String modelListenerClass, String modelName,
328 ClassLoader portletClassLoader)
329 throws Exception {
330
331 ModelListener modelListener =
332 (ModelListener)portletClassLoader.loadClass(
333 modelListenerClass).newInstance();
334
335 BasePersistenceImpl persistence = getPersistence(modelName);
336
337 persistence.registerListener(modelListener);
338
339 return modelListener;
340 }
341
342 protected void initPortalProperties(Properties portalProperties)
343 throws Exception {
344
345 PropsUtil.addProperties(portalProperties);
346
347 if (_log.isDebugEnabled() &&
348 portalProperties.containsKey(PropsKeys.LOCALES)) {
349
350 _log.debug(
351 "Portlet locales " +
352 portalProperties.getProperty(PropsKeys.LOCALES));
353 _log.debug(
354 "Merged locales " + PropsUtil.get(PropsKeys.LOCALES));
355 _log.debug(
356 "Merged locales array length " +
357 PropsUtil.getArray(PropsKeys.LOCALES).length);
358 }
359
360 resetPortalProperties(portalProperties);
361 }
362
363 protected void resetPortalProperties(Properties portalProperties)
364 throws Exception {
365
366 for (String fieldName : _PROPS_KEYS_BOOLEAN) {
367 String key = StringUtil.replace(
368 fieldName.toLowerCase(), StringPool.UNDERLINE,
369 StringPool.PERIOD);
370
371 if (!containsKey(portalProperties, key)) {
372 continue;
373 }
374
375 try {
376 Field field = PropsValues.class.getField(fieldName);
377
378 Boolean value = Boolean.valueOf(GetterUtil.getBoolean(
379 PropsUtil.get(key)));
380
381 field.setBoolean(null, value);
382 }
383 catch (Exception e) {
384 _log.error(
385 "Error setting field " + fieldName + ": " + e.getMessage());
386 }
387 }
388
389 for (String fieldName : _PROPS_KEYS_INTEGER) {
390 String key = StringUtil.replace(
391 fieldName.toLowerCase(), StringPool.UNDERLINE,
392 StringPool.PERIOD);
393
394 if (!containsKey(portalProperties, key)) {
395 continue;
396 }
397
398 try {
399 Field field = PropsValues.class.getField(fieldName);
400
401 Integer value = Integer.valueOf(GetterUtil.getInteger(
402 PropsUtil.get(key)));
403
404 field.setInt(null, value);
405 }
406 catch (Exception e) {
407 _log.error(
408 "Error setting field " + fieldName + ": " + e.getMessage());
409 }
410 }
411
412 for (String fieldName : _PROPS_KEYS_LONG) {
413 String key = StringUtil.replace(
414 fieldName.toLowerCase(), StringPool.UNDERLINE,
415 StringPool.PERIOD);
416
417 if (!containsKey(portalProperties, key)) {
418 continue;
419 }
420
421 try {
422 Field field = PropsValues.class.getField(fieldName);
423
424 Long value = Long.valueOf(GetterUtil.getLong(
425 PropsUtil.get(key)));
426
427 field.setLong(null, value);
428 }
429 catch (Exception e) {
430 _log.error(
431 "Error setting field " + fieldName + ": " + e.getMessage());
432 }
433 }
434
435 for (String fieldName : _PROPS_KEYS_STRING) {
436 String key = StringUtil.replace(
437 fieldName.toLowerCase(), StringPool.UNDERLINE,
438 StringPool.PERIOD);
439
440 if (!containsKey(portalProperties, key)) {
441 continue;
442 }
443
444 try {
445 Field field = PropsValues.class.getField(fieldName);
446
447 String value = GetterUtil.getString(PropsUtil.get(key));
448
449 field.set(null, value);
450 }
451 catch (Exception e) {
452 _log.error(
453 "Error setting field " + fieldName + ": " + e.getMessage());
454 }
455 }
456
457 if (containsKey(portalProperties, PropsKeys.LOCALES)) {
458 PropsValues.LOCALES = PropsUtil.getArray(PropsKeys.LOCALES);
459
460 LanguageUtil.init();
461 }
462
463 LayoutCacheUtil.clearCache();
464 }
465
466 private static final String[] _PROPS_KEYS_BOOLEAN = new String[] {
467 "JAVASCRIPT_FAST_LOAD",
468 "LAYOUT_TEMPLATE_CACHE_ENABLED",
469 "LAYOUT_USER_PRIVATE_LAYOUTS_AUTO_CREATE",
470 "LAYOUT_USER_PRIVATE_LAYOUTS_ENABLED",
471 "LAYOUT_USER_PRIVATE_LAYOUTS_MODIFIABLE",
472 "LAYOUT_USER_PUBLIC_LAYOUTS_AUTO_CREATE",
473 "LAYOUT_USER_PUBLIC_LAYOUTS_ENABLED",
474 "LAYOUT_USER_PUBLIC_LAYOUTS_MODIFIABLE",
475 "MY_PLACES_SHOW_COMMUNITY_PRIVATE_SITES_WITH_NO_LAYOUTS",
476 "MY_PLACES_SHOW_COMMUNITY_PUBLIC_SITES_WITH_NO_LAYOUTS",
477 "MY_PLACES_SHOW_ORGANIZATION_PRIVATE_SITES_WITH_NO_LAYOUTS",
478 "MY_PLACES_SHOW_ORGANIZATION_PUBLIC_SITES_WITH_NO_LAYOUTS",
479 "MY_PLACES_SHOW_USER_PRIVATE_SITES_WITH_NO_LAYOUTS",
480 "MY_PLACES_SHOW_USER_PUBLIC_SITES_WITH_NO_LAYOUTS",
481 "ORGANIZATIONS_COUNTRY_REQUIRED",
482 "THEME_CSS_FAST_LOAD"
483 };
484
485 private static final String[] _PROPS_KEYS_INTEGER = new String[] {
486 };
487
488 private static final String[] _PROPS_KEYS_LONG = new String[] {
489 };
490
491 private static final String[] _PROPS_KEYS_STRING = new String[] {
492 "PASSWORDS_PASSWORDPOLICYTOOLKIT_GENERATOR",
493 "PASSWORDS_PASSWORDPOLICYTOOLKIT_STATIC"
494 };
495
496 private static Log _log = LogFactory.getLog(HookHotDeployListener.class);
497
498 private Map<String, List<Object>> _eventsMap =
499 new HashMap<String, List<Object>>();
500 private Map<String, List<ModelListener>> _modelListenersMap =
501 new HashMap<String, List<ModelListener>>();
502 private Map<String, Properties> _portalPropertiesMap =
503 new HashMap<String, Properties>();
504
505 }