/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.management.j2ee;
import java.util.Set;
import java.util.Map;
import javax.management.ObjectName;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.MBeanServer;
import javax.management.MBeanInfo;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MBeanException;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.ReflectionException;
import javax.management.MBeanServerInvocationHandler;
import com.sun.appserv.management.base.Util;
import com.sun.appserv.management.util.misc.GSetUtil;
import com.sun.appserv.management.util.jmx.JMXUtil;
import com.sun.appserv.management.util.misc.ExceptionUtil;
import com.sun.appserv.management.client.ProxyFactory;
import com.sun.appserv.management.j2ee.J2EEServer;
import com.sun.appserv.management.j2ee.J2EETypes;
import com.sun.appserv.management.j2ee.StateManageable;
import static com.sun.appserv.management.j2ee.StateManageable.*;
import com.sun.appserv.management.j2ee.J2EEServer;
import com.sun.enterprise.management.support.Delegate;
import com.sun.enterprise.management.support.DummyDelegate;
import com.sun.enterprise.management.support.LoaderMBean;
import com.sun.enterprise.management.support.QueryMgrImpl;
import com.sun.enterprise.management.support.DelegateToMBeanDelegate;
import com.sun.enterprise.management.support.oldconfig.OldConfigProxies;
import com.sun.enterprise.management.support.oldconfig.OldServersMBean;
import com.sun.enterprise.admin.mbeans.DomainStatusMBean;
import com.sun.enterprise.admin.mbeans.DomainStatus;
import com.sun.enterprise.admin.mbeans.DomainStatusHelper;
import com.sun.enterprise.ManagementObjectManager;
import com.sun.appserv.management.j2ee.J2EETypes;
import com.sun.enterprise.admin.servermgmt.RuntimeStatus;
import com.sun.enterprise.admin.common.Status;
/**
Server MBean which will reside on DAS for enabling state management including start() and stop().
*/
public class DASJ2EEServerImpl
extends J2EEServerImpl
implements NotificationListener
{
public
DASJ2EEServerImpl( )
{
super( J2EETypes.J2EE_SERVER, DummyDelegate.INSTANCE );
}
static private final Class[] DOMAIN_STATUS_INTERFACES =
new Class[] { DomainStatusMBean.class };
protected DomainStatusMBean
getDomainStatus()
{
DomainStatusMBean domainStatus = null;
try {
final MBeanServer mbeanServer = getMBeanServer();
final Set<ObjectName> candidates = QueryMgrImpl.queryPatternObjectNameSet(
mbeanServer, JMXUtil.newObjectNamePattern(
"*", DomainStatusMBean.DOMAIN_STATUS_PROPS ) );
final ObjectName on = GSetUtil.getSingleton( candidates );
domainStatus = (DomainStatusMBean)MBeanServerInvocationHandler.
newProxyInstance( mbeanServer, on, DomainStatusMBean.class, false );
} catch (Exception e) {
final Throwable rootCause = ExceptionUtil.getRootCause( e );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
}
return( domainStatus );
}
private boolean
remoteServerIsRunning()
{
return (STATE_RUNNING == getstate());
}
private boolean
remoteServerIsStartable()
{
final int cState = getstate();
return (STATE_STOPPED == cState) ||
(STATE_FAILED == cState);
}
private boolean
remoteServerIsStoppable()
{
int cState = getstate();
if ((STATE_STARTING == cState) ||
(STATE_RUNNING == cState) ||
(STATE_FAILED == cState))
{
return true;
}
else
{
return false;
}
}
public void
handleNotification( final Notification notif , final Object ignore)
{
final String notifType = notif.getType();
if ( notifType.equals( DomainStatusMBean.SERVER_STATUS_NOTIFICATION_TYPE ) )
{
final String serverName = (String)
Util.getAMXNotificationValue( notif, DomainStatusMBean.SERVER_NAME_KEY );
//System.out.println( "########## DASJ2EEServerImpl.handleNotification: serverName = " + serverName + ", state = " + getstate() + ": " + com.sun.appserv.management.util.jmx.stringifier.NotificationStringifier.toString(notif) );
if ( serverName.equals( getServerName() ) )
{
setDelegate();
}
}
}
private synchronized void
setDelegate()
{
if ( remoteServerIsRunning() )
{
//System.out.println( "########## DASJ2EEServerImpl.setDelegate(): remoteServerIsRunning=true");
try {
// get the object name for the old jsr77 server mBean
com.sun.enterprise.ManagementObjectManager mgmtObjManager =
com.sun.enterprise.Switch.getSwitch().getManagementObjectManager();
final String strON = mgmtObjManager.getServerBaseON(false, getServerName());
final MBeanServerConnection remoteConn =
getDomainStatus().getServerMBeanServerConnection( getServerName() );
final ObjectName onPattern = new ObjectName(strON + ",*");
final Set<ObjectName> names = JMXUtil.queryNames( remoteConn, onPattern, null);
assert( names.size() == 1 );
final ObjectName serverON = GSetUtil.getSingleton( names );
final Delegate delegate = new DelegateToMBeanDelegate( remoteConn, serverON );
setDelegate( delegate );
setstartTime(System.currentTimeMillis());
//System.out.println( "########## DASJ2EEServerImpl.setDelegate(): set delegate to " + serverON);
}
catch (Exception e) {
final Throwable rootCause = ExceptionUtil.getRootCause( e );
getMBeanLogger().warning(
rootCause.toString() + "\n" + ExceptionUtil.getStackTrace( rootCause ) );
if ( getDelegate() == null )
{
setDelegate( DummyDelegate.INSTANCE );
setstartTime(0);
}
}
}
else
{
//System.out.println( "########## DASJ2EEServerImpl.setDelegate(): setting DummyDelegate" );
setDelegate( DummyDelegate.INSTANCE );
setstartTime(0);
}
}
public void
preRegisterDone()
throws Exception
{
super.preRegisterDone( );
setstartTime( 0 );
setDelegate();
}
protected String
getServerName()
{
return( getSelfName() );
}
public boolean
isstateManageable()
{
return true;
}
final RuntimeStatus
getRuntimeStatus(final String serverName )
{
final MBeanServer mbeanServer = getMBeanServer();
final OldServersMBean oldServers =
OldConfigProxies.getInstance( mbeanServer ).getOldServersMBean( );
final RuntimeStatus status = oldServers.getRuntimeStatus( serverName );
return status;
}
/**
Convert an internal status code to JSR 77 StateManageable state.
*/
private static int
serverStatusCodeToStateManageableState( final int statusCode )
{
int state = STATE_FAILED;
switch( statusCode )
{
default: throw new IllegalArgumentException( "Uknown status code: " + statusCode );
case Status.kInstanceStartingCode: state = STATE_STARTING; break;
case Status.kInstanceRunningCode: state = STATE_RUNNING; break;
case Status.kInstanceStoppingCode: state = STATE_STOPPING; break;
case Status.kInstanceNotRunningCode: state = STATE_STOPPED; break;
}
return state;
}
public int
getstate()
{
int state = STATE_STOPPED;
try
{
final int internalStatus = getRuntimeStatus(getServerName()).getStatus().getStatusCode();
state = serverStatusCodeToStateManageableState( internalStatus );
}
catch ( final Exception e )
{
// not available, must not be running, or (developer mode) method not available
if ( isDASJ2EEServer() )
{
// no way to tell STARTING from RUNNING
state = STATE_RUNNING;
}
}
return state;
}
public void
start()
{
if ( remoteServerIsStartable() )
{
startRemoteServer();
}
else
{
throw new RuntimeException("server is not in a startable state");
}
}
public void
startRecursive()
{
start();
}
/** The DAS is always named "server", or so inquiries suggest */
static final String DAS_SERVER_NAME = "server";
/**
Does this particular J2EEServer represent the DAS?
*/
private boolean
isDASJ2EEServer()
{
return DAS_SERVER_NAME.equals( getName() );
}
public void
stop()
{
if ( isDASJ2EEServer() )
{
getDelegate().invoke( "stop", (Object[])null, (String[])null);
}
else if ( remoteServerIsStoppable() )
{
stopRemoteServer();
}
else
{
throw new RuntimeException("server is not in a stoppable state");
}
}
/*
private MBeanInfo mMBeanInfo = null;
public synchronized MBeanInfo
getMBeanInfo()
{
// compute the MBeanInfo only once!
if ( mMBeanInfo == null )
{
final MBeanInfo superMBeanInfo = super.getMBeanInfo();
mMBeanInfo = new MBeanInfo(
superMBeanInfo.getClassName(),
superMBeanInfo.getDescription(),
mergeAttributeInfos(superMBeanInfo.getAttributes(), getMBeanAttributeInfo()),
superMBeanInfo.getConstructors(),
mergeOperationInfos(superMBeanInfo.getOperations(), getMBeanOperationInfo()),
superMBeanInfo.getNotifications() );
}
return mMBeanInfo;
}
private MBeanAttributeInfo[]
mergeAttributeInfos(
MBeanAttributeInfo[] infos1,
MBeanAttributeInfo[] infos2 )
{
final MBeanAttributeInfo[] infos =
new MBeanAttributeInfo[ infos1.length + infos2.length ];
System.arraycopy( infos1, 0, infos, 0, infos1.length );
System.arraycopy( infos2, 0, infos, infos1.length, infos2.length );
return( infos );
}
private MBeanAttributeInfo[]
getMBeanAttributeInfo()
{
MBeanAttributeInfo[] dAttributes = new MBeanAttributeInfo[1];
dAttributes[0] = new MBeanAttributeInfo("state",
"java.lang.Integer",
"server state",
true,
false,
false);
return dAttributes;
}
*/
/* private MBeanOperationInfo[]
mergeOperationInfos(
MBeanOperationInfo[] infos1,
MBeanOperationInfo[] infos2 )
{
final MBeanOperationInfo[] infos =
new MBeanOperationInfo[ infos1.length + infos2.length ];
System.arraycopy( infos1, 0, infos, 0, infos1.length );
System.arraycopy( infos2, 0, infos, infos1.length, infos2.length );
return( infos );
}
*/
/*
private MBeanOperationInfo[]
getMBeanOperationInfo()
{
MBeanOperationInfo[] dOperations = new MBeanOperationInfo[3];
dOperations[0] = new MBeanOperationInfo("start",
"start server instance",
null,
"void",
MBeanOperationInfo.ACTION);
dOperations[1] = new MBeanOperationInfo("stop",
"stop server instance",
null,
"void",
MBeanOperationInfo.ACTION);
dOperations[2] = new MBeanOperationInfo("startRecursive",
"start server instance",
null,
"void",
MBeanOperationInfo.ACTION);
return dOperations;
}
*/
private void
startRemoteServer()
{
try {
// get the object name for servers config mBean
ObjectName on = DomainStatusHelper.getServersConfigObjectName();
// invoke start method on servers config mBean
// get mBean server
final MBeanServer server = getMBeanServer();
// form the parameters
Object[] params = new Object[1];
params[0] = getServerName();
String[] signature = {"java.lang.String"};
// invoke the start method
server.invoke(on, "startServerInstance", params, signature);
} catch (javax.management.MalformedObjectNameException mfone) {
final Throwable rootCause = ExceptionUtil.getRootCause( mfone );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(mfone);
} catch (javax.management.InstanceNotFoundException infe) {
final Throwable rootCause = ExceptionUtil.getRootCause( infe );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(infe);
} catch (javax.management.MBeanException mbe) {
final Throwable rootCause = ExceptionUtil.getRootCause( mbe );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(mbe);
} catch (javax.management.ReflectionException rfe) {
final Throwable rootCause = ExceptionUtil.getRootCause( rfe );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(rfe);
}
}
private void
stopRemoteServer()
{
try {
// get the object name for servers config mBean
ObjectName on = DomainStatusHelper.getServersConfigObjectName();
// invoke stop method on servers config mBean
// get mBean server
final MBeanServer server = getMBeanServer();
// form the parameters
Object[] params = new Object[1];
params[0] = getServerName();
String[] signature = {"java.lang.String"};
// invoke the start method
server.invoke(on, "stopServerInstance", params, signature);
} catch (javax.management.MalformedObjectNameException mfone) {
final Throwable rootCause = ExceptionUtil.getRootCause( mfone );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(mfone);
} catch (javax.management.InstanceNotFoundException infe) {
// in case of PE and DAS
// it is desit]rable that the instance be not stopped
// hence the log level is fine
final Throwable rootCause = ExceptionUtil.getRootCause( infe );
getMBeanLogger().fine( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(infe);
} catch (javax.management.MBeanException mbe) {
final Throwable rootCause = ExceptionUtil.getRootCause( mbe );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(mbe);
} catch (javax.management.ReflectionException rfe) {
final Throwable rootCause = ExceptionUtil.getRootCause( rfe );
getMBeanLogger().warning( rootCause.toString() + "\n" +
ExceptionUtil.getStackTrace( rootCause ) );
throw new RuntimeException(rfe);
}
}
public boolean
getRestartRequired() {
// Notification mechanism is broken (reason unknown). Just set it explicitly if not
// already set.
//System.out.println( "########## DASJ2EEServerImpl.getRestartRequired:" + getServerName() );
if ( getDelegate() == null || getDelegate() == DummyDelegate.INSTANCE )
{
setDelegate();
}
// there might not be a Delegate. Default to 'true', since a non-running server
// must be restarted!
boolean required = true;
final int state = getstate();
// ensure that these states always return 'true'
if ( state == STATE_STOPPED || state == STATE_FAILED || state == STATE_STOPPING )
{
required = true;
}
else
{
try {
final Object result = getDelegate().getAttribute( "restartRequired" );
required = Boolean.valueOf( "" + result );
}
catch( AttributeNotFoundException e ) {
logWarning( ExceptionUtil.toString(e) );
required = true;
}
}
return required;
}
}