/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.notifd;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.util.IOUtils;
import org.opennms.core.utils.Argument;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.config.NotificationManager;
import org.opennms.netmgt.dao.NodeDao;
import org.opennms.netmgt.model.OnmsAssetRecord;
import org.opennms.netmgt.model.OnmsCategory;
import org.opennms.netmgt.model.OnmsNode;
/**
* @author <A HREF="mailto:jeffg@opennms.org">Jeff Gehlbach</A>
* @author <A HREF="http://www.opennms.org">OpenNMS</A>
*
*/
public class BSFNotificationStrategy implements NotificationStrategy {
private List<Argument> m_arguments;
private Map<String,String> m_notifParams = new HashMap<String,String>();
/* (non-Javadoc)
* @see org.opennms.netmgt.notifd.NotificationStrategy#send(java.util.List)
*/
@Override
public int send(List<Argument> arguments) {
m_arguments = arguments;
String fileName = getFileName();
String lang = getLangClass();
String engine = getBsfEngine();
String extensions[] = getFileExtensions();
LogUtils.infof(this, "Loading notification script from file '%s'", fileName);
File scriptFile = new File(fileName);
BSFManager bsfManager = new BSFManager();
int returnCode = -1;
try {
if(lang==null) lang = BSFManager.getLangFromFilename(fileName);
// Declare some beans that can be used inside the script
HashMap<String,String> results = new HashMap<String,String>();
bsfManager.declareBean("results", results, HashMap.class);
declareBeans(bsfManager);
if(engine != null && lang != null && extensions != null && extensions.length > 0 ){
BSFManager.registerScriptingEngine(lang, engine, extensions);
}
if(scriptFile.exists() && scriptFile.canRead()){
String code = IOUtils.getStringFromReader(new InputStreamReader(new FileInputStream(scriptFile), "UTF-8"));
// Check foot before firing
checkAberrantScriptBehaviors(code);
// Execute the script
bsfManager.exec(lang, "BSFNotificationStrategy", 0, 0, code);
// Check whether the script finished successfully
if ("OK".equals(results.get("status"))) {
LogUtils.infof(this, "Execution succeeded and successful status passed back for script '%s'", scriptFile);
returnCode = 0;
} else {
LogUtils.warnf(this, "Execution succeeded for script '%s', but script did not indicate successful notification by putting an entry into the 'results' bean with key 'status' and value 'OK'", scriptFile);
returnCode = -1;
}
} else {
LogUtils.warnf(this, "Cannot locate or read BSF script file '%s'. Returning failure indication.", fileName);
returnCode = -1;
}
} catch (BSFException e) {
LogUtils.warnf(this, e, "Execution of script '%s' failed with BSFException: %s", scriptFile, e.getMessage());
returnCode = -1;
} catch (FileNotFoundException e){
LogUtils.warnf(this, "Could not find BSF script file '%s'.", fileName);
returnCode = -1;
} catch (IOException e) {
LogUtils.warnf(this, e, "Execution of script '%s' failed with IOException: %s", scriptFile, e.getMessage());
returnCode = -1;
} catch (Throwable e) {
// Catch any RuntimeException throws
LogUtils.warnf(this, e, "Execution of script '%s' failed with unexpected throwable: %s", scriptFile, e.getMessage());
returnCode = -1;
} finally {
bsfManager.terminate();
}
return returnCode;
}
private void declareBeans(BSFManager bsfManager) throws BSFException {
NodeDao nodeDao = Notifd.getInstance().getNodeDao();
Integer nodeId;
try {
nodeId = Integer.valueOf(m_notifParams.get(NotificationManager.PARAM_NODE));
} catch (NumberFormatException nfe) {
nodeId = null;
}
OnmsNode node = null;
OnmsAssetRecord assets = null;
List<String> categories = new ArrayList<String>();
String nodeLabel = null;
String foreignSource = null;
String foreignId = null;
if (nodeId != null) {
node = nodeDao.get(nodeId);
nodeLabel = node.getLabel();
assets = node.getAssetRecord();
for (OnmsCategory cat : node.getCategories()) {
categories.add(cat.getName());
}
foreignSource = node.getForeignSource();
foreignId = node.getForeignId();
}
bsfManager.declareBean("bsf_notif_strategy", this, BSFNotificationStrategy.class);
retrieveParams();
bsfManager.declareBean("notif_params", m_notifParams, Map.class);
bsfManager.declareBean("node_label", nodeLabel, String.class);
bsfManager.declareBean("foreign_source", foreignSource, String.class);
bsfManager.declareBean("foreign_id", foreignId, String.class);
bsfManager.declareBean("node_assets", assets, OnmsAssetRecord.class);
bsfManager.declareBean("node_categories", categories, List.class);
bsfManager.declareBean("node", node, OnmsNode.class);
for (Argument arg : m_arguments) {
if (NotificationManager.PARAM_TEXT_MSG.equals(arg.getSwitch())) bsfManager.declareBean("text_message", arg.getValue(), String.class);
if (NotificationManager.PARAM_NUM_MSG.equals(arg.getSwitch())) bsfManager.declareBean("numeric_message", arg.getValue(), String.class);
if (NotificationManager.PARAM_NODE.equals(arg.getSwitch())) bsfManager.declareBean("node_id", arg.getValue(), String.class);
if (NotificationManager.PARAM_INTERFACE.equals(arg.getSwitch())) bsfManager.declareBean("ip_addr", arg.getValue(), String.class);
if (NotificationManager.PARAM_SERVICE.equals(arg.getSwitch())) bsfManager.declareBean("svc_name", arg.getValue(), String.class);
if (NotificationManager.PARAM_SUBJECT.equals(arg.getSwitch())) bsfManager.declareBean("subject", arg.getValue(), String.class);
if (NotificationManager.PARAM_EMAIL.equals(arg.getSwitch())) bsfManager.declareBean("email", arg.getValue(), String.class);
if (NotificationManager.PARAM_PAGER_EMAIL.equals(arg.getSwitch())) bsfManager.declareBean("pager_email", arg.getValue(), String.class);
if (NotificationManager.PARAM_XMPP_ADDRESS.equals(arg.getSwitch())) bsfManager.declareBean("xmpp_address", arg.getValue(), String.class);
if (NotificationManager.PARAM_TEXT_PAGER_PIN.equals(arg.getSwitch())) bsfManager.declareBean("text_pin", arg.getValue(), String.class);
if (NotificationManager.PARAM_NUM_PAGER_PIN.equals(arg.getSwitch())) bsfManager.declareBean("numeric_pin", arg.getValue(), String.class);
if (NotificationManager.PARAM_WORK_PHONE.equals(arg.getSwitch())) bsfManager.declareBean("work_phone", arg.getValue(), String.class);
if (NotificationManager.PARAM_HOME_PHONE.equals(arg.getSwitch())) bsfManager.declareBean("home_phone", arg.getValue(), String.class);
if (NotificationManager.PARAM_MOBILE_PHONE.equals(arg.getSwitch())) bsfManager.declareBean("mobile_phone", arg.getValue(), String.class);
if (NotificationManager.PARAM_TUI_PIN.equals(arg.getSwitch())) bsfManager.declareBean("phone_pin", arg.getValue(), String.class);
if (NotificationManager.PARAM_MICROBLOG_USERNAME.equals(arg.getSwitch())) bsfManager.declareBean("microblog_username", arg.getValue(), String.class);
}
}
@SuppressWarnings("unused")
private String getSwitchValue(String argSwitch) {
String value = null;
for (Argument arg : m_arguments) {
if (arg.getSwitch().equals(argSwitch)) {
value = arg.getValue();
}
}
if (value != null && value.equals("")) value = null;
return value;
}
private String getSwitchSubstitution(String argSwitch) {
String value = null;
for (Argument arg : m_arguments) {
if (arg.getSwitch().equals(argSwitch)) {
value = arg.getSubstitution();
}
}
if (value != null && value.equals("")) value = null;
return value;
}
private void checkAberrantScriptBehaviors(String script) {
if (script.matches("(?s)\\.exec\\s*\\(")) {
// Here we should check for stupid stuff like use of System.exec()
// and log stern warnings if found.
}
}
private String getFileName() {
return getSwitchSubstitution("file-name");
}
private String getLangClass() {
return getSwitchSubstitution("lang-class");
}
private String getBsfEngine() {
return getSwitchSubstitution("bsf-engine");
}
private String[] getFileExtensions() {
String exts = getSwitchSubstitution("file-extensions");
if (exts == null) return null;
return exts.split(",");
}
private void retrieveParams() {
for (Argument arg : m_arguments) {
m_notifParams.put(arg.getSwitch(), arg.getValue());
}
}
public void log(String level, String format, Object... args) {
if ("TRACE".equals(level)) LogUtils.tracef(this, format, args);
if ("DEBUG".equals(level)) LogUtils.debugf(this, format, args);
if ("INFO".equals(level)) LogUtils.infof(this, format, args);
if ("WARN".equals(level)) LogUtils.warnf(this, format, args);
if ("ERROR".equals(level)) LogUtils.errorf(this, format, args);
if ("FATAL".equals(level)) LogUtils.errorf(this, format, args);
}
}