/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.rhq.plugins.mobicents.tools;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.ConnectionFactory;
import org.mc4j.ems.connection.EmsConnectException;
import org.mc4j.ems.connection.EmsConnection;
import org.mc4j.ems.connection.settings.ConnectionSettings;
import org.mc4j.ems.connection.support.ConnectionProvider;
import org.mc4j.ems.connection.support.metadata.ConnectionTypeDescriptor;
import org.mc4j.ems.connection.support.metadata.InternalVMTypeDescriptor;
import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.plugins.jmx.JMXComponent;
/**
* Supports Mobicents Sip Balancer
*
* @author jean.deruelle@gmail.com
*/
public class MobicentsSipBalancerComponent implements JMXComponent {
private static Log log = LogFactory.getLog(MobicentsSipBalancerComponent.class);
private ResourceContext resourceContext;
private EmsConnection connection;
/**
* Controls the dampening of connection error stack traces in an attempt to control spam to the log
* file. Each time a connection error is encountered, this will be incremented. When the connection
* is finally established, this will be reset to zero.
*/
private int consecutiveConnectionErrors;
public void start(ResourceContext context) {
resourceContext = context;
// Attempt to load the connection now. If we cannot, do not consider the start operation as failed. The only
// exception to this rule is if the connection cannot be made due to a JMX security exception. In this case,
// we treat it as an invalid plugin configuration and throw the appropriate exception (see the javadoc for
// ResourceComponent)
try {
getEmsConnection();
} catch (Exception e) {
// Explicit checking for security exception (i.e. invalid credentials for connecting to JMX)
if (e instanceof EmsConnectException) {
Throwable cause = e.getCause();
if (cause instanceof SecurityException) {
throw new InvalidPluginConfigurationException(
"Invalid JMX credentials specified for connecting to this balancer.", e);
}
}
}
}
public void stop() {
if (this.connection != null) {
try {
this.connection.close();
} catch (Exception e) {
log.error("Error closing Mobicents Sip Balancer connection: " + e);
}
this.connection = null;
}
}
public AvailabilityType getAvailability() {
try {
EmsConnection connection = getEmsConnection();
if(connection != null) {
connection.getBean("mobicents:type=LoadBalancer,name=LoadBalancer");
return AvailabilityType.UP;
} else {
return AvailabilityType.DOWN;
}
} catch (Exception e) {
return AvailabilityType.DOWN;
}
}
public EmsConnection getEmsConnection() {
if (this.connection == null) {
try {
Configuration pluginConfig = resourceContext.getPluginConfiguration();
ConnectionSettings connectionSettings = new ConnectionSettings();
connectionSettings.initializeConnectionType((ConnectionTypeDescriptor) Class.forName(
J2SE5ConnectionTypeDescriptor.class.getCanonicalName()).newInstance());
connectionSettings.setServerUrl("service:jmx:rmi:///jndi/rmi://" + pluginConfig.getSimpleValue(MobicentsSipBalancerDiscoveryComponent.HOST_PROP, "localhost") + ":" + pluginConfig.getSimpleValue(MobicentsSipBalancerDiscoveryComponent.RMI_REGISTRY_PORT_PROP, "2000") + "/server");
connectionSettings.setPrincipal(null);
connectionSettings.setCredentials(null);
String balancerExecutableJarFilePath = pluginConfig.getSimpleValue(MobicentsSipBalancerDiscoveryComponent.BALANCER_EXECUTABLE_JAR_FILE_PATH, null);
String balancerExecutableJarFile = pluginConfig.getSimpleValue(MobicentsSipBalancerDiscoveryComponent.BALANCER_EXECUTABLE_JAR_FILE, null);
log.debug("JarBalancer = " + balancerExecutableJarFile);
log.debug("JarBalancerPath = " + balancerExecutableJarFilePath);
// allow JMX to unmarshall SIPNode class in LoadBalancerComponent
List<File> classpathEntries = connectionSettings.getClassPathEntries();
if(classpathEntries == null) {
classpathEntries = new ArrayList<File>();
}
classpathEntries.add(new File(balancerExecutableJarFile));
connectionSettings.setClassPathEntries(classpathEntries);
// connectionSettings.setLibraryURI(pluginConfig.getSimpleValue("balancerJarPath", null));
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.discoverServerClasses(connectionSettings);
if (connectionSettings.getAdvancedProperties() == null) {
connectionSettings.setAdvancedProperties(new Properties());
}
// Tell EMS to make copies of jar files so that the ems classloader doesn't lock
// application files (making us unable to update them) Bug: JBNADM-670
connectionSettings.getControlProperties().setProperty(ConnectionFactory.COPY_JARS_TO_TEMP,
String.valueOf(Boolean.TRUE));
// But tell it to put them in a place that we clean up when shutting down the agent
connectionSettings.getControlProperties().setProperty(ConnectionFactory.JAR_TEMP_DIR,
resourceContext.getTemporaryDirectory().getAbsolutePath());
connectionSettings.getAdvancedProperties().setProperty(InternalVMTypeDescriptor.DEFAULT_DOMAIN_SEARCH,
"mobicents");
log.info("Loading Mobicents Sip Balancer connection [" + connectionSettings.getServerUrl() + "]...");
ConnectionProvider connectionProvider = connectionFactory.getConnectionProvider(connectionSettings);
this.connection = connectionProvider.connect();
this.connection.loadSynchronous(false); // this loads all the MBeans
this.consecutiveConnectionErrors = 0;
if (log.isDebugEnabled())
log.debug("Successfully made connection to the Mobicents Sip Balancer instance for resource ["
+ this.resourceContext.getResourceKey() + "]");
} catch (Exception e) {
// The connection will be established even in the case that the principal cannot be authenticated,
// but the connection will not work. That failure seems to come from the call to loadSynchronous after
// the connection is established. If we get to this point that an exception was thrown, close any
// connection that was made and null it out so we can try to establish it again.
if (connection != null) {
if (log.isDebugEnabled())
log.debug("Connection created but an exception was thrown. Closing the connection.", e);
connection.close();
connection = null;
}
// Since the connection is attempted each time it's used, failure to connect could result in log
// file spamming. Log it once for every 10 consecutive times it's encountered.
if (consecutiveConnectionErrors % 10 == 0) {
log.warn("Could not establish connection to the Mobicents Sip Balancer instance ["
+ (consecutiveConnectionErrors + 1) + "] times for resource ["
+ resourceContext.getResourceKey() + "]", e);
}
if (log.isDebugEnabled())
log.debug("Could not connect to the Mobicents Sip Balancer instance for resource ["
+ resourceContext.getResourceKey() + "]", e);
consecutiveConnectionErrors++;
}
}
return connection;
}
}