/*
* Copyright 2008-2014 by Emeric Vernat
*
* This file is part of Java Melody.
*
* 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.
*/
package net.bull.javamelody;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
/**
* Informations sur Tomcat, sans code html de présentation.
* L'état d'une instance est initialisé à son instanciation et non mutable;
* il est donc de fait thread-safe.
* Cet état est celui d'un serveur Tomcat, similaire à celui fourni dans le manager de Tomcat.
* Les instances sont sérialisables pour pouvoir être transmises au serveur de collecte.
* @author Emeric Vernat
*/
final class TomcatInformations implements Serializable {
// cette classe utilise la même technique avec les MBeans Tomcat que la webapp manager de Tomcat
// http://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/catalina/manager/StatusManagerServlet.java
// http://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java
// http://svn.apache.org/repos/asf/tomcat/trunk/webapps/manager/xform.xsl
private static final boolean TOMCAT_USED = System.getProperty("catalina.home") != null;
private static final long serialVersionUID = -6145865427461051370L;
@SuppressWarnings("all")
private static final List<ObjectName> THREAD_POOLS = new ArrayList<ObjectName>();
@SuppressWarnings("all")
private static final List<ObjectName> GLOBAL_REQUEST_PROCESSORS = new ArrayList<ObjectName>();
private static int mbeansInitAttemps;
private final String name;
private final int maxThreads;
private final int currentThreadCount;
private final int currentThreadsBusy;
private final long bytesReceived;
private final long bytesSent;
private final int requestCount;
private final int errorCount;
private final long processingTime;
private final long maxTime;
private TomcatInformations(MBeans mBeans, ObjectName threadPool) throws JMException {
super();
name = threadPool.getKeyProperty("name");
maxThreads = (Integer) mBeans.getAttribute(threadPool, "maxThreads");
currentThreadCount = (Integer) mBeans.getAttribute(threadPool, "currentThreadCount");
currentThreadsBusy = (Integer) mBeans.getAttribute(threadPool, "currentThreadsBusy");
ObjectName grp = null;
for (final ObjectName globalRequestProcessor : GLOBAL_REQUEST_PROCESSORS) {
if (name.equals(globalRequestProcessor.getKeyProperty("name"))) {
grp = globalRequestProcessor;
break;
}
}
if (grp != null) {
bytesReceived = (Long) mBeans.getAttribute(grp, "bytesReceived");
bytesSent = (Long) mBeans.getAttribute(grp, "bytesSent");
requestCount = (Integer) mBeans.getAttribute(grp, "requestCount");
errorCount = (Integer) mBeans.getAttribute(grp, "errorCount");
processingTime = (Long) mBeans.getAttribute(grp, "processingTime");
maxTime = (Long) mBeans.getAttribute(grp, "maxTime");
} else {
bytesReceived = 0;
bytesSent = 0;
requestCount = 0;
errorCount = 0;
processingTime = 0;
maxTime = 0;
}
}
static List<TomcatInformations> buildTomcatInformationsList() {
if (!TOMCAT_USED) {
return Collections.emptyList();
}
try {
synchronized (THREAD_POOLS) {
if ((THREAD_POOLS.isEmpty() || GLOBAL_REQUEST_PROCESSORS.isEmpty())
&& mbeansInitAttemps < 10) {
// lors du premier appel dans Tomcat lors du déploiement de la webapp,
// ce initMBeans ne fonctionne pas car les MBeans n'existent pas encore,
// donc il faut réessayer plus tard
initMBeans();
// issue 406, Tomcat mbeans never found in jboss eap 6.2,
// we must stop initMBeans at some point
mbeansInitAttemps++;
}
}
final MBeans mBeans = new MBeans();
final List<TomcatInformations> tomcatInformationsList = new ArrayList<TomcatInformations>(
THREAD_POOLS.size());
// rq: le processor correspondant au threadPool peut se retrouver selon
// threadPool.getKeyProperty("name").equals(globalRequestProcessor.getKeyProperty("name"))
for (final ObjectName threadPool : THREAD_POOLS) {
tomcatInformationsList.add(new TomcatInformations(mBeans, threadPool));
}
return tomcatInformationsList;
} catch (final InstanceNotFoundException e) {
// nécessaire pour JBoss 6.0 quand appelé depuis MonitoringFilter.destroy via
// writeHtmlToLastShutdownFile
return Collections.emptyList();
} catch (final AttributeNotFoundException e) {
// issue 220 and end of issue 133:
// AttributeNotFoundException: No attribute called maxThreads (in some JBossAS or JBossWeb)
return Collections.emptyList();
} catch (final JMException e) {
// n'est pas censé arriver
throw new IllegalStateException(e);
}
}
// visibilité package pour réinitialisation en test unitaire
static void initMBeans() throws MalformedObjectNameException {
// rq: en général, il y a 2 connecteurs (http et ajp 1.3) définis dans server.xml et donc
// 2 threadPools et 2 globalRequestProcessors de même nom : http-8080 et jk-8009 (ajp13)
final MBeans mBeans = new MBeans();
THREAD_POOLS.clear();
GLOBAL_REQUEST_PROCESSORS.clear();
THREAD_POOLS.addAll(mBeans.getTomcatThreadPools());
GLOBAL_REQUEST_PROCESSORS.addAll(mBeans.getTomcatGlobalRequestProcessors());
}
String getName() {
return name;
}
int getMaxThreads() {
return maxThreads;
}
int getCurrentThreadCount() {
return currentThreadCount;
}
int getCurrentThreadsBusy() {
return currentThreadsBusy;
}
long getBytesReceived() {
return bytesReceived;
}
long getBytesSent() {
return bytesSent;
}
int getRequestCount() {
return requestCount;
}
int getErrorCount() {
return errorCount;
}
long getProcessingTime() {
return processingTime;
}
long getMaxTime() {
return maxTime;
}
/** {@inheritDoc} */
@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + getName() + ", maxThreads="
+ getMaxThreads() + ", currentThreadCount=" + getCurrentThreadCount()
+ ", currentThreadsBusy=" + getCurrentThreadsBusy() + ", bytesReceived="
+ getBytesReceived() + ", bytesSent=" + getBytesSent() + ", requestCount="
+ getRequestCount() + ", errorCount=" + getErrorCount() + ", processingTime="
+ getProcessingTime() + ", maxTime=" + getMaxTime() + ']';
}
}