/* * RHQ Management Platform * Copyright (C) 2005-2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.plugin.pc.alert; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.rhq.core.domain.alert.notification.AlertNotification; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.plugin.PluginKey; import org.rhq.core.domain.plugin.ServerPlugin; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.enterprise.server.plugin.ServerPluginManagerLocal; import org.rhq.enterprise.server.plugin.pc.AbstractTypeServerPluginContainer; import org.rhq.enterprise.server.plugin.pc.ServerPluginContext; import org.rhq.enterprise.server.plugin.pc.ServerPluginEnvironment; import org.rhq.enterprise.server.plugin.pc.ServerPluginManager; import org.rhq.enterprise.server.util.LookupUtil; import org.rhq.enterprise.server.xmlschema.generated.serverplugin.alert.AlertPluginDescriptorType; import org.rhq.enterprise.server.xmlschema.generated.serverplugin.alert.CustomUi; /** * Plugin manager that takes care of loading the plug-ins and instantiating * of {@link AlertSender} etc. * @author Heiko W. Rupp */ public class AlertSenderPluginManager extends ServerPluginManager { private final Log log = getLog(); private Map<String, String> pluginClassByName = new HashMap<String, String>(); private Map<String, ServerPluginEnvironment> pluginEnvByName = new HashMap<String, ServerPluginEnvironment>(); private Map<String, AlertSenderInfo> senderInfoByName = new HashMap<String, AlertSenderInfo>(); private Map<String, String> backingBeanByName = new HashMap<String, String>(); private Map<String, String> backingBeanNameByName = new HashMap<String, String>(); public AlertSenderPluginManager(AbstractTypeServerPluginContainer pc) { super(pc); } /** * Postprocess the loading of the plugin - the actual load is done * in the super class. * Here we verify that the passed <plugin-class> is valid and build the * list of plugins that can be queried by the UI etc. * * @param env the environment of the plugin to be loaded * @param enabled if <code>true</code>, the plugin is to be enabled and will be started soon * * @throws Exception if the alert plugin could not be loaded due to errors such as the alert class being invalid */ @Override public void loadPlugin(ServerPluginEnvironment env, boolean enabled) throws Exception { super.loadPlugin(env, enabled); if (enabled) { AlertPluginDescriptorType type = (AlertPluginDescriptorType) env.getPluginDescriptor(); // make sure the alert sender class name is valid String className = type.getPluginClass(); try { loadPluginClass(env, className, false); } catch (Exception e) { log.error("Alert sender class [" + className + "] defined in plugin [" + env.getPluginKey().getPluginName() + "] is invalid and will be ignored. Cause: " + ThrowableUtil.getAllMessages(e)); try { unloadPlugin(env.getPluginKey().getPluginName()); } catch (Throwable t) { log.warn(" +--> unload failed too. Cause: " + ThrowableUtil.getAllMessages(t)); } throw e; } // // Ok, we have a valid plugin class, so we can look for other things and store the info // // The short name is basically the key into the plugin String shortName = type.getShortName(); pluginClassByName.put(shortName, className); // UI snippet path allows the plugin to inject user interface fragments to the alert pages String uiSnippetPath = null; URL uiSnippetUrl = null; CustomUi customUI = type.getCustomUi(); if (customUI != null) { uiSnippetPath = customUI.getUiSnippetName(); try { uiSnippetUrl = env.getPluginClassLoader().getResource(uiSnippetPath); if (uiSnippetUrl == null) { throw new Exception("plugin is missing alert ui snippet named [" + uiSnippetPath + "]"); } log.debug("Alert plugin UI snippet for [" + shortName + "] is at: " + uiSnippetUrl); } catch (Exception e) { log.error("Invalid alert UI snippet provided inside <custom-ui> for alert plugin [" + shortName + "]. Plugin will be ignored. Cause: " + ThrowableUtil.getAllMessages(e)); throw e; } className = customUI.getBackingBeanClass(); try { loadPluginClass(env, className, true); // TODO how make this available to Seam and the Web-CL ? backingBeanByName.put(shortName, className); } catch (Throwable t) { String errMsg = "Backing bean [" + className + "] not found for plugin [" + shortName + ']'; log.error(errMsg); throw new Exception(errMsg, t); } String beanName = customUI.getBackingBeanName(); // Default to <backing-bean-class> value if name is not provided if (beanName == null || beanName.length() == 0) { beanName = className; } backingBeanNameByName.put(shortName, beanName); } AlertSenderInfo info = new AlertSenderInfo(shortName, type.getDescription(), env.getPluginKey()); info.setUiSnippetUrl(uiSnippetUrl); info.setUiSnippetShortPath(uiSnippetPath); senderInfoByName.put(shortName, info); pluginEnvByName.put(shortName, env); } } @Override protected void unloadPlugin(String pluginName) throws Exception { super.unloadPlugin(pluginName); String shortName = null; for (AlertSenderInfo info : senderInfoByName.values()) { if (info.getPluginName().equals(pluginName)) { shortName = info.getShortName(); break; } } if (shortName != null) { pluginClassByName.remove(shortName); senderInfoByName.remove(shortName); pluginEnvByName.remove(shortName); backingBeanByName.remove(shortName); } } /** * Instantiate an AlertSender for the passed shortName, which is the name you have provided * in the plugin descriptor in the <shortName> element * @param notification The alert notification we need the sender for. Wanted sender is in notification.getSenderName() * @return a new AlertSender with preferences set * @see AlertSender */ public AlertSender getAlertSenderForNotification(AlertNotification notification) { String senderName = notification.getSenderName(); String className = pluginClassByName.get(senderName); if (className == null) { log.error("getAlertSenderForNotification: No pluginClass found for sender: " + senderName); return null; } ServerPluginEnvironment env = pluginEnvByName.get(senderName); AlertSender sender; try { sender = (AlertSender) instantiatePluginClass(env, className); } catch (Exception e) { log.error(e); // TODO return null; } // We have no entityManager lying around here, which means // Configuration is an uninitialized Proxy and we'd get a LazyInit // Exception later. // So lets get it from the SessionBeans sender.alertParameters = getNewOrCleansed(notification.getConfiguration()); sender.extraParameters = getNewOrCleansed(notification.getExtraConfiguration()); ServerPluginContext ctx = getServerPluginContext(env); PluginKey key = ctx.getPluginEnvironment().getPluginKey(); ServerPluginManagerLocal pluginsMgr = LookupUtil.getServerPluginManager(); ServerPlugin plugin = pluginsMgr.getServerPlugin(key); plugin = pluginsMgr.getServerPluginRelationships(plugin); sender.preferences = getNewOrCleansed(plugin.getPluginConfiguration()); sender.pluginComponent = getServerPluginComponent(key.getPluginName()); sender.serverPluginEnvironment = pluginEnvByName.get(senderName); return sender; } private Configuration getNewOrCleansed(Configuration config) { if (config == null) { return new Configuration(); } else { return config.deepCopy(); } } /** * Return the list of deployed alert sender plug-ins by their <shortName> * @return List of plugin names */ public List<String> getPluginList() { return new ArrayList<String>(pluginClassByName.keySet()); } public AlertSenderInfo getAlertSenderInfo(String shortName) { return senderInfoByName.get(shortName); } public CustomAlertSenderBackingBean getBackingBeanForSender(String shortName) { String className = backingBeanByName.get(shortName); //className = "Local" + className; if (className == null) { return null; } ServerPluginEnvironment env = pluginEnvByName.get(shortName); CustomAlertSenderBackingBean bean = null; try { bean = (CustomAlertSenderBackingBean) instantiatePluginClass(env, className); bean.alertParameters = new Configuration(); // Just to be sure } catch (Exception e) { log.error("Can't instantiate alert sender backing bean [" + className + "]. Cause: " + e.getMessage()); } return bean; } public String getBackingBeanNameForSender(String shortName) { return backingBeanNameByName.get(shortName); } }