package org.jolokia.detector;
/*
* Copyright 2009-2013 Roland Huss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.management.*;
import org.jolokia.backend.executor.MBeanServerExecutor;
import org.jolokia.config.Configuration;
import org.jolokia.request.JmxRequest;
import org.jolokia.util.LogHandler;
import org.json.simple.JSONObject;
/**
* Detector for Glassfish servers
*
* @author roland
* @since 04.12.10
*/
public class GlassfishDetector extends AbstractServerDetector {
private static final Pattern GLASSFISH_VERSION = Pattern.compile("^.*Glassfish.*\\sv?(.*?)$",Pattern.CASE_INSENSITIVE);
private static final Pattern GLASSFISH_FULL_VERSION = Pattern.compile("^.*Glassfish.*?\\sv?([.\\d]+).*$",Pattern.CASE_INSENSITIVE);
private static final Pattern PAYARA_VERSION = Pattern.compile("^.*Payara.*\\sv?(.*?)$",Pattern.CASE_INSENSITIVE);
private static final Pattern PAYARA_FULL_VERSION = Pattern.compile("^.*Payara.*?\\sv?([.\\d]+).*$",Pattern.CASE_INSENSITIVE);
private static final String GLASSFISH_NAME = "glassfish";
private static final String GLASSFISH_VENDOR_NAME = "Oracle";
private static final String PAYARA_NAME = "Payara Server";
private static final String PAYARA_VENDOR_NAME = "Payara Foundation";
private String serverName;
private String vendorName;
/** {@inheritDoc}
* @param pMBeanServerExecutor*/
public ServerHandle detect(MBeanServerExecutor pMBeanServerExecutor) {
String version = detectVersion(pMBeanServerExecutor);
if (version!= null) {
return new GlassfishServerHandle(version, new HashMap<String, String>());
} else {
return null;
}
}
private String detectVersion(MBeanServerExecutor pMBeanServerExecutor) {
String fullVersion = getSingleStringAttribute(pMBeanServerExecutor,"com.sun.appserv:j2eeType=J2EEServer,*","serverVersion");
String version = extractVersionFromFullVersion(fullVersion);
if (fullVersion == null || "3".equals(version)) {
String versionFromAmx = getSingleStringAttribute(pMBeanServerExecutor,"amx:type=domain-root,*","ApplicationServerFullVersion");
version =
getVersionFromFullVersion(
version,versionFromAmx != null ?
versionFromAmx :
System.getProperty("glassfish.version")
);
} else if (mBeanExists(pMBeanServerExecutor,"com.sun.appserver:type=Host,*")) {
// Last desperate try to get hold of Glassfish MBean
version = "3";
}
return version;
}
// Tries to match Glassfish first, then Payara Server, updating server and vendor name
private String extractVersionFromFullVersion(String pFullVersion) {
if (pFullVersion != null) {
Matcher matcher = GLASSFISH_VERSION.matcher(pFullVersion);
if (matcher.matches()) {
serverName = GLASSFISH_NAME;
vendorName = GLASSFISH_VENDOR_NAME;
return matcher.group(1);
}
matcher = PAYARA_VERSION.matcher(pFullVersion);
if (matcher.matches()) {
serverName = PAYARA_NAME;
vendorName = PAYARA_VENDOR_NAME;
return matcher.group(1);
}
}
return null;
}
private boolean isAmxBooted(MBeanServerExecutor pServerManager) {
return mBeanExists(pServerManager,"amx:type=domain-root,*");
}
// Return true if AMX could be booted, false otherwise
private synchronized boolean bootAmx(MBeanServerExecutor pServers, final LogHandler pLoghandler) {
ObjectName bootMBean = null;
try {
bootMBean = new ObjectName("amx-support:type=boot-amx");
} catch (MalformedObjectNameException e) {
// Cannot happen ....
}
try {
pServers.call(bootMBean, new MBeanServerExecutor.MBeanAction<Void>() {
/** {@inheritDoc} */
public Void execute(MBeanServerConnection pConn, ObjectName pName, Object ... extraArgs)
throws ReflectionException, InstanceNotFoundException, IOException, MBeanException {
pConn.invoke(pName, "bootAMX", null, null);
return null;
}
});
return true;
} catch (InstanceNotFoundException e) {
pLoghandler.error("No bootAmx MBean found: " + e,e);
// Can happen, when a call to bootAmx comes to early before the bean
// is registered
return false;
} catch (IllegalArgumentException e) {
pLoghandler.error("Exception while booting AMX: " + e,e);
// We dont try it again
return true;
} catch (Exception e) {
pLoghandler.error("Exception while executing bootAmx: " + e, e);
// dito
return true;
}
}
private String getVersionFromFullVersion(String pOriginalVersion,String pFullVersion) {
if (pFullVersion == null) {
return pOriginalVersion;
}
Matcher v3Matcher = GLASSFISH_FULL_VERSION.matcher(pFullVersion);
Matcher payaraMatcher = PAYARA_FULL_VERSION.matcher(pFullVersion);
if (v3Matcher.matches()) {
serverName = GLASSFISH_NAME;
vendorName = GLASSFISH_VENDOR_NAME;
return v3Matcher.group(1);
} else if (payaraMatcher.matches()) {
serverName = PAYARA_NAME;
vendorName = PAYARA_VENDOR_NAME;
return payaraMatcher.group(1);
} else {
return pOriginalVersion;
}
}
private class GlassfishServerHandle extends ServerHandle {
private boolean amxShouldBeBooted = false;
private LogHandler logHandler;
/**
* Server handle for a glassfish server
*
* @param version Glassfish version
* @param extraInfo extra infos
*/
public GlassfishServerHandle(String version, Map<String, String> extraInfo) {
super(vendorName, serverName, version, extraInfo);
}
@Override
/** {@inheritDoc} */
public Map<String, String> getExtraInfo(MBeanServerExecutor pServerManager) {
Map<String,String> extra = super.getExtraInfo(pServerManager);
if (pServerManager != null && extra != null && getVersion().startsWith("3")) {
extra.put("amxBooted",Boolean.toString(isAmxBooted(pServerManager)));
}
return extra;
}
@Override
/** {@inheritDoc} */
public void preDispatch(MBeanServerExecutor pMBeanServerExecutor, JmxRequest pJmxReq) {
if (amxShouldBeBooted) {
// Clear flag only of bootAMX succeed or fails with an unrecoverable error
amxShouldBeBooted = !bootAmx(pMBeanServerExecutor,logHandler);
}
}
@Override
/** {@inheritDoc} */
public void postDetect(MBeanServerExecutor pServerManager,
Configuration pConfig, LogHandler pLoghandler) {
JSONObject opts = getDetectorOptions(pConfig,pLoghandler);
amxShouldBeBooted = (opts == null || opts.get("bootAmx") == null || (Boolean) opts.get("bootAmx"))
&& !isAmxBooted(pServerManager);
logHandler = pLoghandler;
}
}
}