org.glassfish.gmbal.impl.MBeanImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webservices-rt Show documentation
Show all versions of webservices-rt Show documentation
This module contains the Metro runtime code.
/*
* Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
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 subTypes ; // Null if not used: don't create empty
// sets if not used.
// First index is type, second is name.
private Map> 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>() ;
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 ) ) ;
// Note that the construction of an MBean skeleton and
// facet registration must stay in sync. The code is currently separated into
// two places (here and call to new MBeanSkeleton( skel, skel )).
// This will also be important for dealing with multiple upper bounds.
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> children() {
// Make a copy to avoid problems with concurrent modification.
Map> result = new
HashMap>() ;
for (Map.Entry> entry
: children.entrySet()) {
result.put( entry.getKey(),
Collections.unmodifiableMap(
new HashMap( entry.getValue() ) ) ) ;
}
return Collections.unmodifiableMap( result ) ;
}
public synchronized void addChild( MBeanImpl child ) {
child.parent( this ) ;
// XXX Add test case!
if (subTypes != null && !subTypes.contains(child.type())) {
throw Exceptions.self.invalidSubtypeOfParent( this.oname,
this.subTypes, child.objectName(), child.type() ) ;
}
Map map = children.get( child.type() ) ;
if (map == null) {
map = new HashMap() ;
children.put( child.type(), map ) ;
}
// XXX add test case!
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 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 ) ) ;
// Note that the "/" MUST be passed to getQuotedName, or we
// can get things like /"...", which is wrong.
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