001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jmx.export.metadata;
018:
019: import java.beans.PropertyDescriptor;
020: import java.lang.reflect.Method;
021: import java.util.Collection;
022: import java.util.Iterator;
023:
024: import org.springframework.beans.BeanUtils;
025: import org.springframework.beans.factory.InitializingBean;
026: import org.springframework.metadata.Attributes;
027: import org.springframework.util.Assert;
028:
029: /**
030: * Implementation of the <code>JmxAttributeSource</code> interface that
031: * reads metadata via Spring's <code>Attributes</code> abstraction.
032: *
033: * <p>Typically used for reading in source-level attributes via
034: * Commons Attributes.
035: *
036: * @author Rob Harrop
037: * @since 1.2
038: * @see org.springframework.metadata.Attributes
039: * @see org.springframework.metadata.commons.CommonsAttributes
040: */
041: public class AttributesJmxAttributeSource implements
042: JmxAttributeSource, InitializingBean {
043:
044: /**
045: * Underlying Attributes implementation that we're using.
046: */
047: private Attributes attributes;
048:
049: /**
050: * Create a new AttributesJmxAttributeSource.
051: * @see #setAttributes
052: */
053: public AttributesJmxAttributeSource() {
054: }
055:
056: /**
057: * Create a new AttributesJmxAttributeSource.
058: * @param attributes the Attributes implementation to use
059: * @see org.springframework.metadata.commons.CommonsAttributes
060: */
061: public AttributesJmxAttributeSource(Attributes attributes) {
062: if (attributes == null) {
063: throw new IllegalArgumentException("Attributes is required");
064: }
065: this .attributes = attributes;
066: }
067:
068: /**
069: * Set the Attributes implementation to use.
070: * @see org.springframework.metadata.commons.CommonsAttributes
071: */
072: public void setAttributes(Attributes attributes) {
073: this .attributes = attributes;
074: }
075:
076: public void afterPropertiesSet() {
077: if (this .attributes == null) {
078: throw new IllegalArgumentException(
079: "'attributes' is required");
080: }
081: }
082:
083: /**
084: * If the specified class has a <code>ManagedResource</code> attribute,
085: * then it is returned. Otherwise returns null.
086: * @param clazz the class to read the attribute data from
087: * @return the attribute, or <code>null</code> if not found
088: * @throws InvalidMetadataException if more than one attribute exists
089: */
090: public ManagedResource getManagedResource(Class clazz) {
091: Assert.notNull(this .attributes, "'attributes' is required");
092: Collection attrs = this .attributes.getAttributes(clazz,
093: ManagedResource.class);
094: if (attrs.isEmpty()) {
095: return null;
096: } else if (attrs.size() == 1) {
097: return (ManagedResource) attrs.iterator().next();
098: } else {
099: throw new InvalidMetadataException(
100: "A Class can have only one ManagedResource attribute");
101: }
102: }
103:
104: /**
105: * If the specified method has a <code>ManagedAttribute</code> attribute,
106: * then it is returned. Otherwise returns null.
107: * @param method the method to read the attribute data from
108: * @return the attribute, or <code>null</code> if not found
109: * @throws InvalidMetadataException if more than one attribute exists,
110: * or if the supplied method does not represent a JavaBean property
111: */
112: public ManagedAttribute getManagedAttribute(Method method)
113: throws InvalidMetadataException {
114: Assert.notNull(this .attributes, "'attributes' is required");
115: PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
116: if (pd == null) {
117: throw new InvalidMetadataException(
118: "The ManagedAttribute attribute is only valid for JavaBean properties: "
119: + "use ManagedOperation for methods");
120: }
121: Collection attrs = this .attributes.getAttributes(method,
122: ManagedAttribute.class);
123: if (attrs.isEmpty()) {
124: return null;
125: } else if (attrs.size() == 1) {
126: return (ManagedAttribute) attrs.iterator().next();
127: } else {
128: throw new InvalidMetadataException(
129: "A Method can have only one ManagedAttribute attribute");
130: }
131: }
132:
133: /**
134: * If the specified method has a <code>ManagedOperation</code> attribute,
135: * then it is returned. Otherwise return null.
136: * @param method the method to read the attribute data from
137: * @return the attribute, or <code>null</code> if not found
138: * @throws InvalidMetadataException if more than one attribute exists,
139: * or if the supplied method represents a JavaBean property
140: */
141: public ManagedOperation getManagedOperation(Method method) {
142: Assert.notNull(this .attributes, "'attributes' is required");
143: PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
144: if (pd != null) {
145: throw new InvalidMetadataException(
146: "The ManagedOperation attribute is not valid for JavaBean properties: "
147: + "use ManagedAttribute instead");
148: }
149: Collection attrs = this .attributes.getAttributes(method,
150: ManagedOperation.class);
151: if (attrs.isEmpty()) {
152: return null;
153: } else if (attrs.size() == 1) {
154: return (ManagedOperation) attrs.iterator().next();
155: } else {
156: throw new InvalidMetadataException(
157: "A Method can have only one ManagedAttribute attribute");
158: }
159: }
160:
161: /**
162: * If the specified method has <code>ManagedOperationParameter</code> attributes,
163: * then these are returned, otherwise a zero length array is returned.
164: * @param method the method to get the managed operation parameters for
165: * @return the array of ManagedOperationParameter objects
166: * @throws InvalidMetadataException if the number of ManagedOperationParameter
167: * attributes does not match the number of parameters in the method
168: */
169: public ManagedOperationParameter[] getManagedOperationParameters(
170: Method method) throws InvalidMetadataException {
171:
172: Assert.notNull(this .attributes, "'attributes' is required");
173: Collection attrs = this .attributes.getAttributes(method,
174: ManagedOperationParameter.class);
175: if (attrs.size() == 0) {
176: return new ManagedOperationParameter[0];
177: } else if (attrs.size() != method.getParameterTypes().length) {
178: throw new InvalidMetadataException(
179: "Method ["
180: + method
181: + "] has an incorrect number of ManagedOperationParameters specified");
182: } else {
183: ManagedOperationParameter[] params = new ManagedOperationParameter[attrs
184: .size()];
185: for (Iterator it = attrs.iterator(); it.hasNext();) {
186: ManagedOperationParameter param = (ManagedOperationParameter) it
187: .next();
188: if (param.getIndex() < 0
189: || param.getIndex() >= params.length) {
190: throw new InvalidMetadataException(
191: "ManagedOperationParameter index for ["
192: + param.getName()
193: + "] is out of bounds");
194: }
195: params[param.getIndex()] = param;
196: }
197: return params;
198: }
199: }
200:
201: /**
202: * If the specified has {@link ManagedNotification} attributes these are returned, otherwise
203: * a zero-length array is returned.
204: */
205: public ManagedNotification[] getManagedNotifications(Class clazz) {
206: Assert.notNull(this .attributes, "'attributes' is required");
207: Collection attrs = this .attributes.getAttributes(clazz,
208: ManagedNotification.class);
209: return attrs.isEmpty() ? new ManagedNotification[0]
210: : (ManagedNotification[]) attrs
211: .toArray(new ManagedNotification[attrs.size()]);
212: }
213: }
|