1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.events.EventsProcessorUtil;
26  import com.liferay.portal.kernel.bean.ContextClassLoaderBeanHandler;
27  import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
28  import com.liferay.portal.kernel.configuration.Configuration;
29  import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
30  import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
31  import com.liferay.portal.kernel.deploy.hot.HotDeployException;
32  import com.liferay.portal.kernel.events.Action;
33  import com.liferay.portal.kernel.events.InvokerAction;
34  import com.liferay.portal.kernel.events.InvokerSessionAction;
35  import com.liferay.portal.kernel.events.InvokerSimpleAction;
36  import com.liferay.portal.kernel.events.SessionAction;
37  import com.liferay.portal.kernel.events.SimpleAction;
38  import com.liferay.portal.kernel.language.LanguageUtil;
39  import com.liferay.portal.kernel.log.Log;
40  import com.liferay.portal.kernel.log.LogFactoryUtil;
41  import com.liferay.portal.kernel.util.ArrayUtil;
42  import com.liferay.portal.kernel.util.FileUtil;
43  import com.liferay.portal.kernel.util.GetterUtil;
44  import com.liferay.portal.kernel.util.HttpUtil;
45  import com.liferay.portal.kernel.util.StringPool;
46  import com.liferay.portal.kernel.util.StringUtil;
47  import com.liferay.portal.kernel.util.Validator;
48  import com.liferay.portal.kernel.xml.Document;
49  import com.liferay.portal.kernel.xml.Element;
50  import com.liferay.portal.kernel.xml.SAXReaderUtil;
51  import com.liferay.portal.model.BaseModel;
52  import com.liferay.portal.model.ModelListener;
53  import com.liferay.portal.security.auth.AuthFailure;
54  import com.liferay.portal.security.auth.AuthPipeline;
55  import com.liferay.portal.security.auth.Authenticator;
56  import com.liferay.portal.security.auth.AutoLogin;
57  import com.liferay.portal.security.auth.CompanyThreadLocal;
58  import com.liferay.portal.security.ldap.AttributesTransformer;
59  import com.liferay.portal.security.ldap.AttributesTransformerFactory;
60  import com.liferay.portal.service.persistence.BasePersistence;
61  import com.liferay.portal.servlet.filters.autologin.AutoLoginFilter;
62  import com.liferay.portal.servlet.filters.cache.CacheUtil;
63  import com.liferay.portal.struts.MultiMessageResources;
64  import com.liferay.portal.struts.MultiMessageResourcesFactory;
65  import com.liferay.portal.util.PortalInstances;
66  import com.liferay.portal.util.PortalUtil;
67  import com.liferay.portal.util.PropsKeys;
68  import com.liferay.portal.util.PropsUtil;
69  import com.liferay.portal.util.PropsValues;
70  
71  import java.io.File;
72  import java.io.InputStream;
73  
74  import java.lang.reflect.Field;
75  import java.lang.reflect.Proxy;
76  
77  import java.net.URL;
78  
79  import java.util.ArrayList;
80  import java.util.HashMap;
81  import java.util.HashSet;
82  import java.util.Iterator;
83  import java.util.List;
84  import java.util.Map;
85  import java.util.Properties;
86  import java.util.Set;
87  
88  import javax.servlet.ServletContext;
89  
90  /**
91   * <a href="HookHotDeployListener.java.html"><b><i>View Source</i></b></a>
92   *
93   * @author Brian Wing Shun Chan
94   * @author Bruno Farache
95   */
96  public class HookHotDeployListener
97      extends BaseHotDeployListener implements PropsKeys {
98  
99      public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
100         try {
101             doInvokeDeploy(event);
102         }
103         catch (Throwable t) {
104             throwHotDeployException(event, "Error registering hook for ", t);
105         }
106     }
107 
108     public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
109         try {
110             doInvokeUndeploy(event);
111         }
112         catch (Throwable t) {
113             throwHotDeployException(event, "Error unregistering hook for ", t);
114         }
115     }
116 
117     protected boolean containsKey(Properties portalProperties, String key) {
118         if (_log.isDebugEnabled()) {
119             return true;
120         }
121         else {
122             return portalProperties.containsKey(key);
123         }
124     }
125 
126     protected void destroyCustomJspBag(CustomJspBag customJspBag) {
127         String customJspDir = customJspBag.getCustomJspDir();
128         List<String> customJsps = customJspBag.getCustomJsps();
129         //String timestamp = customJspBag.getTimestamp();
130 
131         String portalWebDir = PortalUtil.getPortalWebDir();
132 
133         for (String customJsp : customJsps) {
134             int pos = customJsp.indexOf(customJspDir);
135 
136             String portalJsp = customJsp.substring(
137                 pos + customJspDir.length(), customJsp.length());
138 
139             File portalJspFile = new File(portalWebDir + portalJsp);
140             File portalJspBackupFile = getPortalJspBackupFile(portalJspFile);
141 
142             if (portalJspBackupFile.exists()) {
143                 FileUtil.copyFile(portalJspBackupFile, portalJspFile);
144 
145                 portalJspBackupFile.delete();
146             }
147             else if (portalJspFile.exists()) {
148                 portalJspFile.delete();
149             }
150         }
151     }
152 
153     protected void destroyPortalProperties(Properties portalProperties)
154         throws Exception {
155 
156         PropsUtil.removeProperties(portalProperties);
157 
158         if (_log.isDebugEnabled() && portalProperties.containsKey(LOCALES)) {
159             _log.debug(
160                 "Portlet locales " + portalProperties.getProperty(LOCALES));
161             _log.debug("Original locales " + PropsUtil.get(LOCALES));
162             _log.debug(
163                 "Original locales array length " +
164                     PropsUtil.getArray(LOCALES).length);
165         }
166 
167         resetPortalProperties(portalProperties);
168 
169         if (portalProperties.contains(PropsKeys.LDAP_ATTRS_TRANSFORMER_IMPL)) {
170             AttributesTransformerFactory.setInstance(null);
171         }
172     }
173 
174     protected void doInvokeDeploy(HotDeployEvent event) throws Exception {
175         ServletContext servletContext = event.getServletContext();
176 
177         String servletContextName = servletContext.getServletContextName();
178 
179         if (_log.isDebugEnabled()) {
180             _log.debug("Invoking deploy for " + servletContextName);
181         }
182 
183         String xml = HttpUtil.URLtoString(
184             servletContext.getResource("/WEB-INF/liferay-hook.xml"));
185 
186         if (xml == null) {
187             return;
188         }
189 
190         if (_log.isInfoEnabled()) {
191             _log.info("Registering hook for " + servletContextName);
192         }
193 
194         _servletContextNames.add(servletContextName);
195 
196         ClassLoader portletClassLoader = event.getContextClassLoader();
197 
198         Document doc = SAXReaderUtil.read(xml, true);
199 
200         Element root = doc.getRootElement();
201 
202         String portalPropertiesLocation = root.elementText("portal-properties");
203 
204         if (Validator.isNotNull(portalPropertiesLocation)) {
205             Configuration portalPropertiesConfiguration = null;
206 
207             try {
208                 String name = portalPropertiesLocation;
209 
210                 int pos = name.lastIndexOf(".properties");
211 
212                 if (pos != -1) {
213                     name = name.substring(0, pos);
214                 }
215 
216                 portalPropertiesConfiguration =
217                     ConfigurationFactoryUtil.getConfiguration(
218                         portletClassLoader, name);
219             }
220             catch (Exception e) {
221                 _log.error("Unable to read " + portalPropertiesLocation, e);
222             }
223 
224             if (portalPropertiesConfiguration != null) {
225                 Properties portalProperties =
226                     portalPropertiesConfiguration.getProperties();
227 
228                 if (portalProperties.size() > 0) {
229                     _portalPropertiesMap.put(
230                         servletContextName, portalProperties);
231 
232                     // Initialize properties, auto logins, model listeners, and
233                     // events in that specific order. Events have to be loaded
234                     // last because they may require model listeners to have
235                     // been registered.
236 
237                     initPortalProperties(portletClassLoader, portalProperties);
238                     initAuthFailures(
239                         servletContextName, portletClassLoader,
240                         portalProperties);
241                     initAutoLogins(
242                         servletContextName, portletClassLoader,
243                         portalProperties);
244                     initModelListeners(
245                         servletContextName, portletClassLoader,
246                         portalProperties);
247                     initEvents(
248                         servletContextName, portletClassLoader,
249                         portalProperties);
250                 }
251             }
252         }
253 
254         LanguagesContainer languagesContainer = new LanguagesContainer();
255 
256         _languagesContainerMap.put(servletContextName, languagesContainer);
257 
258         List<Element> languagePropertiesEls = root.elements(
259             "language-properties");
260 
261         for (Element languagePropertiesEl : languagePropertiesEls) {
262             String languagePropertiesLocation = languagePropertiesEl.getText();
263 
264             try {
265                 URL url = portletClassLoader.getResource(
266                     languagePropertiesLocation);
267 
268                 if (url == null) {
269                     continue;
270                 }
271 
272                 InputStream is = url.openStream();
273 
274                 Properties properties = new Properties();
275 
276                 properties.load(is);
277 
278                 is.close();
279 
280                 String localeKey = getLocaleKey(languagePropertiesLocation);
281 
282                 if (localeKey != null) {
283                     languagesContainer.addLanguage(localeKey, properties);
284                 }
285             }
286             catch (Exception e) {
287                 _log.error("Unable to read " + languagePropertiesLocation, e);
288             }
289         }
290 
291         String customJspDir = root.elementText("custom-jsp-dir");
292 
293         if (Validator.isNotNull(customJspDir)) {
294             if (_log.isDebugEnabled()) {
295                 _log.debug("Custom JSP directory: " + customJspDir);
296             }
297 
298             List<String> customJsps = new ArrayList<String>();
299 
300             String webDir = servletContext.getRealPath(StringPool.SLASH);
301 
302             getCustomJsps(servletContext, webDir, customJspDir, customJsps);
303 
304             if (customJsps.size() > 0) {
305                 CustomJspBag customJspBag = new CustomJspBag(
306                     customJspDir, customJsps);
307 
308                 if (_log.isDebugEnabled()) {
309                     StringBuilder sb = new StringBuilder();
310 
311                     sb.append("Custom JSP files:\n");
312 
313                     Iterator<String> itr = customJsps.iterator();
314 
315                     while (itr.hasNext()) {
316                         String customJsp = itr.next();
317 
318                         sb.append(customJsp);
319 
320                         if (itr.hasNext()) {
321                             sb.append(StringPool.NEW_LINE);
322                         }
323                     }
324 
325                     _log.debug(sb.toString());
326                 }
327 
328                 _customJspBagsMap.put(servletContextName, customJspBag);
329 
330                 initCustomJspBag(customJspBag);
331             }
332         }
333 
334         // Begin backwards compatibility for 5.1.0
335 
336         ModelListenersContainer modelListenersContainer =
337             _modelListenersContainerMap.get(servletContextName);
338 
339         if (modelListenersContainer == null) {
340             modelListenersContainer = new ModelListenersContainer();
341 
342             _modelListenersContainerMap.put(
343                 servletContextName, modelListenersContainer);
344         }
345 
346         List<Element> modelListenerEls = root.elements("model-listener");
347 
348         for (Element modelListenerEl : modelListenerEls) {
349             String modelName = modelListenerEl.elementText("model-name");
350             String modelListenerClassName = modelListenerEl.elementText(
351                 "model-listener-class");
352 
353             ModelListener<BaseModel<?>> modelListener = initModelListener(
354                 modelName, modelListenerClassName, portletClassLoader);
355 
356             if (modelListener != null) {
357                 modelListenersContainer.registerModelListener(
358                     modelName, modelListener);
359             }
360         }
361 
362         EventsContainer eventsContainer = _eventsContainerMap.get(
363             servletContextName);
364 
365         if (eventsContainer == null) {
366             eventsContainer = new EventsContainer();
367 
368             _eventsContainerMap.put(servletContextName, eventsContainer);
369         }
370 
371         List<Element> eventEls = root.elements("event");
372 
373         for (Element eventEl : eventEls) {
374             String eventName = eventEl.elementText("event-type");
375             String eventClassName = eventEl.elementText("event-class");
376 
377             Object obj = initEvent(
378                 eventName, eventClassName, portletClassLoader);
379 
380             if (obj != null) {
381                 eventsContainer.registerEvent(eventName, obj);
382             }
383         }
384 
385         // End backwards compatibility for 5.1.0
386 
387         registerClpMessageListeners(servletContext, portletClassLoader);
388 
389         if (_log.isInfoEnabled()) {
390             _log.info(
391                 "Hook for " + servletContextName + " is available for use");
392         }
393     }
394 
395     protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
396         ServletContext servletContext = event.getServletContext();
397 
398         String servletContextName = servletContext.getServletContextName();
399 
400         if (_log.isDebugEnabled()) {
401             _log.debug("Invoking undeploy for " + servletContextName);
402         }
403 
404         if (!_servletContextNames.remove(servletContextName)) {
405             return;
406         }
407 
408         AuthenticatorsContainer authenticatorsContainer =
409             _authenticatorsContainerMap.remove(servletContextName);
410 
411         if (authenticatorsContainer != null) {
412             authenticatorsContainer.unregisterAuthenticators();
413         }
414 
415         AuthFailuresContainer authFailuresContainer =
416             _authFailuresContainerMap.remove(servletContextName);
417 
418         if (authFailuresContainer != null) {
419             authFailuresContainer.unregisterAuthFailures();
420         }
421 
422         AutoLoginsContainer autoLoginsContainer =
423             _autoLoginsContainerMap.remove(servletContextName);
424 
425         if (autoLoginsContainer != null) {
426             autoLoginsContainer.unregisterAutoLogins();
427         }
428 
429         CustomJspBag customJspBag = _customJspBagsMap.remove(
430             servletContextName);
431 
432         if (customJspBag != null) {
433             destroyCustomJspBag(customJspBag);
434         }
435 
436         EventsContainer eventsContainer = _eventsContainerMap.remove(
437             servletContextName);
438 
439         if (eventsContainer != null) {
440             eventsContainer.unregisterEvents();
441         }
442 
443         LanguagesContainer languagesContainer = _languagesContainerMap.remove(
444             servletContextName);
445 
446         if (languagesContainer != null) {
447             languagesContainer.unregisterLanguages();
448         }
449 
450         ModelListenersContainer modelListenersContainer =
451             _modelListenersContainerMap.remove(servletContextName);
452 
453         if (modelListenersContainer != null) {
454             modelListenersContainer.unregisterModelListeners();
455         }
456 
457         Properties portalProperties = _portalPropertiesMap.remove(
458             servletContextName);
459 
460         if (portalProperties != null) {
461             destroyPortalProperties(portalProperties);
462         }
463 
464         unregisterClpMessageListeners(servletContext);
465 
466         if (_log.isInfoEnabled()) {
467             _log.info("Hook for " + servletContextName + " was unregistered");
468         }
469     }
470 
471     protected void getCustomJsps(
472         ServletContext servletContext, String webDir, String resourcePath,
473         List<String> customJsps) {
474 
475         Set<String> resourcePaths = servletContext.getResourcePaths(
476             resourcePath);
477 
478         for (String curResourcePath : resourcePaths) {
479             if (curResourcePath.endsWith(StringPool.SLASH)) {
480                 getCustomJsps(
481                     servletContext, webDir, curResourcePath, customJsps);
482             }
483             else {
484                 String customJsp = webDir + curResourcePath;
485 
486                 customJsp = StringUtil.replace(
487                     customJsp, StringPool.DOUBLE_SLASH, StringPool.SLASH);
488 
489                 customJsps.add(customJsp);
490             }
491         }
492     }
493 
494     protected String getLocaleKey(String languagePropertiesLocation) {
495         String localeKey = null;
496 
497         int x = languagePropertiesLocation.indexOf(StringPool.UNDERLINE);
498         int y = languagePropertiesLocation.indexOf(".properties");
499 
500         if ((x != -1) && (y != 1)) {
501             localeKey = languagePropertiesLocation.substring(x + 1, y);
502         }
503 
504         return localeKey;
505     }
506 
507     protected BasePersistence getPersistence(String modelName) {
508         int pos = modelName.lastIndexOf(StringPool.PERIOD);
509 
510         String entityName = modelName.substring(pos + 1);
511 
512         pos = modelName.lastIndexOf(".model.");
513 
514         String packagePath = modelName.substring(0, pos);
515 
516         return (BasePersistence)PortalBeanLocatorUtil.locate(
517             packagePath + ".service.persistence." + entityName +
518                 "Persistence.impl");
519     }
520 
521     protected File getPortalJspBackupFile(File portalJspFile) {
522         String fileName = portalJspFile.toString();
523 
524         if (fileName.endsWith(".jsp")) {
525             fileName =
526                 fileName.substring(0, fileName.length() - 4) + ".portal.jsp";
527         }
528         else if (fileName.endsWith(".jspf")) {
529             fileName =
530                 fileName.substring(0, fileName.length() - 5) + ".portal.jspf";
531         }
532 
533         return new File(fileName);
534     }
535 
536     protected void initAuthenticators(
537             ClassLoader portletClassLoader, Properties portalProperties,
538             String key, AuthenticatorsContainer authenticatorsContainer)
539         throws Exception {
540 
541         String[] authenticatorClassNames = StringUtil.split(
542             portalProperties.getProperty(key));
543 
544         for (String authenticatorClassName : authenticatorClassNames) {
545             Authenticator authenticator =
546                 (Authenticator)portletClassLoader.loadClass(
547                     authenticatorClassName).newInstance();
548 
549             authenticator = (Authenticator)Proxy.newProxyInstance(
550                 portletClassLoader, new Class[] {Authenticator.class},
551                 new ContextClassLoaderBeanHandler(
552                     authenticator, portletClassLoader));
553 
554             authenticatorsContainer.registerAuthenticator(
555                 key, authenticator);
556         }
557     }
558 
559     protected void initAuthenticators(
560             String servletContextName, ClassLoader portletClassLoader,
561             Properties portalProperties)
562         throws Exception {
563 
564         AuthenticatorsContainer authenticatorsContainer =
565             new AuthenticatorsContainer();
566 
567         _authenticatorsContainerMap.put(
568             servletContextName, authenticatorsContainer);
569 
570         initAuthenticators(
571             portletClassLoader, portalProperties, AUTH_PIPELINE_PRE,
572             authenticatorsContainer);
573         initAuthenticators(
574             portletClassLoader, portalProperties, AUTH_PIPELINE_POST,
575             authenticatorsContainer);
576     }
577 
578     protected void initAuthFailures(
579             ClassLoader portletClassLoader, Properties portalProperties,
580             String key, AuthFailuresContainer authFailuresContainer)
581         throws Exception {
582 
583         String[] authFailureClassNames = StringUtil.split(
584             portalProperties.getProperty(key));
585 
586         for (String authFailureClassName : authFailureClassNames) {
587             AuthFailure authFailure = (AuthFailure)portletClassLoader.loadClass(
588                 authFailureClassName).newInstance();
589 
590             authFailure = (AuthFailure)Proxy.newProxyInstance(
591                 portletClassLoader, new Class[] {AuthFailure.class},
592                 new ContextClassLoaderBeanHandler(
593                     authFailure, portletClassLoader));
594 
595             authFailuresContainer.registerAuthFailure(
596                 key, authFailure);
597         }
598     }
599 
600     protected void initAuthFailures(
601             String servletContextName, ClassLoader portletClassLoader,
602             Properties portalProperties)
603         throws Exception {
604 
605         AuthFailuresContainer authFailuresContainer =
606             new AuthFailuresContainer();
607 
608         _authFailuresContainerMap.put(
609             servletContextName, authFailuresContainer);
610 
611         initAuthFailures(
612             portletClassLoader, portalProperties, AUTH_FAILURE,
613             authFailuresContainer);
614         initAuthFailures(
615             portletClassLoader, portalProperties, AUTH_MAX_FAILURES,
616             authFailuresContainer);
617     }
618 
619     protected void initAutoLogins(
620             String servletContextName, ClassLoader portletClassLoader,
621             Properties portalProperties)
622         throws Exception {
623 
624         AutoLoginsContainer autoLoginsContainer = new AutoLoginsContainer();
625 
626         _autoLoginsContainerMap.put(servletContextName, autoLoginsContainer);
627 
628         String[] autoLoginClassNames = StringUtil.split(
629             portalProperties.getProperty(AUTO_LOGIN_HOOKS));
630 
631         for (String autoLoginClassName : autoLoginClassNames) {
632             AutoLogin autoLogin = (AutoLogin)portletClassLoader.loadClass(
633                 autoLoginClassName).newInstance();
634 
635             autoLogin = (AutoLogin)Proxy.newProxyInstance(
636                 portletClassLoader, new Class[] {AutoLogin.class},
637                 new ContextClassLoaderBeanHandler(
638                     autoLogin, portletClassLoader));
639 
640             autoLoginsContainer.registerAutoLogin(autoLogin);
641         }
642     }
643 
644     protected void initCustomJspBag(CustomJspBag customJspBag)
645         throws Exception {
646 
647         String customJspDir = customJspBag.getCustomJspDir();
648         List<String> customJsps = customJspBag.getCustomJsps();
649         //String timestamp = customJspBag.getTimestamp();
650 
651         String portalWebDir = PortalUtil.getPortalWebDir();
652 
653         for (String customJsp : customJsps) {
654             int pos = customJsp.indexOf(customJspDir);
655 
656             String portalJsp = customJsp.substring(
657                 pos + customJspDir.length(), customJsp.length());
658 
659             File portalJspFile = new File(portalWebDir + portalJsp);
660             File portalJspBackupFile = getPortalJspBackupFile(portalJspFile);
661 
662             if (portalJspFile.exists() && !portalJspBackupFile.exists()) {
663                 FileUtil.copyFile(portalJspFile, portalJspBackupFile);
664             }
665 
666             String customJspContent = FileUtil.read(customJsp);
667 
668             FileUtil.write(portalJspFile, customJspContent);
669         }
670     }
671 
672     protected Object initEvent(
673             String eventName, String eventClassName,
674             ClassLoader portletClassLoader)
675         throws Exception {
676 
677         if (eventName.equals(APPLICATION_STARTUP_EVENTS)) {
678             SimpleAction simpleAction =
679                 (SimpleAction)portletClassLoader.loadClass(
680                     eventClassName).newInstance();
681 
682             simpleAction = new InvokerSimpleAction(
683                 simpleAction, portletClassLoader);
684 
685             long companyId = CompanyThreadLocal.getCompanyId();
686 
687             long[] companyIds = PortalInstances.getCompanyIds();
688 
689             for (long curCompanyId : companyIds) {
690                 CompanyThreadLocal.setCompanyId(curCompanyId);
691 
692                 simpleAction.run(new String[] {String.valueOf(curCompanyId)});
693             }
694 
695             CompanyThreadLocal.setCompanyId(companyId);
696 
697             return null;
698         }
699 
700         if (ArrayUtil.contains(_PROPS_KEYS_EVENTS, eventName)) {
701             Action action = (Action)portletClassLoader.loadClass(
702                 eventClassName).newInstance();
703 
704             action = new InvokerAction(action, portletClassLoader);
705 
706             EventsProcessorUtil.registerEvent(eventName, action);
707 
708             return action;
709         }
710 
711         if (ArrayUtil.contains(_PROPS_KEYS_SESSION_EVENTS, eventName)) {
712             SessionAction sessionAction =
713                 (SessionAction)portletClassLoader.loadClass(
714                     eventClassName).newInstance();
715 
716             sessionAction = new InvokerSessionAction(
717                 sessionAction, portletClassLoader);
718 
719             EventsProcessorUtil.registerEvent(eventName, sessionAction);
720 
721             return sessionAction;
722         }
723 
724         return null;
725     }
726 
727     protected void initEvents(
728             String servletContextName, ClassLoader portletClassLoader,
729             Properties portalProperties)
730         throws Exception {
731 
732         EventsContainer eventsContainer = new EventsContainer();
733 
734         _eventsContainerMap.put(servletContextName, eventsContainer);
735 
736         Iterator<Object> itr = portalProperties.keySet().iterator();
737 
738         while (itr.hasNext()) {
739             String key = (String)itr.next();
740 
741             if (!key.equals(APPLICATION_STARTUP_EVENTS) &&
742                 !ArrayUtil.contains(_PROPS_KEYS_EVENTS, key) &&
743                 !ArrayUtil.contains(_PROPS_KEYS_SESSION_EVENTS, key)) {
744 
745                 continue;
746             }
747 
748             String eventName = key;
749             String[] eventClassNames = StringUtil.split(
750                 portalProperties.getProperty(key));
751 
752             for (String eventClassName : eventClassNames) {
753                 Object obj = initEvent(
754                     eventName, eventClassName, portletClassLoader);
755 
756                 if (obj == null) {
757                     continue;
758                 }
759 
760                 eventsContainer.registerEvent(eventName, obj);
761             }
762         }
763     }
764 
765     protected ModelListener<BaseModel<?>> initModelListener(
766             String modelName, String modelListenerClassName,
767             ClassLoader portletClassLoader)
768         throws Exception {
769 
770         ModelListener<BaseModel<?>> modelListener =
771             (ModelListener<BaseModel<?>>)portletClassLoader.loadClass(
772                 modelListenerClassName).newInstance();
773 
774         modelListener = (ModelListener<BaseModel<?>>)Proxy.newProxyInstance(
775             portletClassLoader, new Class[] {ModelListener.class},
776             new ContextClassLoaderBeanHandler(
777                 modelListener, portletClassLoader));
778 
779         BasePersistence persistence = getPersistence(modelName);
780 
781         persistence.registerListener(modelListener);
782 
783         return modelListener;
784     }
785 
786     protected void initModelListeners(
787             String servletContextName, ClassLoader portletClassLoader,
788             Properties portalProperties)
789         throws Exception {
790 
791         ModelListenersContainer modelListenersContainer =
792             new ModelListenersContainer();
793 
794         _modelListenersContainerMap.put(
795             servletContextName, modelListenersContainer);
796 
797         Iterator<Object> itr = portalProperties.keySet().iterator();
798 
799         while (itr.hasNext()) {
800             String key = (String)itr.next();
801 
802             if (!key.startsWith(VALUE_OBJECT_LISTENER)) {
803                 continue;
804             }
805 
806             String modelName = key.substring(VALUE_OBJECT_LISTENER.length());
807             String modelListenerClassName = portalProperties.getProperty(key);
808 
809             ModelListener<BaseModel<?>> modelListener = initModelListener(
810                 modelName, modelListenerClassName, portletClassLoader);
811 
812             if (modelListener != null) {
813                 modelListenersContainer.registerModelListener(
814                     modelName, modelListener);
815             }
816         }
817     }
818 
819     protected void initPortalProperties(
820             ClassLoader portletClassLoader, Properties portalProperties)
821         throws Exception {
822 
823         PropsUtil.addProperties(portalProperties);
824 
825         if (_log.isDebugEnabled() && portalProperties.containsKey(LOCALES)) {
826             _log.debug(
827                 "Portlet locales " + portalProperties.getProperty(LOCALES));
828             _log.debug("Merged locales " + PropsUtil.get(LOCALES));
829             _log.debug(
830                 "Merged locales array length " +
831                     PropsUtil.getArray(LOCALES).length);
832         }
833 
834         resetPortalProperties(portalProperties);
835 
836         if (portalProperties.contains(PropsKeys.LDAP_ATTRS_TRANSFORMER_IMPL)) {
837             String attributesTransformerClassName =
838                 portalProperties.getProperty(
839                     PropsKeys.LDAP_ATTRS_TRANSFORMER_IMPL);
840 
841             AttributesTransformer attributesTransformer =
842                 (AttributesTransformer)portletClassLoader.loadClass(
843                     attributesTransformerClassName).newInstance();
844 
845             attributesTransformer =
846                 (AttributesTransformer)Proxy.newProxyInstance(
847                     portletClassLoader,
848                     new Class[] {AttributesTransformer.class},
849                     new ContextClassLoaderBeanHandler(
850                         attributesTransformer, portletClassLoader));
851 
852             AttributesTransformerFactory.setInstance(attributesTransformer);
853         }
854     }
855 
856     protected void resetPortalProperties(Properties portalProperties)
857         throws Exception {
858 
859         for (String key : _PROPS_VALUES_BOOLEAN) {
860             String fieldName = StringUtil.replace(
861                 key.toUpperCase(), StringPool.PERIOD,  StringPool.UNDERLINE);
862 
863             if (!containsKey(portalProperties, key)) {
864                 continue;
865             }
866 
867             try {
868                 Field field = PropsValues.class.getField(fieldName);
869 
870                 Boolean value = Boolean.valueOf(GetterUtil.getBoolean(
871                     PropsUtil.get(key)));
872 
873                 field.setBoolean(null, value);
874             }
875             catch (Exception e) {
876                 _log.error(
877                     "Error setting field " + fieldName + ": " + e.getMessage());
878             }
879         }
880 
881         for (String key : _PROPS_VALUES_INTEGER) {
882             String fieldName = StringUtil.replace(
883                 key.toUpperCase(), StringPool.PERIOD,  StringPool.UNDERLINE);
884 
885             if (!containsKey(portalProperties, key)) {
886                 continue;
887             }
888 
889             try {
890                 Field field = PropsValues.class.getField(fieldName);
891 
892                 Integer value = Integer.valueOf(GetterUtil.getInteger(
893                     PropsUtil.get(key)));
894 
895                 field.setInt(null, value);
896             }
897             catch (Exception e) {
898                 _log.error(
899                     "Error setting field " + fieldName + ": " + e.getMessage());
900             }
901         }
902 
903         for (String key : _PROPS_VALUES_LONG) {
904             String fieldName = StringUtil.replace(
905                 key.toUpperCase(), StringPool.PERIOD,  StringPool.UNDERLINE);
906 
907             if (!containsKey(portalProperties, key)) {
908                 continue;
909             }
910 
911             try {
912                 Field field = PropsValues.class.getField(fieldName);
913 
914                 Long value = Long.valueOf(GetterUtil.getLong(
915                     PropsUtil.get(key)));
916 
917                 field.setLong(null, value);
918             }
919             catch (Exception e) {
920                 _log.error(
921                     "Error setting field " + fieldName + ": " + e.getMessage());
922             }
923         }
924 
925         for (String key : _PROPS_VALUES_STRING) {
926             String fieldName = StringUtil.replace(
927                 key.toUpperCase(), StringPool.PERIOD,  StringPool.UNDERLINE);
928 
929             if (!containsKey(portalProperties, key)) {
930                 continue;
931             }
932 
933             try {
934                 Field field = PropsValues.class.getField(fieldName);
935 
936                 String value = GetterUtil.getString(PropsUtil.get(key));
937 
938                 field.set(null, value);
939             }
940             catch (Exception e) {
941                 _log.error(
942                     "Error setting field " + fieldName + ": " + e.getMessage());
943             }
944         }
945 
946         for (String key : _PROPS_VALUES_STRING_ARRAY) {
947             String fieldName = StringUtil.replace(
948                 key.toUpperCase(), StringPool.PERIOD,  StringPool.UNDERLINE);
949 
950             if (!containsKey(portalProperties, key)) {
951                 continue;
952             }
953 
954             try {
955                 Field field = PropsValues.class.getField(fieldName);
956 
957                 String[] value = PropsUtil.getArray(key);
958 
959                 field.set(null, value);
960             }
961             catch (Exception e) {
962                 _log.error(
963                     "Error setting field " + fieldName + ": " + e.getMessage());
964             }
965         }
966 
967         if (containsKey(portalProperties, LOCALES)) {
968             PropsValues.LOCALES = PropsUtil.getArray(LOCALES);
969 
970             LanguageUtil.init();
971         }
972 
973         CacheUtil.clearCache();
974     }
975 
976     private static final String[] _PROPS_KEYS_EVENTS = new String[] {
977         LOGIN_EVENTS_POST,
978         LOGIN_EVENTS_PRE,
979         LOGOUT_EVENTS_POST,
980         LOGOUT_EVENTS_PRE,
981         SERVLET_SERVICE_EVENTS_POST,
982         SERVLET_SERVICE_EVENTS_PRE
983     };
984 
985     private static final String[] _PROPS_KEYS_SESSION_EVENTS = new String[] {
986         SERVLET_SESSION_CREATE_EVENTS,
987         SERVLET_SESSION_DESTROY_EVENTS
988     };
989 
990     private static final String[] _PROPS_VALUES_BOOLEAN = new String[] {
991         "auth.forward.by.last.path",
992         "captcha.check.portal.create_account",
993         "field.enable.com.liferay.portal.model.Contact.birthday",
994         "field.enable.com.liferay.portal.model.Contact.male",
995         "field.enable.com.liferay.portal.model.Organization.status",
996         "javascript.fast.load",
997         "layout.template.cache.enabled",
998         "layout.user.private.layouts.auto.create",
999         "layout.user.private.layouts.enabled",
1000        "layout.user.private.layouts.modifiable",
1001        "layout.user.public.layouts.auto.create",
1002        "layout.user.public.layouts.enabled",
1003        "layout.user.public.layouts.modifiable",
1004        "login.create.account.allow.custom.password",
1005        "my.places.show.community.private.sites.with.no.layouts",
1006        "my.places.show.community.public.sites.with.no.layouts",
1007        "my.places.show.organization.private.sites.with.no.layouts",
1008        "my.places.show.organization.public.sites.with.no.layouts",
1009        "my.places.show.user.private.sites.with.no.layouts",
1010        "my.places.show.user.public.sites.with.no.layouts",
1011        "terms.of.use.required",
1012        "theme.css.fast.load",
1013        "theme.images.fast.load"
1014    };
1015
1016    private static final String[] _PROPS_VALUES_INTEGER = new String[] {
1017    };
1018
1019    private static final String[] _PROPS_VALUES_LONG = new String[] {
1020    };
1021
1022    private static final String[] _PROPS_VALUES_STRING = new String[] {
1023        "default.landing.page.path",
1024        "passwords.passwordpolicytoolkit.generator",
1025        "passwords.passwordpolicytoolkit.static"
1026    };
1027
1028    private static final String[] _PROPS_VALUES_STRING_ARRAY = new String[] {
1029        "layout.static.portlets.all",
1030        "session.phishing.protected.attributes"
1031    };
1032
1033    private static Log _log =
1034        LogFactoryUtil.getLog(HookHotDeployListener.class);
1035
1036    private Map<String, AuthenticatorsContainer> _authenticatorsContainerMap =
1037        new HashMap<String, AuthenticatorsContainer>();
1038    private Map<String, AuthFailuresContainer> _authFailuresContainerMap =
1039        new HashMap<String, AuthFailuresContainer>();
1040    private Map<String, AutoLoginsContainer> _autoLoginsContainerMap =
1041        new HashMap<String, AutoLoginsContainer>();
1042    private Map<String, CustomJspBag> _customJspBagsMap =
1043        new HashMap<String, CustomJspBag>();
1044    private Map<String, EventsContainer> _eventsContainerMap =
1045        new HashMap<String, EventsContainer>();
1046    private Map<String, LanguagesContainer> _languagesContainerMap =
1047        new HashMap<String, LanguagesContainer>();
1048    private Map<String, ModelListenersContainer> _modelListenersContainerMap =
1049        new HashMap<String, ModelListenersContainer>();
1050    private Map<String, Properties> _portalPropertiesMap =
1051        new HashMap<String, Properties>();
1052    private Set<String> _servletContextNames = new HashSet<String>();
1053
1054    private class AuthenticatorsContainer {
1055
1056        public void registerAuthenticator(
1057            String key, Authenticator authenticator) {
1058
1059            List<Authenticator> authenticators = _authenticators.get(key);
1060
1061            if (authenticators == null) {
1062                authenticators = new ArrayList<Authenticator>();
1063
1064                _authenticators.put(key, authenticators);
1065            }
1066
1067            AuthPipeline.registerAuthenticator(key, authenticator);
1068
1069            authenticators.add(authenticator);
1070        }
1071
1072        public void unregisterAuthenticators() {
1073            for (Map.Entry<String, List<Authenticator>> entry :
1074                    _authenticators.entrySet()) {
1075
1076                String key = entry.getKey();
1077                List<Authenticator> authenticators = entry.getValue();
1078
1079                for (Authenticator authenticator : authenticators) {
1080                    AuthPipeline.unregisterAuthenticator(key, authenticator);
1081                }
1082            }
1083        }
1084
1085        Map<String, List<Authenticator>> _authenticators =
1086            new HashMap<String, List<Authenticator>>();
1087
1088    }
1089
1090    private class AuthFailuresContainer {
1091
1092        public void registerAuthFailure(String key, AuthFailure authFailure) {
1093            List<AuthFailure> authFailures = _authFailures.get(key);
1094
1095            if (authFailures == null) {
1096                authFailures = new ArrayList<AuthFailure>();
1097
1098                _authFailures.put(key, authFailures);
1099            }
1100
1101            AuthPipeline.registerAuthFailure(key, authFailure);
1102
1103            authFailures.add(authFailure);
1104        }
1105
1106        public void unregisterAuthFailures() {
1107            for (Map.Entry<String, List<AuthFailure>> entry :
1108                    _authFailures.entrySet()) {
1109
1110                String key = entry.getKey();
1111                List<AuthFailure> authFailures = entry.getValue();
1112
1113                for (AuthFailure authFailure : authFailures) {
1114                    AuthPipeline.unregisterAuthFailure(key, authFailure);
1115                }
1116            }
1117        }
1118
1119        Map<String, List<AuthFailure>> _authFailures =
1120            new HashMap<String, List<AuthFailure>>();
1121
1122    }
1123
1124    private class AutoLoginsContainer {
1125
1126        public void registerAutoLogin(AutoLogin autoLogin) {
1127            AutoLoginFilter.registerAutoLogin(autoLogin);
1128
1129            _autoLogins.add(autoLogin);
1130        }
1131
1132        public void unregisterAutoLogins() {
1133            for (AutoLogin autoLogin : _autoLogins) {
1134                AutoLoginFilter.unregisterAutoLogin(autoLogin);
1135            }
1136        }
1137
1138        List<AutoLogin> _autoLogins = new ArrayList<AutoLogin>();
1139
1140    }
1141
1142    private class CustomJspBag {
1143
1144        public CustomJspBag(String customJspDir, List<String> customJsps) {
1145            _customJspDir = customJspDir;
1146            _customJsps = customJsps;
1147        }
1148
1149        public String getCustomJspDir() {
1150            return _customJspDir;
1151        }
1152
1153        public List<String> getCustomJsps() {
1154            return _customJsps;
1155        }
1156
1157        private String _customJspDir;
1158        private List<String> _customJsps;
1159
1160    }
1161
1162    private class EventsContainer {
1163
1164        public void registerEvent(String eventName, Object event) {
1165            List<Object> events = _eventsMap.get(eventName);
1166
1167            if (events == null) {
1168                events = new ArrayList<Object>();
1169
1170                _eventsMap.put(eventName, events);
1171            }
1172
1173            events.add(event);
1174        }
1175
1176        public void unregisterEvents() {
1177            for (Map.Entry<String, List<Object>> entry :
1178                    _eventsMap.entrySet()) {
1179
1180                String eventName = entry.getKey();
1181                List<Object> events = entry.getValue();
1182
1183                for (Object event : events) {
1184                    EventsProcessorUtil.unregisterEvent(eventName, event);
1185                }
1186            }
1187        }
1188
1189        private Map<String, List<Object>> _eventsMap =
1190            new HashMap<String, List<Object>>();
1191
1192    }
1193
1194    private class LanguagesContainer {
1195
1196        public void addLanguage(String localeKey, Properties properties) {
1197            _multiMessageResources.putLocale(localeKey);
1198
1199            Properties oldProperties = _multiMessageResources.putMessages(
1200                properties, localeKey);
1201
1202            _languagesMap.put(localeKey, oldProperties);
1203        }
1204
1205        public void unregisterLanguages() {
1206            for (String key : _languagesMap.keySet()) {
1207                Properties properties = _languagesMap.get(key);
1208
1209                _multiMessageResources.putMessages(properties, key);
1210            }
1211        }
1212
1213        private Map<String, Properties> _languagesMap =
1214            new HashMap<String, Properties>();
1215        private MultiMessageResources _multiMessageResources =
1216            MultiMessageResourcesFactory.getInstance();
1217
1218    }
1219
1220    private class ModelListenersContainer {
1221
1222        public void registerModelListener(
1223            String modelName, ModelListener<BaseModel<?>> modelListener) {
1224
1225            List<ModelListener<BaseModel<?>>> modelListeners =
1226                _modelListenersMap.get(modelName);
1227
1228            if (modelListeners == null) {
1229                modelListeners = new ArrayList<ModelListener<BaseModel<?>>>();
1230
1231                _modelListenersMap.put(modelName, modelListeners);
1232            }
1233
1234            modelListeners.add(modelListener);
1235        }
1236
1237        public void unregisterModelListeners() {
1238            for (Map.Entry<String, List<ModelListener<BaseModel<?>>>> entry :
1239                    _modelListenersMap.entrySet()) {
1240
1241                String modelName = entry.getKey();
1242                List<ModelListener<BaseModel<?>>> modelListeners =
1243                    entry.getValue();
1244
1245                BasePersistence persistence = getPersistence(modelName);
1246
1247                for (ModelListener<BaseModel<?>> modelListener :
1248                        modelListeners) {
1249
1250                    persistence.unregisterListener(modelListener);
1251                }
1252            }
1253        }
1254
1255        private Map<String, List<ModelListener<BaseModel<?>>>>
1256            _modelListenersMap =
1257                new HashMap<String, List<ModelListener<BaseModel<?>>>>();
1258
1259    }
1260
1261}