/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.server.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import com.caucho.cloud.network.NetworkListenSystem;
import com.caucho.env.meter.MeterService;
import com.caucho.env.meter.TotalMeter;
import com.caucho.env.service.ResinSystem;
import com.caucho.management.server.AbstractEmitterObject;
import com.caucho.management.server.CacheItem;
import com.caucho.management.server.ClusterMXBean;
import com.caucho.management.server.ClusterServerMXBean;
import com.caucho.management.server.EnvironmentMXBean;
import com.caucho.management.server.PortMXBean;
import com.caucho.management.server.ServerMXBean;
import com.caucho.management.server.TcpConnectionMXBean;
import com.caucho.management.server.ThreadPoolMXBean;
import com.caucho.network.listen.TcpSocketLinkListener;
import com.caucho.network.listen.TcpSocketLink;
import com.caucho.server.dispatch.Invocation;
import com.caucho.server.dispatch.InvocationServer;
import com.caucho.server.util.CauchoSystem;
import com.caucho.util.Alarm;
public class ServerAdmin extends AbstractEmitterObject
implements ServerMXBean
{
private static final String BYTES_PROBE = "Resin|Http|Request Bytes";
private TotalMeter _httpBytesProbe;
private Server _server;
ServerAdmin(Server server)
{
_server = server;
MeterService.createAverageMeter(BYTES_PROBE, "");
String name = BYTES_PROBE;
_httpBytesProbe = (TotalMeter) MeterService.getMeter(name);
registerSelf();
}
@Override
public String getName()
{
return null;
}
@Override
public String getType()
{
return "Server";
}
@Override
public String getId()
{
return _server.getServerId();
}
@Override
public int getServerIndex()
{
return _server.getServerIndex();
}
//
// Hierarchy
//
/**
* Returns the cluster server owning this server
*/
@Override
public ClusterServerMXBean getSelfServer()
{
return _server.getSelfServer().getAdmin();
}
/**
* Returns the cluster owning this server
*/
@Override
public ClusterMXBean getCluster()
{
return _server.getCluster().getAdmin();
}
@Override
public EnvironmentMXBean getEnvironment()
{
// XXX: possible GC/classloader issues
return _server.getEnvironmentAdmin();
}
/**
* Returns the array of ports.
*/
@Override
public PortMXBean []getPorts()
{
Collection<TcpSocketLinkListener> portList = getNetworkListeners();
PortMXBean []ports = new PortMXBean[portList.size()];
int i = 0;
for (TcpSocketLinkListener port : portList) {
ports[i++] = port.getAdmin();
}
return ports;
}
/**
* Returns the server's thread pool administration
*/
@Override
public ThreadPoolMXBean getThreadPool()
{
return _server.getResin().getThreadPoolAdmin();
}
/**
* Returns the cluster port
*/
@Override
public PortMXBean getClusterPort()
{
return null;
}
//
// Configuration attributes
//
@Override
public boolean isBindPortsAfterStart()
{
ResinSystem resinSystem = _server.getResinSystem();
NetworkListenSystem listenService
= resinSystem.getService(NetworkListenSystem.class);
return listenService.isBindPortsAfterStart();
}
/**
* Returns true if detailed statistics are being kept.
*/
@Override
public boolean isDetailedStatistics()
{
return false;
}
@Override
public boolean isDevelopmentModeErrorPage()
{
return _server.isDevelopmentModeErrorPage();
}
@Override
public long getMemoryFreeMin()
{
return 0;
}
@Override
public long getPermGenFreeMin()
{
return 0;
}
@Override
public String getServerHeader()
{
return _server.getServerHeader();
}
@Override
public boolean isSelectManagerEnabled()
{
return false;
}
@Override
public long getShutdownWaitMax()
{
return _server.getShutdownWaitMax();
}
@Override
public String getStage()
{
return _server.getStage();
}
@Override
public int getUrlLengthMax()
{
return _server.getUrlLengthMax();
}
//
// state
//
/**
* The current lifecycle state.
*/
@Override
public String getState()
{
return _server.getState();
}
/**
* Returns the current time according to the server.
*/
@Override
public Date getCurrentTime()
{
return new Date(Alarm.getExactTime());
}
/**
* Returns the last start time.
*/
@Override
public Date getStartTime()
{
return new Date(_server.getStartTime());
}
/**
* Returns the time since the last start time.
*/
@Override
public long getUptime()
{
return Alarm.getExactTime() - _server.getStartTime();
}
//
// statistics
//
/**
* Returns the current number of threads that are servicing requests.
*/
@Override
public int getThreadActiveCount()
{
int activeThreadCount = -1;
for (TcpSocketLinkListener port : getNetworkListeners()) {
if (port.getActiveThreadCount() >= 0) {
if (activeThreadCount == -1)
activeThreadCount = 0;
activeThreadCount += port.getActiveThreadCount();
}
}
return activeThreadCount;
}
/**
* Returns the current number of connections that are in the keepalive
* state and are using a thread to maintain the connection.
*/
@Override
public int getThreadKeepaliveCount()
{
int keepaliveThreadCount = -1;
for (TcpSocketLinkListener port : getNetworkListeners()) {
if (port.getKeepaliveConnectionCount() >= 0) {
if (keepaliveThreadCount == -1)
keepaliveThreadCount = 0;
keepaliveThreadCount += port.getKeepaliveConnectionCount();
}
}
return keepaliveThreadCount;
}
/**
* Returns the current number of connections that are in the keepalive
* state and are using select to maintain the connection.
*/
@Override
public int getSelectKeepaliveCount()
{
return 0;
}
/**
* Returns the total number of requests serviced by the server
* since it started.
*/
@Override
public long getRequestCountTotal()
{
long lifetimeRequestCount = 0;
for (TcpSocketLinkListener port : getNetworkListeners())
lifetimeRequestCount += port.getLifetimeRequestCount();
return lifetimeRequestCount;
}
/**
* Returns the number of requests that have ended up in the keepalive state
* for this server in its lifetime.
*/
@Override
public long getKeepaliveCountTotal()
{
return -1;
}
/**
* The total number of connections that have terminated with
* {@link com.caucho.vfs.ClientDisconnectException}.
*/
@Override
public long getClientDisconnectCountTotal()
{
long lifetimeClientDisconnectCount = 0;
for (TcpSocketLinkListener port : getNetworkListeners())
lifetimeClientDisconnectCount += port.getLifetimeClientDisconnectCount();
return lifetimeClientDisconnectCount;
}
/**
* Returns the total duration in milliseconds that requests serviced by
* this server have taken.
*/
@Override
public long getRequestTimeTotal()
{
return -1;
}
/**
* Returns the total number of bytes that requests serviced by this
* server have read.
*/
@Override
public long getRequestReadBytesTotal()
{
return -1;
}
/**
* Returns the total number of bytes that requests serviced by this
* server have written.
*/
@Override
public long getRequestWriteBytesTotal()
{
if (_httpBytesProbe != null)
return (long) _httpBytesProbe.getTotal();
else
return 0;
}
/**
* Returns the invocation cache hit count.
*/
@Override
public long getInvocationCacheHitCountTotal()
{
return _server.getInvocationServer().getInvocationCacheHitCount();
}
/**
* Returns the invocation cache miss count.
*/
@Override
public long getInvocationCacheMissCountTotal()
{
return _server.getInvocationServer().getInvocationCacheMissCount();
}
/**
* Returns the current total amount of memory available for the JVM, in bytes.
*/
@Override
public long getRuntimeMemory()
{
if (Alarm.isTest())
return 666;
else
return Runtime.getRuntime().totalMemory();
}
/**
* Returns the current free amount of memory available for the JVM, in bytes.
*/
@Override
public long getRuntimeMemoryFree()
{
if (Alarm.isTest())
return 666;
else
return Runtime.getRuntime().freeMemory();
}
/**
* Returns the CPU load average.
*/
@Override
public double getCpuLoadAvg()
{
try {
if (Alarm.isTest())
return 0;
else
return CauchoSystem.getLoadAvg();
} catch (Exception e) {
return 0;
}
}
/**
* Returns the cache stuff.
*/
public ArrayList<CacheItem> getCacheStatistics()
{
InvocationServer server = _server.getInvocationServer();
ArrayList<Invocation> invocationList = server.getInvocations();
if (invocationList == null)
return null;
HashMap<String,CacheItem> itemMap = new HashMap<String,CacheItem>();
for (int i = 0; i < invocationList.size(); i++) {
Invocation inv = (Invocation) invocationList.get(i);
String uri = inv.getURI();
int p = uri.indexOf('?');
if (p >= 0)
uri = uri.substring(0, p);
CacheItem item = itemMap.get(uri);
if (item == null) {
item = new CacheItem();
item.setUrl(uri);
itemMap.put(uri, item);
}
}
return null;
}
//
// Operations
//
/**
* Restart this Resin server.
*/
@Override
public void restart()
{
_server.destroy();
}
/**
* Finds the ConnectionMXBean for a given thread id
*/
@Override
public TcpConnectionMXBean findConnectionByThreadId(long threadId)
{
TcpSocketLink conn = getListenService().findConnectionByThreadId(threadId);
if (conn != null)
return conn.getAdmin();
else
return null;
}
private Collection<TcpSocketLinkListener> getNetworkListeners()
{
NetworkListenSystem listenService
= _server.getResinSystem().getService(NetworkListenSystem.class);
return listenService.getListeners();
}
private NetworkListenSystem getListenService()
{
return _server.getResinSystem().getService(NetworkListenSystem.class);
}
}