org.glassfish.gmbal.impl.MBeanSkeleton 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 org.glassfish.gmbal.AMXMetadata;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicLong;
import java.lang.reflect.Method;
import java.lang.reflect.ReflectPermission;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanException;
import javax.management.InvalidAttributeValueException;
import javax.management.AttributeNotFoundException;
import javax.management.ReflectionException;
import javax.management.MBeanParameterInfo;
import javax.management.NotificationBroadcasterSupport;
import javax.management.AttributeChangeNotification;
import org.glassfish.gmbal.NameValue;
import org.glassfish.gmbal.ManagedOperation;
import org.glassfish.gmbal.ParameterNames;
import javax.management.Descriptor;
import javax.management.JMException;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
import org.glassfish.gmbal.impl.trace.TraceRegistration;
import org.glassfish.gmbal.impl.trace.TraceRegistrationFine;
import org.glassfish.gmbal.impl.trace.TraceRuntime;
import org.glassfish.gmbal.typelib.EvaluatedClassAnalyzer;
import org.glassfish.gmbal.typelib.EvaluatedClassDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedFieldDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedMethodDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedType;
import org.glassfish.pfl.basic.algorithm.DumpIgnore;
import org.glassfish.pfl.basic.algorithm.DumpToString;
import org.glassfish.pfl.basic.contain.Pair;
import org.glassfish.pfl.basic.facet.FacetAccessor;
import org.glassfish.pfl.basic.func.BinaryFunction;
import org.glassfish.pfl.tf.spi.annotation.InfoMethod;
@TraceRegistrationFine
@TraceRegistration
@TraceRuntime
public class MBeanSkeleton {
private static Descriptor DEFAULT_AMX_DESCRIPTOR =
DescriptorIntrospector.descriptorForElement( null,
ManagedObjectManagerImpl.DefaultAMXMetadataHolder.class ) ;
@TraceRuntime
public interface Operation
extends BinaryFunction, Object> {
};
private AMXMetadata mbeanType;
private final String type;
private Descriptor descriptor;
@DumpToString
private final AtomicLong sequenceNumber;
@DumpToString
private final ManagedObjectManagerInternal mom;
@DumpIgnore
private final Map setters;
private final Map getters;
private AttributeDescriptor nameAttributeDescriptor;
private final Map, Operation>> operations;
private final List mbeanAttributeInfoList;
private final List mbeanOperationInfoList;
private final ModelMBeanInfoSupport mbInfo;
private void addToCompoundMap(
Map> source, Map> dest) {
for (Map.Entry> entry : source.entrySet()) {
Map dmap = dest.get(entry.getKey());
if (dmap == null) {
dmap = new HashMap();
dest.put(entry.getKey(), dmap);
}
dmap.putAll(entry.getValue());
}
}
public MBeanSkeleton(final EvaluatedClassDeclaration annotatedClass,
final EvaluatedClassAnalyzer ca,
final ManagedObjectManagerInternal mom) {
boolean isDefaultAMXMetadata = false ;
mbeanType = mom.getFirstAnnotationOnClass(annotatedClass, AMXMetadata.class);
if (mbeanType == null) {
isDefaultAMXMetadata = true ;
mbeanType = mom.getDefaultAMXMetadata() ;
}
type = mom.getTypeName(annotatedClass.cls(), "AMX_TYPE",
mbeanType.type());
Descriptor ldesc = DescriptorIntrospector.descriptorForElement( mom,
annotatedClass.cls() ) ;
if (isDefaultAMXMetadata) {
// We didn't have an @AMXMetadata annotation on annotatedClass,
// so we need to construct a new Descriptor that contains the
// default AMXMetadata values, as well as any other values that
// may be present from other metadata annotations.
ldesc = DescriptorUtility.union( DEFAULT_AMX_DESCRIPTOR, ldesc ) ;
}
// Now fix up the descriptor so that the ModelMBean code won't
// complain.
descriptor = makeValidDescriptor( ldesc, DescriptorType.mbean, type);
sequenceNumber = new AtomicLong();
this.mom = mom;
setters = new HashMap();
getters = new HashMap();
operations = new HashMap, Operation>>();
mbeanAttributeInfoList = new ArrayList();
mbeanOperationInfoList = new ArrayList();
analyzeAttributes(ca);
analyzeOperations(ca);
analyzeObjectNameKeys(ca);
mbInfo = makeMbInfo(mom.getDescription(annotatedClass));
}
// In case of conflicts, always prefer second over first.
private MBeanSkeleton(MBeanSkeleton first, MBeanSkeleton second) {
mbeanType = second.mbeanType;
type = second.type;
descriptor = DescriptorUtility.union(first.descriptor,
second.descriptor);
sequenceNumber = new AtomicLong();
mom = second.mom;
setters = new HashMap();
setters.putAll(first.setters);
setters.putAll(second.setters);
getters = new HashMap();
getters.putAll(first.getters);
getters.putAll(second.getters);
nameAttributeDescriptor = second.nameAttributeDescriptor;
operations = new HashMap, Operation>>();
addToCompoundMap(first.operations, operations);
addToCompoundMap(second.operations, operations);
mbeanAttributeInfoList = new ArrayList();
mbeanAttributeInfoList.addAll(first.mbeanAttributeInfoList);
mbeanAttributeInfoList.addAll(second.mbeanAttributeInfoList);
mbeanOperationInfoList = new ArrayList();
mbeanOperationInfoList.addAll(first.mbeanOperationInfoList);
mbeanOperationInfoList.addAll(second.mbeanOperationInfoList);
// This must go last, because it depends on some of the
// preceding initializations.
mbInfo = makeMbInfo(second.mbInfo.getDescription());
}
private ModelMBeanInfoSupport makeMbInfo(String description) {
ModelMBeanAttributeInfo[] attrInfos = mbeanAttributeInfoList.toArray(
new ModelMBeanAttributeInfo[mbeanAttributeInfoList.size()]);
ModelMBeanOperationInfo[] operInfos = mbeanOperationInfoList.toArray(
new ModelMBeanOperationInfo[mbeanOperationInfoList.size()]);
return new ModelMBeanInfoSupport( type, description, attrInfos, null,
operInfos, null, descriptor);
}
/** Create a new MBeanSkeleton that is the composition of this one
* and skel. Note that, if this and skel contain the same attribute,
* the version from skel will appear in the composition.
*/
public MBeanSkeleton compose(MBeanSkeleton skel) {
return new MBeanSkeleton(this, skel);
}
private enum DescriptorType { mbean, attribute, operation }
// Create a valid descriptor so that ModelMBinfoSupport won't throw
// an exception.
Descriptor makeValidDescriptor(Descriptor desc, DescriptorType dtype,
String dname) {
Map map = new HashMap();
String[] names = desc.getFieldNames();
Object[] values = desc.getFieldValues((String[]) null);
for (int ctr = 0; ctr < names.length; ctr++) {
map.put(names[ctr], values[ctr]);
}
map.put("descriptorType", dtype.toString());
if (dtype == DescriptorType.operation) {
map.put("role", "operation");
map.put("targetType", "ObjectReference");
} else if (dtype == DescriptorType.mbean) {
map.put("persistPolicy", "never");
map.put("log", "F");
map.put("visibility", "1");
}
map.put("name", dname);
map.put("displayName", dname);
return DescriptorUtility.makeDescriptor(map);
}
@Override
public String toString() {
return "DynamicMBeanSkeleton[type" + type + "]";
}
@InfoMethod
private void descriptorContents( String name, String description,
Descriptor desc ) {}
@InfoMethod
private void attributeInfoContents( ModelMBeanAttributeInfo info ) {}
// This method should only be called when getter.id.equals( setter.id )
@TraceRegistrationFine
private void processAttribute(AttributeDescriptor getter,
AttributeDescriptor setter) {
if ((setter == null) && (getter == null)) {
throw Exceptions.self.notBothNull();
}
if ((setter != null) && (getter != null)
&& !setter.type().equals(getter.type())) {
throw Exceptions.self.typesMustMatch();
}
AttributeDescriptor nonNullDescriptor =
(getter != null) ? getter : setter;
String name = nonNullDescriptor.id();
String description = nonNullDescriptor.description();
Descriptor desc = DescriptorUtility.EMPTY_DESCRIPTOR;
if (getter != null) {
desc = DescriptorUtility.union(desc,
DescriptorIntrospector.descriptorForElement( mom,
getter.accessible()));
}
if (setter != null) {
desc = DescriptorUtility.union(desc,
DescriptorIntrospector.descriptorForElement( mom,
setter.accessible()));
}
desc = makeValidDescriptor(desc, DescriptorType.attribute, name);
descriptorContents( name, description, desc ) ;
TypeConverter tc = mom.getTypeConverter(nonNullDescriptor.type());
ModelMBeanAttributeInfo ainfo = new ModelMBeanAttributeInfo(name,
tc.getManagedType().getClassName(), description,
getter != null, setter != null, false, desc);
attributeInfoContents(ainfo);
mbeanAttributeInfoList.add(ainfo);
}
@InfoMethod
private void attributes(
Pair