/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
package org.opensolaris.opengrok.management.client;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
* Class to handle the connection and methods to the OpenGrok Agent
* @author Jan S Berg
*/
public class AgentConnection implements NotificationListener {
private MBeanServerConnection server = null;
private final ObjectName objName;
private static final String objStrName = "OGA:name=AgentIndexRunner,source=timer";
private static final Logger logger = Logger.getLogger(AgentConnection.class.getName());
private String agenturl = "";
private JMXConnector jmxconn = null;
private boolean connected = false;
private ActionListener actionListener = null;
private boolean listenerRegistered = false;
private static final long RECONNECT_SLEEPTIME = 5000;
public static final String JAVA_LANG_STRING = "java.lang.String";
public static final String JAVA_LANG_OBJECT = "java.lang.Object";
private StringBuilder filesInfo = new StringBuilder();
/** MAX size of the filesInfo buffer */
private static final int FILESINFOMAX = 50000;
private long starttime = 0;
private long endtime = 0;
/**
* Constructor for AgentConnection to OpenGrok JMX Agent
* @param url The JMX url for the agent to connect to
* @throws java.net.MalformedURLException if url is not in correct format
* @throws java.io.IOException if a connection error occurs
* @throws javax.management.MalformedObjectNameException if the JMX object name is not correct
*/
public AgentConnection(String url) throws MalformedURLException, IOException, MalformedObjectNameException {
agenturl = url;
objName = new ObjectName(objStrName);
}
public MBeanServerConnection getMBeanServerConnection() {
if (!isConnected()) {
try {
reconnect(1);
} catch (IOException ex) {
logger.log(Level.SEVERE, ex.getMessage());
logger.log(Level.FINE, "getMBeanServerConnection", ex);
}
}
return server;
}
public String getAgentURL() {
return agenturl;
}
public void setActionListener(ActionListener listener) {
actionListener = listener;
}
public String getFilesInfo() {
return filesInfo.toString();
}
public void clearFilesInfo() {
filesInfo = new StringBuilder();
}
public long getStartTime() {
return starttime;
}
public long getEndTime() {
return endtime;
}
void setUrl(String property) {
agenturl = property;
}
public void handleNotification(Notification notification, java.lang.Object handback) {
StringBuilder sb = new StringBuilder();
sb.append("Notification type: '");
sb.append(notification.getType());
sb.append("', seq nr: '");
sb.append(notification.getSequenceNumber());
sb.append("', message: '");
sb.append(notification.getMessage());
sb.append("', user data: '");
sb.append(notification.getUserData());
sb.append("'");
String notif = "Notification: '" + notification + "'";
String source = "Notification: source: '" + notification.getSource() + "'";
if (notification.getType().equals("ogaaction")) {
if (handback instanceof String) {
logger.fine(sb.toString());
logger.finest(notif);
logger.finest(source);
} else if (handback instanceof ObjectName) {
handleObjectName(sb, notification, handback);
}
} else if (notification.getType().equals("ogainfostring")) {
if (handback instanceof String) {
logger.finest(sb.toString());
logger.finest(notif);
logger.finest(source);
} else if (handback instanceof ObjectName) {
ObjectName pingBean = (ObjectName) handback;
logger.finest("Received notification from '" + pingBean + "' " + sb.toString());
}
} else if (notification.getType().equals("ogainfolong")) {
if (handback instanceof String) {
logger.finest(sb.toString());
logger.finest(notif);
logger.finest(source);
} else if (handback instanceof ObjectName) {
ObjectName pingBean = (ObjectName) handback;
logger.info("Received notification from '" + pingBean + "' " + sb.toString());
if ("StartIndexing".equals(notification.getMessage())) {
starttime = ((Long) notification.getUserData()).longValue();
} else if ("FinishedIndexing".equals(notification.getMessage())) {
endtime = ((Long) notification.getUserData()).longValue();
} else {
logger.warning("Unknown message " + notification.getMessage());
}
}
} else {
logger.info(sb.toString());
logger.finest(notif);
logger.finest(source);
}
}
private void handleObjectName(StringBuilder sb, Notification notification, Object handback) {
ObjectName pingBean = (ObjectName) handback;
logger.fine("Received notification from '" + pingBean + "' " + sb.toString());
if (filesInfo.length() < FILESINFOMAX) {
//filesInfo.append(notification.getMessage());
filesInfo.append(notification.getUserData().toString());
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "OpenGrok fileevent"));
}
}
}
public void registerListener() throws IOException,
InstanceNotFoundException {
logger.fine("Registering listener " + this.getClass().getName() + " for ObjectName " + objName);
server.addNotificationListener(objName, this, null, objName);
logger.fine("Listener Registered");
listenerRegistered = true;
}
public void reconnect(int retrytimes) throws MalformedURLException, IOException {
logger.fine("Doing reconnect on " + agenturl);
boolean notconnected = true;
int triednumtimes = 0;
while (notconnected) {
triednumtimes++;
if (jmxconn != null) {
try {
jmxconn.close();
} catch (Exception ex) {
logger.warning("Exception during close " + ex.getMessage());
}
}
try {
connect();
notconnected = false;
} catch (MalformedURLException ex) {
logger.log(Level.SEVERE, null, ex);
throw ex;
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
notconnected = true;
if (triednumtimes <= retrytimes) {
logger.info("retry connect did try " + triednumtimes + ", retrying " +
retrytimes + " times, waiting " + RECONNECT_SLEEPTIME + " before" +
" next try.");
try {
Thread.sleep(RECONNECT_SLEEPTIME);
} catch (Exception sleepex) {
logger.finest("reconnect: " + sleepex.getMessage());
}
} else {
throw ex;
}
}
}
}
protected void connect() throws MalformedURLException, IOException {
JMXServiceURL url = new JMXServiceURL(agenturl);
logger.info("jmx url " + url);
HashMap<String, Object> env = new HashMap<String, Object>();
jmxconn = JMXConnectorFactory.connect(url, env);
logger.finer("jmx connect ok");
server = jmxconn.getMBeanServerConnection();
logger.info("JMX connection ok");
connected = true;
}
public boolean isConnected() {
return connected;
}
public void unregister() {
if ((server != null) && (objName != null) && listenerRegistered) {
try {
logger.fine("Unregistering listener " + this.getClass().getName() + " for ObjectName " + objName);
server.removeNotificationListener(objName, this, null, objName);
listenerRegistered = false;
} catch (Exception remnlex) {
logger.warning("Exception unregister notif listener " + this.getClass().getName() + " for ObjectName " + objName);
}
}
try {
if (jmxconn != null) {
logger.fine("Closing connection");
jmxconn.close();
jmxconn = null;
server = null;
}
} catch (Exception e) {
logger.log(Level.WARNING, "disconnect: " + e.getMessage());
logger.log(Level.FINE, "unregister", e);
}
}
}