/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.hq.plugin.jboss;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Config parsing intended only for JBoss server auto discovery.
*/
public class JBossConfig {
private static final Log log =
LogFactory.getLog(JBossConfig.class.getName());
private static final String NAMING_MBEAN =
"jboss:service=Naming";
private static final String BINDING_MBEAN =
"jboss.system:service=ServiceBindingManager";
private static final String WEBSERVER_MBEAN =
"jboss.web:service=WebServer";
private static HashMap cache = null;
private File serviceXML;
private File bindingXML;
private String jnpPort;
private String jnpPortBinding;
private String jnpAddress;
private String jnpAddressBinding;
private String httpPort;
private String serverBinding;
private long lastModified;
private long lastModifiedBinding;
private JBossConfig(File serviceXML) {
this.serviceXML = serviceXML;
this.lastModified = this.serviceXML.lastModified();
}
public static synchronized JBossConfig getConfig(File configXML) {
if (cache == null) {
cache = new HashMap();
}
JBossConfig cfg =
(JBossConfig)cache.get(configXML);
if ((cfg == null) || cfg.hasChanged()) {
if (cfg == null) {
log.debug("Parsing unseen: " + configXML);
}
else {
log.debug("Parsing modified: " + configXML);
}
cfg = new JBossConfig(configXML);
cache.put(configXML, cfg);
Document doc = null;
try {
doc = cfg.parse(cfg.serviceXML);
cfg.findJnpPort(doc);
} catch (IOException e) {
log.error("Error parsing " + cfg.serviceXML, e);
} finally {
doc = null;
}
}
else {
log.debug("Unchanged: " + configXML);
}
return cfg;
}
private boolean hasChanged() {
long lastModified = this.serviceXML.lastModified();
if (lastModified != this.lastModified) {
this.lastModified = lastModified;
return true;
}
if (this.bindingXML != null) {
lastModified = this.bindingXML.lastModified();
if (lastModified != this.lastModifiedBinding) {
return true;
}
}
return false;
}
public String getHttpPort() {
return this.httpPort;
}
public String getJnpPort() {
String port =
(this.jnpPortBinding == null) ?
this.jnpPort : this.jnpPortBinding;
if (port == null) {
return "1099";
}
else {
return port;
}
}
public String getJnpAddress() {
String addr =
(this.jnpAddressBinding == null) ?
this.jnpAddress : this.jnpAddressBinding;
if ((addr == null) ||
addr.equals("${jboss.bind.address}"))
{
return "127.0.0.1";
}
else {
return addr;
}
}
private String getAttribute(Node node, String name) {
NamedNodeMap attrs = node.getAttributes();
if (attrs == null) {
return null;
}
Node item = attrs.getNamedItem(name);
if (item == null) {
return null;
}
return item.getNodeValue();
}
private String getText(Node node) {
return node.getFirstChild().getNodeValue().trim();
}
private static boolean hasValue(String val) {
return (val != null) && (val.length() != 0);
}
public File getJBossHome() {
File home = this.serviceXML.getParentFile();
while (home != null) {
boolean isServer = home.getName().equals("server");
home = home.getParentFile();
if (isServer) {
break;
}
}
return home;
}
private boolean findJnpPortBinding(Document doc) {
boolean foundPort = false;
NodeList servers =
doc.getDocumentElement().getElementsByTagName("server");
for (int i=0; i<servers.getLength(); i++) {
Node server = servers.item(i);
if (!server.hasAttributes()) {
continue;
}
String name = getAttribute(server, "name");
if (!name.equals(this.serverBinding)) {
continue;
}
NodeList configs = server.getChildNodes();
for (int j=0; j<configs.getLength(); j++) {
Node config = configs.item(j);
if (!config.hasAttributes()) {
continue;
}
if (!"service-config".equals(config.getNodeName())) {
continue;
}
name = getAttribute(config, "name");
boolean isNaming=false, isWebserver=false;
if (!((isNaming = name.equals(NAMING_MBEAN)) ||
(isWebserver = name.equals(WEBSERVER_MBEAN))))
{
continue;
}
NodeList bindings = config.getChildNodes();
for (int k=0; k<bindings.getLength(); k++) {
Node binding = bindings.item(k);
if (!"binding".equals(binding.getNodeName())) {
continue;
}
if (binding.hasAttributes()) {
String val = getAttribute(binding, "port");
log.debug(this.serverBinding + " " +
name + "=" + val);
if (hasValue(val)) {
if (isNaming) {
this.jnpPortBinding = val;
foundPort = true;
}
else if (isWebserver) {
this.httpPort = val;
}
}
val = getAttribute(binding, "host");
if (hasValue(val)) {
if (isNaming) {
this.jnpAddressBinding = val;
}
}
}
break;
}
}
}
return foundPort;
}
private boolean findJnpPortBinding(Node mbean)
throws IOException {
NodeList attrs = mbean.getChildNodes();
for (int i=0; i<attrs.getLength(); i++) {
Node attr = attrs.item(i);
if (!attr.hasAttributes()) {
continue;
}
String attrName = getAttribute(attr, "name");
if ("ServerName".equals(attrName)) {
this.serverBinding = getText(attr);
log.debug("ServerName=" + this.serverBinding);
}
else if ("StoreURL".equals(attrName)) {
String url = getText(attr);
File home = getJBossHome();
if (home != null) {
log.debug("jboss.home.url=" + home);
url = StringUtil.replace(url,
"${jboss.home.url}",
home.toString());
}
url = StringUtil.replace(url,
"${jboss.server.config.url}",
this.serviceXML.getParentFile().toString());
File bindings = new File(url);
boolean exists = bindings.exists();
log.debug("StoreURL exists=" + exists + " (" + url + ")");
if (exists) {
this.bindingXML = bindings;
this.lastModifiedBinding =
bindings.lastModified();
Document bindingDoc;
try {
bindingDoc = parse(bindings);
return findJnpPortBinding(bindingDoc);
} finally {
bindingDoc = null;
}
}
}
}
return false;
}
private boolean findJnpPort(Node mbean) {
NodeList attrs = mbean.getChildNodes();
boolean foundPort = false;
for (int i=0; i<attrs.getLength(); i++) {
Node attr = attrs.item(i);
if (!attr.hasAttributes()) {
continue;
}
String attrName = getAttribute(attr, "name");
if ("Port".equals(attrName)) {
String val = getText(attr);
if (hasValue(val)) {
this.jnpPort = val;
foundPort = true;
}
}
else if ("BindAddress".equals(attrName)) {
String val = getText(attr);
if (hasValue(val)) {
this.jnpAddress = val;
}
}
}
return foundPort;
}
private void findJnpPort(Document doc)
throws IOException {
NodeList mbeans =
doc.getDocumentElement().getElementsByTagName("mbean");
for (int i=0; i<mbeans.getLength(); i++) {
Node mbean = mbeans.item(i);
if (!mbean.hasAttributes()) {
continue;
}
String name = getAttribute(mbean, "name");
if (NAMING_MBEAN.equals(name)) {
findJnpPort(mbean);
log.debug(NAMING_MBEAN + " port=" + this.jnpPort +
", host=" + this.jnpAddress);
}
else if (BINDING_MBEAN.equals(name)) {
findJnpPortBinding(mbean);
log.debug(BINDING_MBEAN + " port=" + this.jnpPortBinding +
", host=" + this.jnpAddressBinding);
}
}
log.debug("JNP port=" + getJnpPort());
}
private Document parse(File file)
throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
return parser.parse(new InputSource(fis));
} catch (ParserConfigurationException e) {
throw new IllegalArgumentException(e.getMessage());
} catch (SAXException e) {
throw new IllegalArgumentException(e.getMessage());
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {}
}
}
}
public static void main(String args[]) throws Exception {
if (args.length != 1) {
System.out.println("Usage: <config file>");
System.exit(1);
}
JBossConfig cfg = JBossConfig.getConfig(new File(args[0]));
System.out.println("JNP url: jnp://" +
cfg.getJnpAddress() + ":" +
cfg.getJnpPort());
if (cfg.getHttpPort() != null) {
System.out.println("HTTP port: " + cfg.getHttpPort());
}
}
}