/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2009-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.protocols.xmp.capsd;
import java.net.InetAddress;
import java.util.Map;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import org.krupczak.Xmp.SocketOpts;
import org.krupczak.Xmp.Xmp;
import org.krupczak.Xmp.XmpSession;
import org.opennms.core.utils.ParameterMap;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.capsd.AbstractPlugin;
import org.opennms.netmgt.config.xmpConfig.XmpConfig;
import org.opennms.netmgt.protocols.xmp.XmpUtil;
import org.opennms.netmgt.protocols.xmp.XmpUtilException;
import org.opennms.netmgt.protocols.xmp.config.XmpConfigFactory;
/**
* <P>
* This class is designed to be used by the capabilities daemon to test for the
* existence of an XMP (XML Management Protocol) daemon on remote interfaces,
* optionally also checking for the presence and value of specified MIB objects.
* The class implements the Plugin interface that allows it to be used along
* with other plugins by the daemon.
* </P>
*
* @author <A HREF="mailto:jeffg@opennms.org">Jeff Gehlbach</A>
* @author <A HREF="http://www.opennms.org">OpenNMS </A>
* @author <A HREF="mailto:jeffg@opennms.org">Jeff Gehlbach</A>
* @author <A HREF="http://www.opennms.org">OpenNMS </A>
* @version $Id: $
*/
public final class XmpPlugin extends AbstractPlugin {
/**
* The protocol supported by the plugin
*/
private final static String PROTOCOL_NAME = "XMP";
/**
* The default port to use for XMP
*/
private final static int DEFAULT_PORT = Xmp.XMP_PORT;
/**
* Default number of retries for TCP requests
*/
private final static int DEFAULT_RETRY = 0;
/**
* Default timeout (in milliseconds) for XMP requests
*/
private final static int DEFAULT_TIMEOUT = 5000; // in milliseconds
/**
* Default XMP user for performing requests
*/
private final static String DEFAULT_AUTHEN_USER = "xmpUser";
/**
* Default type of request to perform
*/
private final static String DEFAULT_REQUEST_TYPE = "GetRequest";
/**
* Default MIB from which to make request
*/
private final static String DEFAULT_REQUEST_MIB = "core";
/**
* Default table from which to make request
*/
private final static String DEFAULT_REQUEST_TABLE = "";
/**
* Default object name to request
*/
private final static String DEFAULT_REQUEST_OBJECT = "sysObjectID";
/**
* Default instance to request (for SelectTableRequest only)
*/
private final static String DEFAULT_REQUEST_INSTANCE = "*";
/**
* Default string against which to match the returned value(s)
*/
private final static String DEFAULT_VALUE_MATCH = null;
/**
* Default string against which to match the returned instance(s)
*/
private final static String DEFAULT_INSTANCE_MATCH = null;
/**
* Default integer denoting minimum number of
* matches allowed
*/
private final static int DEFAULT_MIN_MATCHES = 1;
/**
* Default integer denoting maximum number of
* matches allowed.
*/
private final static int DEFAULT_MAX_MATCHES = 1;
/**
* Default boolean indicating whether maximum number
* of matches is actually unbounded
*/
private final static boolean DEFAULT_MAX_MATCHES_UNBOUNDED = true;
private static final boolean DEFAULT_VALUE_CASE_SENSITIVE = false;
private static final String DEFAULT_VALUE_OPERAND = XmpUtil.EQUALS;
/**
* Returns the name of the protocol that this plugin checks on the target
* system for support.
*
* @return The protocol name for this plugin.
*/
public String getProtocolName() {
return PROTOCOL_NAME;
}
/**
* {@inheritDoc}
*
* Returns true if the protocol defined by this plugin is supported. If the
* protocol is not supported then a false value is returned to the caller.
*/
public boolean isProtocolSupported(InetAddress address) {
throw new UnsupportedOperationException("Undirected XMP checking not supported");
}
/**
* {@inheritDoc}
*
* Returns true if the protocol defined by this plugin is supported. If the
* protocol is not supported then a false value is returned to the caller.
* The qualifier map passed to the method is used by the plugin to return
* additional information by key-name. These key-value pairs can be added to
* service events if needed.
*/
public boolean isProtocolSupported(InetAddress address, Map<String, Object> qualifiers) {
ThreadCategory log = ThreadCategory.getInstance(getClass());
XmpConfig protoConfig = XmpConfigFactory.getInstance().getXmpConfig();
XmpSession session;
SocketOpts sockopts = new SocketOpts();
// TODO how to apply timeout and retry to XMP operations?
int retry = protoConfig.hasRetry() ? protoConfig.getRetry() : DEFAULT_RETRY;
int timeout = protoConfig.hasTimeout() ? protoConfig.getTimeout() : DEFAULT_TIMEOUT;
int port = DEFAULT_PORT;
String authenUser = DEFAULT_AUTHEN_USER;
String requestType = DEFAULT_REQUEST_TYPE;
String mib = DEFAULT_REQUEST_MIB;
String table = DEFAULT_REQUEST_TABLE;
String object = DEFAULT_REQUEST_OBJECT;
String instance = DEFAULT_REQUEST_INSTANCE;
String instanceMatch = null;
String valueOperator = XmpUtil.EQUALS;
String valueOperand = DEFAULT_VALUE_OPERAND;
int minMatches = DEFAULT_MIN_MATCHES;
int maxMatches = DEFAULT_MAX_MATCHES;
boolean maxMatchesUnbounded = DEFAULT_MAX_MATCHES_UNBOUNDED;
boolean valueCaseSensitive = DEFAULT_VALUE_CASE_SENSITIVE;
if (qualifiers != null) {
retry = ParameterMap.getKeyedInteger(qualifiers, "retry", protoConfig.hasRetry() ? protoConfig.getRetry() : DEFAULT_RETRY);
timeout = ParameterMap.getKeyedInteger(qualifiers, "timeout", protoConfig.hasTimeout() ? protoConfig.getTimeout() : DEFAULT_TIMEOUT);
port = ParameterMap.getKeyedInteger(qualifiers, "port", DEFAULT_PORT);
authenUser = ParameterMap.getKeyedString(qualifiers, "authenUser", DEFAULT_AUTHEN_USER);
requestType = ParameterMap.getKeyedString(qualifiers, "request-type", DEFAULT_REQUEST_TYPE);
mib = ParameterMap.getKeyedString(qualifiers, "mib", DEFAULT_REQUEST_MIB);
table = ParameterMap.getKeyedString(qualifiers, "table", DEFAULT_REQUEST_TABLE);
object = ParameterMap.getKeyedString(qualifiers, "object", DEFAULT_REQUEST_OBJECT);
instance = ParameterMap.getKeyedString(qualifiers, "instance", DEFAULT_REQUEST_INSTANCE);
instanceMatch = ParameterMap.getKeyedString(qualifiers, "instance-match", DEFAULT_INSTANCE_MATCH);
valueOperator = ParameterMap.getKeyedString(qualifiers, "value-operator", "==");
valueOperand = ParameterMap.getKeyedString(qualifiers, "value-match", DEFAULT_VALUE_MATCH);
valueCaseSensitive = ParameterMap.getKeyedBoolean(qualifiers, "value-case-sensitive", DEFAULT_VALUE_CASE_SENSITIVE);
minMatches = ParameterMap.getKeyedInteger(qualifiers, "min-matches", DEFAULT_MIN_MATCHES);
maxMatches = ParameterMap.getKeyedInteger(qualifiers, "max-matches", DEFAULT_MAX_MATCHES);
String maxMatchesUnboundedStr = ParameterMap.getKeyedString(qualifiers, "max-matches", "unbounded");
maxMatchesUnbounded = (maxMatchesUnboundedStr.equalsIgnoreCase("unbounded"));
}
// Set the SO_TIMEOUT so that this thing has a prayer of working over a WAN
sockopts.setConnectTimeout(timeout);
// If this is a SelectTableRequest, then you can't use the defaults
// for Table and Object.
if (requestType.equalsIgnoreCase("SelectTableRequest")) {
if (table.equals(DEFAULT_REQUEST_TABLE)) {
throw new IllegalArgumentException("When performing a SelectTableRequest, table must be specified");
}
if (object.equals(DEFAULT_REQUEST_OBJECT)) {
throw new IllegalArgumentException("When performing a SelectTableRequest, object must be specified and must be tabular");
}
}
// If this is a GetRequest, then you can't specify a table or
// an instance
else if (requestType.equalsIgnoreCase("GetRequest")) {
if (! table.equals(DEFAULT_REQUEST_TABLE)) {
throw new IllegalArgumentException("When performing a GetRequest, table must not be specified");
}
if (! instance.equals(DEFAULT_REQUEST_INSTANCE)) {
throw new IllegalArgumentException("When performing a GetRequest, instance must not be specified");
}
} else {
throw new IllegalArgumentException("Unknown request type " + requestType + ", only GetRequest and SelectTableRequest are supported");
}
RE instanceRegex = null;
try {
if (instanceMatch == null) {
instanceRegex = null;
} else if (instanceMatch != null) {
instanceRegex = new RE(instanceMatch);
}
} catch (RESyntaxException e) {
throw new java.lang.reflect.UndeclaredThrowableException(e);
}
boolean result = false;
session = new XmpSession(sockopts, address, port, authenUser);
/*
if (session == null) {
log.info("XMP connection failed to " + address + ":" + port + " with user " + authenUser + " and " + sockopts);
return false;
}
*/
if (requestType.equalsIgnoreCase("SelectTableRequest")) {
try {
result = XmpUtil.handleTableQuery(session, mib, table, object, instance, instanceRegex, valueOperator, valueOperand, minMatches, maxMatches, maxMatchesUnbounded, log, valueCaseSensitive);
} catch (XmpUtilException e) {
result = false;
}
} else if (requestType.equalsIgnoreCase("GetRequest")) {
try {
result = XmpUtil.handleScalarQuery(session, mib, object, valueOperator, valueOperand, log, valueCaseSensitive);
} catch (XmpUtilException e) {
result = false;
}
}
return result;
}
}