package org.glassfish.gmbal.impl ;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.management.Attribute ;
import javax.management.AttributeList ;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException ;
import javax.management.InvalidAttributeValueException ;
import javax.management.AttributeNotFoundException ;
import javax.management.MBeanRegistrationException;
import javax.management.NotCompliantMBeanException;
import javax.management.ReflectionException ;
import javax.management.MBeanInfo ;
import javax.management.NotificationBroadcasterSupport ;
import javax.management.MBeanNotificationInfo ;
import javax.management.AttributeChangeNotification ;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.security.AccessController ;
import java.security.PrivilegedExceptionAction ;
import java.security.PrivilegedActionException ;
import java.util.Map ;
import java.util.HashMap ;
import java.util.HashSet;
import java.util.Set;
import org.glassfish.external.amx.AMX;
import org.glassfish.gmbal.GmbalMBean;
import org.glassfish.pfl.basic.facet.FacetAccessor;
import org.glassfish.pfl.basic.facet.FacetAccessorImpl;
import org.glassfish.pfl.basic.logex.OperationTracer;
public class MBeanImpl extends NotificationBroadcasterSupport
implements FacetAccessor, GmbalMBean {
private boolean registered ;
private final MBeanSkeleton skel ;
private final String type ;
private String name ;
private ObjectName oname ;
private MBeanImpl parent ;
private final Set<String> subTypes ;
private Map<String,Map<String,MBeanImpl>> children ;
private Object target ;
private MBeanServer server ;
private String parentPathForObjectName;
private boolean suspended;
public MBeanImpl( final MBeanSkeleton skel,
final Object obj, final MBeanServer server,
final String type ) {
this.registered = false ;
this.skel = skel ;
this.type = type ;
this.name = "" ;
this.oname = null ;
this.parent = null ;
this.children = new HashMap<String,Map<String,MBeanImpl>>() ;
this.target = obj ;
String[] stypes = skel.getMBeanType().subTypes() ;
if (stypes.length > 0) {
this.subTypes = new HashSet( Arrays.asList(stypes)) ;
} else {
this.subTypes = null ;
}
addFacet( obj ) ;
addFacet( new AMXImpl( this ) ) ;
this.server = server ;
this.parentPathForObjectName = null ;
this.suspended = false ;
}
@Override
public synchronized boolean equals( Object obj ) {
if (this == obj) {
return true ;
}
if (!(obj instanceof MBeanImpl)) {
return false ;
}
MBeanImpl other = (MBeanImpl)obj ;
return parent == other.parent() &&
name.equals( other.name() ) &&
type.equals( other.type() ) ;
}
@Override
public synchronized int hashCode() {
if (parent == null) {
return name.hashCode() ^ type.hashCode() ;
} else {
return name.hashCode() ^ type.hashCode() ^ parent.hashCode() ;
}
}
@Override
public String toString() {
return "MBeanImpl[type=" + type + ",name=" + name
+ ",oname=" + oname + "]" ;
}
public MBeanSkeleton skeleton() {
return skel ;
}
public String type() {
return type ;
}
public Object target() {
return target ;
}
public synchronized String name() {
return name ;
}
public synchronized void name( String str ) {
name = str ;
}
public synchronized ObjectName objectName() {
return oname ;
}
public synchronized void objectName( ObjectName oname ) {
this.oname = oname ;
}
public synchronized MBeanImpl parent() {
return parent ;
}
public synchronized void parent( MBeanImpl entity ) {
if (parent == null) {
parent = entity ;
} else {
throw Exceptions.self.nodeAlreadyHasParent(entity) ;
}
}
public synchronized Map<String,Map<String,MBeanImpl>> children() {
Map<String,Map<String,MBeanImpl>> result = new
HashMap<String,Map<String,MBeanImpl>>() ;
for (Map.Entry<String,Map<String,MBeanImpl>> entry
: children.entrySet()) {
result.put( entry.getKey(),
Collections.unmodifiableMap(
new HashMap<String,MBeanImpl>( entry.getValue() ) ) ) ;
}
return Collections.unmodifiableMap( result ) ;
}
public synchronized void addChild( MBeanImpl child ) {
child.parent( this ) ;
if (subTypes != null && !subTypes.contains(child.type())) {
throw Exceptions.self.invalidSubtypeOfParent( this.oname,
this.subTypes, child.objectName(), child.type() ) ;
}
Map<String,MBeanImpl> map = children.get( child.type() ) ;
if (map == null) {
map = new HashMap<String,MBeanImpl>() ;
children.put( child.type(), map ) ;
}
boolean isSingleton = child.skeleton().getMBeanType().isSingleton() ;
if (isSingleton && map.size() > 0) {
throw Exceptions.self.childMustBeSingleton( this.oname,
child.type(), child.objectName() ) ;
}
map.put( child.name(), child) ;
}
public synchronized void removeChild( MBeanImpl child ) {
Map<String,MBeanImpl> map = children.get( child.type() ) ;
if (map != null) {
map.remove( child.name() ) ;
if (map.isEmpty()) {
children.remove( child.type() ) ;
}
}
}
private void restNameHelper( StringBuilder sb ) {
if (parent() != null) {
parent().restNameHelper( sb ) ;
sb.append( '/' ) ;
}
sb.append( type() ) ;
if (!name.equals("")) {
sb.append( '[' ) ;
sb.append( name ) ;
sb.append( ']' ) ;
}
}
private synchronized String restName() {
StringBuilder sb = new StringBuilder( 60 ) ;
restNameHelper( sb ) ;
return sb.toString() ;
}
public synchronized String getParentPathPart( String rootParentPrefix ) {
if (parentPathForObjectName == null) {
StringBuilder result = new StringBuilder() ;
result.append( AMX.PARENT_PATH_KEY ) ;
result.append( "=" ) ;
String qname ;
if (rootParentPrefix == null) {
qname = "/" + restName() ;
} else {
qname = rootParentPrefix + "/" + restName() ;
}
result.append( MBeanTree.getQuotedName( qname ) ) ;
result.append( ',' ) ;
parentPathForObjectName = result.toString() ;
}
return parentPathForObjectName ;
}
public synchronized boolean suspended() {
return suspended ;
}
public synchronized void suspended( boolean flag ) {
suspended = flag ;
}
public synchronized void register() throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (!registered) {
if (skeleton().mom().jmxRegistrationDebug()) {
Exceptions.self.registeringMBean( oname ) ;
}
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
server.registerMBean( MBeanImpl.this, oname ) ;
return null ;
}
} ) ;
} catch (PrivilegedActionException exc) {
final Throwable e = exc.getCause() ;
if (e instanceof InstanceAlreadyExistsException) {
throw (InstanceAlreadyExistsException)e ;
} else if (e instanceof MBeanRegistrationException) {
throw (MBeanRegistrationException)e ;
} else if (e instanceof NotCompliantMBeanException) {
throw (NotCompliantMBeanException)e ;
} else {
Exceptions.self.unexpectedException(
"MBeanServer.registerMBean", e ) ;
}
}
registered = true ;
} else {
Exceptions.self.registerMBeanRegistered( oname ) ;
}
}
public synchronized void unregister() throws InstanceNotFoundException,
MBeanRegistrationException {
if (registered) {
if (skeleton().mom().jmxRegistrationDebug()) {
Exceptions.self.unregisteringMBean( oname ) ;
}
registered = false ;
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
server.unregisterMBean( oname );
return null ;
}
} ) ;
} catch (PrivilegedActionException exc) {
final Throwable e = exc.getCause() ;
if (e instanceof InstanceNotFoundException) {
throw (InstanceNotFoundException)e ;
} else if (e instanceof MBeanRegistrationException) {
throw (MBeanRegistrationException)e ;
} else {
Exceptions.self.unexpectedException(
"MBeanServer.unregisterMBean", e ) ;
}
}
} else {
Exceptions.self.unregisterMBeanNotRegistered( oname ) ;
}
}
public Object getAttribute(String attribute)
throws AttributeNotFoundException, MBeanException, ReflectionException {
OperationTracer.clear() ;
return skel.getAttribute( this, attribute ) ;
}
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException {
OperationTracer.clear() ;
skel.setAttribute( this, this, attribute ) ;
}
public AttributeList getAttributes(String[] attributes) {
OperationTracer.clear() ;
return skel.getAttributes( this, attributes ) ;
}
public AttributeList setAttributes(AttributeList attributes) {
OperationTracer.clear() ;
return skel.setAttributes( this, this, attributes ) ;
}
public Object invoke(String actionName, Object params[], String signature[])
throws MBeanException, ReflectionException {
OperationTracer.clear() ;
return skel.invoke( this, actionName, params, signature ) ;
}
private static final MBeanNotificationInfo[]
ATTRIBUTE_CHANGE_NOTIFICATION_INFO = { new MBeanNotificationInfo(
new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE },
AttributeChangeNotification.class.getName(),
"An Attribute of this MBean has changed" )
} ;
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
return ATTRIBUTE_CHANGE_NOTIFICATION_INFO.clone() ;
}
public MBeanInfo getMBeanInfo() {
return skel.getMBeanInfo();
}
private FacetAccessor facetAccessorDelegate =
new FacetAccessorImpl( this ) ;
public <T> T facet(Class<T> cls ) {
return facetAccessorDelegate.facet( cls ) ;
}
public <T> void addFacet(T obj) {
facetAccessorDelegate.addFacet( obj ) ;
}
public void removeFacet( Class<?> cls ) {
facetAccessorDelegate.removeFacet( cls ) ;
}
public Object invoke(Method method, Object... args) {
return facetAccessorDelegate.invoke( method, args ) ;
}
public Collection<Object> facets() {
return facetAccessorDelegate.facets() ;
}
public Object get(Field field ) {
return facetAccessorDelegate.get( field ) ;
}
public void set(Field field, Object value ) {
facetAccessorDelegate.set( field, value ) ;
}
}